Docs / Security / How to Set Up Mutual TLS (mTLS) Between Services

How to Set Up Mutual TLS (mTLS) Between Services

By Admin · Mar 15, 2026 · Updated Apr 25, 2026 · 195 views · 3 min read

Mutual TLS (mTLS) requires both client and server to present certificates during the TLS handshake. This ensures that both parties are authenticated, preventing unauthorized services from communicating with your backend APIs.

How mTLS Differs from Standard TLS

  • Standard TLS: Client verifies server certificate. Server does not verify client.
  • Mutual TLS: Both client and server verify each other's certificates. Both must present valid certificates.

When to Use mTLS

  • Service-to-service communication (microservices)
  • API authentication between trusted services
  • Zero-trust network architectures
  • Database connections over untrusted networks

Step 1: Create a Certificate Authority

# Create a private CA for your infrastructure
# Generate CA private key
openssl genrsa -out ca.key 4096

# Generate CA certificate (valid for 10 years)
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
  -subj "/C=US/ST=New York/O=MyOrg/CN=Internal CA"

Step 2: Generate Server Certificate

# Generate server key and CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
  -subj "/C=US/ST=New York/O=MyOrg/CN=api.internal"

# Sign with CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out server.crt -days 365

Step 3: Generate Client Certificate

# Generate client key and CSR
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
  -subj "/C=US/ST=New York/O=MyOrg/CN=web-service"

# Sign with CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out client.crt -days 365

Step 4: Configure Nginx for mTLS

# /etc/nginx/conf.d/api.conf
server {
    listen 8443 ssl;
    server_name api.internal;

    # Server certificate
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # Require client certificate
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client on;

    # Pass client cert info to backend
    proxy_set_header X-SSL-Client-CN $ssl_client_s_dn_cn;
    proxy_set_header X-SSL-Client-Verify $ssl_client_verify;

    location / {
        proxy_pass http://localhost:3000;
    }
}

Step 5: Test mTLS

# Test with client certificate (should succeed)
curl --cert client.crt --key client.key --cacert ca.crt \
  https://api.internal:8443/health

# Test without client certificate (should fail with 400/403)
curl --cacert ca.crt https://api.internal:8443/health
# Error: 400 No required SSL certificate was sent

Certificate Rotation

# Automate certificate renewal before expiry
# Check expiry date
openssl x509 -in client.crt -noout -enddate

# Generate new certificate with same key
openssl req -new -key client.key -out client-new.csr
openssl x509 -req -in client-new.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out client-new.crt -days 365

# Deploy new certificate and restart services

Was this article helpful?