Configure HTTPS Between Client and APISIX
TLS (Transport Layer Security) is a cryptographic protocol designed to secure communication between two entities. Enforcing HTTPS between clients and APISIX improves the security and authenticity during the data transmission.
This guide will show you how to configure HTTPS between client applications and APISIX.

Prerequisite(s)
- Install Docker.
- Install cURL to send requests to the services for validation.
- Follow the Getting Started tutorial to start a new APISIX instance in Docker.
Create a Route
Create a route that forwards all requests to /ip
to the upstream httpbin.org
:
- Admin API
- ADC
- Ingress Controller
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "quickstart-client-ip",
"uri": "/ip",
"upstream": {
"nodes": {
"httpbin.org:80":1
},
"type": "roundrobin"
}
}'
An HTTP/1.1 200 OK
response verifies that the route is created successfully.
services:
- name: httpbin Service
routes:
- uris:
- /ip
name: quickstart-client-ip
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
Synchronize the configuration to APISIX:
adc sync -f adc-service.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: quickstart-client-ip
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /ip
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: quickstart-client-ip
spec:
ingressClassName: apisix
http:
- name: quickstart-client-ip
match:
paths:
- /ip
upstreams:
- name: httpbin-external-domain
Apply the configuration to your cluster:
kubectl apply -f httpbin-route.yaml
Generate Certificates and Keys
Generate the certificate authority (CA) key and certificate:
openssl genrsa -out ca.key 2048 && \
openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CN=ROOTCA" && \
openssl x509 -req -days 36500 -sha256 -extensions v3_ca -signkey ca.key -in ca.csr -out ca.crt
Generate the key and certificate with the common name test.com
for APISIX, and sign with the CA certificate:
openssl genrsa -out server.key 2048 && \
openssl req -new -sha256 -key server.key -out server.csr -subj "/CN=test.com" && \
openssl x509 -req -days 36500 -sha256 -extensions v3_req \
-CA ca.crt -CAkey ca.key -CAserial ca.srl -CAcreateserial \
-in server.csr -out server.crt
Configure HTTPS for APISIX
You can optionally load the content of server.crt
and server.key
into environment variables:
export server_cert=$(cat server.crt)
export server_key=$(cat server.key)
- Admin API
- ADC
- Ingress Controller
Create an SSL certificate object to save the server certificate and its key:
curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT -d '
{
"id": "quickstart-tls-client-ssl",
"sni": "test.com",
"cert": "'"${server_cert}"'",
"key": "'"${server_key}"'"
}'
❶ sni
: test.com
, the same as server certificate CN value
❷ cert
: server certificate
❸ key
: private key for the server certificate
ssls:
- snis:
- test.com
certificates:
- certificate: ${server_cert}
key: ${server_key}
❶ sni
: test.com
, the same as server certificate CN value
❷ cert
: server certificate
❸ key
: private key for the server certificate
Synchronize the configuration to APISIX:
adc sync -f adc-ssl.yaml -f adc-service.yaml
You should enable SSL for the gateway if you have not already:
helm upgrade apisix apisix/apisix \
--namespace ingress-apisix \
--set apisix.deployment.role=traditional \
--set apisix.deployment.role_traditional.config_provider=yaml \
--set etcd.enabled=false \
--set ingress-controller.enabled=true \
--set ingress-controller.config.provider.type=apisix-standalone \
--set ingress-controller.apisix.adminService.namespace=ingress-apisix \
--set ingress-controller.gatewayProxy.createDefault=true \
--set apisix.ssl.enabled=true
Port forward the SSL port to your host machine:
kubectl port-forward svc/apisix-gateway 9443:443 &
Create a Kubernetes TLS secret manifest file:
kubectl create secret tls test-tls-secret \
--cert=server.crt \
--key=server.key \
--namespace=ingress-apisix \
--dry-run=client -o yaml > secret.yaml
Apply the secret to your cluster:
kubectl apply -f secret.yaml
- Gateway API
- APISIX CRD
Update your Gateway manifest file as such:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: ingress-apisix
name: apisix
spec:
gatewayClassName: apisix
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
hostname: test.com
tls:
certificateRefs:
- kind: Secret
group: ""
name: test-tls-secret
infrastructure:
parametersRef:
group: apisix.apache.org
kind: GatewayProxy
name: apisix-config
Apply the configuration to your cluster:
kubectl apply -f gateway.yaml
Create a Kubernetes manifest file for TLS configuration:
apiVersion: apisix.apache.org/v2
kind: ApisixTls
metadata:
namespace: ingress-apisix
name: test-tls
spec:
ingressClassName: apisix
hosts:
- test.com
secret:
name: test-tls-secret
namespace: ingress-apisix
Apply the configuration to your cluster:
kubectl apply -f tls.yaml
Verify HTTPS between Client and APISIX
As the certificate is only valid for the CN test.com
, you should use test.com
as the domain name where APISIX is hosted.
Send a request to https://test.com:9443/ip
and resolve test.com
to 127.0.0.1
:
curl -ikv --resolve "test.com:9443:127.0.0.1" "https://test.com:9443/ip"
A TLS handshake process similar to the following verifies the TLS between client and APISIX is enabled:
* Added test.com:9443:127.0.0.1 to DNS cache
* Hostname test.com was found in DNS cache
* Trying 127.0.0.1:9443...
* Connected to test.com (127.0.0.1) port 9443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=test.com
* start date: Apr 21 07:47:54 2023 GMT
* expire date: Mar 28 07:47:54 2123 GMT
* issuer: CN=ROOTCA
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x556274d632e0)
> GET /ip HTTP/2
> Host: test.com:9443
> user-agent: curl/7.74.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
HTTP/2 200
...
Next Steps
You can learn more about TLS and APISIX SSL object in SSL Certificates.
APISIX also supports mTLS connection between clients and APISIX. See Configure mTLS between client and APISIX for more details.