Nginx
To configure nginx as a reverse proxy, we need to create a new file (e.g. app) in the directory /etc/nginx/sites-enabled.
Info
Don't forget to replace the placeholders with the actual values:
[DOMAIN]Domain name (e.g. app.example.com)[CLIENT_WEB_PORT]: Port of the client web application.[SERVER_CORE_PORT]: Port of the server core application.
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default off;
}
server {
server_name [DOMAIN];
listen 80;
gzip on;
gzip_types text/plain application/xml text/css application/javascript;
gzip_min_length 1000;
client_max_body_size 0;
chunked_transfer_encoding on;
location / {
expires $expires;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://127.0.0.1:[CLIENT_WEB_PORT];
}
location /api/ {
rewrite ^/api(/.*)$ $1 break;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Clear the client-certificate header so a public request can never
# spoof it. Only a trusted mTLS location (see below) may set it.
proxy_set_header X-Forwarded-Tls-Client-Cert "";
proxy_read_timeout 2m;
proxy_connect_timeout 2m;
proxy_pass http://127.0.0.1:[SERVER_CORE_PORT];
}
}Certificate
The easiest way to set up a certificate is with the help of certbot. On a Linux based system, letsencrypt can be installed with the following command.
Certificate roles
The certificate configured in this section identifies the NGINX HTTPS endpoint to browsers and API clients. It is not an Authup client-certificate trust anchor. See Trust Anchors (Trusted CAs) for the difference and the mTLS topology.
sudo apt install certbot python3-certbot-nginxA certificate can be requested and installed with the following command.
sudo certbot --nginx -d [DOMAIN]TLS client certificates
The recommended topology uses a dedicated hostname that requests a client certificate and routes to the same private Authup listener. Configure Authup:
CERTIFICATE_SOURCE=forwarded
MTLS_PUBLIC_URL=https://mtls.auth.example.comThen add an NGINX server/location for that hostname:
server {
listen 443 ssl;
server_name mtls.auth.example.com;
ssl_certificate /etc/letsencrypt/live/mtls.auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mtls.auth.example.com/privkey.pem;
# Ask for a certificate but leave realm-specific trust decisions to Authup.
# This also permits self-signed certificates used only for token binding.
ssl_verify_client optional_no_ca;
location / {
proxy_pass http://127.0.0.1:[SERVER_CORE_PORT];
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Always derive this value from the current TLS handshake. Never pass
# through a public request's header value.
proxy_set_header X-Forwarded-Tls-Client-Cert $ssl_client_escaped_cert;
}
}If ordinary OAuth clients share the same hostname, optional_no_ca lets them connect without a certificate; Authup rejects only requests whose client or token configuration requires one. A separate mTLS hostname avoids browser certificate prompts on the normal UI origin and is published through mtls_endpoint_aliases when MTLS_PUBLIC_URL is set.
The Authup listener must remain private. Any other proxy location that reaches it must clear the forwarding header:
proxy_set_header X-Forwarded-Tls-Client-Cert "";Native forwarded mode has no intermediate chain
$ssl_client_escaped_cert contains the leaf certificate only. With CERTIFICATE_SOURCE=forwarded, a client using authMethod: tls must have a leaf signed directly by an enabled trust anchor in its realm.
For a root → intermediate → leaf PKI, use an ingress that emits RFC 9440 Client-Cert and Client-Cert-Chain and select CERTIFICATE_SOURCE=standard.
NGINX requests and attests the handshake certificate; Authup validates TLS client-authentication chains against its live realm trust anchors. Do not copy those realm trust anchors into a second authorization CA store in NGINX. See OAuth Client Certificates for client URI-SAN and token-binding requirements.