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 or on Kubernetes.
- Install jq to encode the PEM files as JSON strings.
- If you use the Admin API examples and authentication is enabled, export an admin-role key as
ADMIN_API_KEY. Configure the key underdeployment.admin.admin_key. The Docker quickstart disables authentication for local evaluation; keep it enabled in production.
Create a Route
Create a route that forwards all requests to /ip to the upstream httpbin.org:
- Admin API
- ADC
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-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.
Give this example its own service name. ADC matches a service by name, so reusing httpbin Service updates that existing service even when the label is different. If you previously synchronized this example, delete the older quickstart-client-ip route on httpbin Service after synchronizing, and leave every other route on that service in place.
services:
- name: Downstream HTTPS Service
labels:
docs-example: downstream-https
routes:
- uris:
- /ip
name: quickstart-client-ip
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
ADC reconciles services as desired state. Preview only this example's labeled service and confirm that the diff contains no unintended updates or deletions:
adc diff -f adc-service.yaml \
--include-resource-type service \
--label-selector docs-example=downstream-https
Synchronize the reviewed service configuration:
adc sync -f adc-service.yaml \
--include-resource-type service \
--label-selector docs-example=downstream-https
Generate Certificates and Keys
Generate the certificate authority (CA) key and certificate:
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 36500 -sha256 \
-key ca.key \
-out ca.crt \
-subj "/CN=MyTestCA" \
-extensions v3_ca \
-config <(printf "[req]\ndistinguished_name=req\n[v3_ca]\nbasicConstraints=critical,CA:TRUE\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always,issuer")
Generate the key and certificate signing request (CSR) for APISIX:
openssl genrsa -out server.key 2048
openssl req -new -sha256 \
-key server.key \
-out server.csr \
-subj "/CN=test.com"
Sign the server CSR with the CA certificate. The subject alternative name (SAN) makes the certificate valid for the DNS name test.com:
openssl x509 -req -days 36500 -sha256 \
-in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt \
-extensions v3_req \
-extfile <(printf "[v3_req]\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth\nsubjectAltName=DNS:test.com")
Configure HTTPS for APISIX
The ADC example uses environment variables to insert the PEM contents into its resources file:
export server_cert=$(cat server.crt)
export server_key=$(cat server.key)
- Admin API
- ADC
Create the SSL object with an SNI that matches the certificate's test.com DNS name. jq reads the PEM files and encodes their newlines as valid JSON:
jq -n --rawfile cert server.crt --rawfile key server.key \
'{id: "quickstart-tls-client-ssl", sni: "test.com", cert: $cert, key: $key}' \
| curl -i "http://127.0.0.1:9180/apisix/admin/ssls" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @-
ssls:
- labels:
docs-example: downstream-https
snis:
- test.com
certificates:
- certificate: ${server_cert}
key: ${server_key}
❶ sni: test.com, the same as the server certificate's DNS name
❷ cert: server certificate
❸ key: private key for the server certificate
Preview the SSL and service changes within the same example-owned scope:
adc diff -f adc-ssl.yaml -f adc-service.yaml \
--include-resource-type ssl \
--include-resource-type service \
--label-selector docs-example=downstream-https
Synchronize the reviewed SSL and service configuration:
adc sync -f adc-ssl.yaml -f adc-service.yaml \
--include-resource-type ssl \
--include-resource-type service \
--label-selector docs-example=downstream-https
Verify HTTPS between Client and APISIX
The server certificate is valid for the DNS name test.com. Use that hostname for verification while resolving it to the local APISIX address.
Send a request to the route. --cacert verifies the APISIX certificate chain, and --resolve connects test.com to 127.0.0.1 without disabling hostname verification:
curl -iv --cacert ca.crt \
--noproxy test.com \
--resolve "test.com:9443:127.0.0.1" \
"https://test.com:9443/ip"
The request should succeed with an HTTP 2xx response. Relevant lines from an OpenSSL-backed curl build should resemble the following:
* subjectAltName: host "test.com" matched cert's "test.com"
* SSL certificate verify ok.
< HTTP/2 200
The exact transcript depends on the curl TLS backend and negotiated HTTP version. Verify that the output confirms both the certificate match and successful certificate verification; do not rely only on the HTTP status.
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.