Authentication

TLS encryption without authentication is vulnerable to man-in-the-middle attacks. A secure stunnel deployment must authenticate the TLS server and, when access control requires it, the TLS client.

Stunnel supports three common trust models:

For introductory client and server configurations, begin with the HOWTO.

Choosing an Authentication Model

Requirement Recommended model
Public or broadly distributed service PKI server certificate
Private service with centrally managed identities Private PKI and mutual TLS
Small closed deployment without a CA PSK
Fixed peer whose certificate can be updated out of band Certificate pinning
Hardware-backed private key PKI with an OpenSSL provider or engine

Do not disable authentication to work around certificate errors. Correct the trust store, certificate chain, expected identity, or system clock instead.

PKI Server Authentication

A TLS server presents a certificate chain and proves possession of the corresponding private key:

[server]
accept = 0.0.0.0:8443
connect = 127.0.0.1:8080
cert = /etc/stunnel/server-fullchain.pem
key = /etc/stunnel/private/server.key
sslVersionMin = TLSv1.2

The certificate file starts with the leaf certificate and contains the required intermediate certificates in chain order. The private key may be stored in the same file, in which case key defaults to the value of cert, but separate files are usually easier to protect and rotate.

On Unix, restrict private-key access to the account that loads it:

chmod 600 /etc/stunnel/private/server.key

A service that starts unprivileged needs file ownership or group permissions for its service account. If stunnel starts as root and then applies setuid or setgid, it can load a root-owned key before dropping privileges.

Public services should use a certificate issued by an appropriate CA, normally obtained and renewed with an ACME client. Self-signed certificates are suitable for controlled testing or explicit pinning, not as a reason to disable verification.

Verifying a Server in Client Mode

A client must validate both the certificate chain and the server identity:

[client]
client = yes
accept = 127.0.0.1:8080
connect = server.example.com:8443
verifyChain = yes
CAfile = /etc/ssl/certs/ca-certificates.crt
checkHost = server.example.com
sni = server.example.com
sslVersionMin = TLSv1.2

These options perform different tasks:

SNI does not authenticate a server. A configuration with sni but without verifyChain and checkHost remains vulnerable to impersonation.

The CA bundle path varies by operating system. Common locations include /etc/ssl/certs/ca-certificates.crt, /etc/ssl/cert.pem, and /etc/pki/tls/certs/ca-bundle.crt.

Modern certificates should carry DNS names and IP addresses in the Subject Alternative Name extension. Configure checkHost for the final TLS server, not for the local stunnel listener, HTTP proxy, or unrelated load balancer name.

Trust directories and external stores

CApath points to a directory of hashed CA certificates. Prepare or refresh it with the OpenSSL rehash tool supplied by the operating system, commonly:

openssl rehash /etc/stunnel/ca

With OpenSSL 3.0 or later, CAstore can load trust anchors through an OSSL_STORE URI. URI syntax and system-store availability depend on the installed OpenSSL providers.

Mutual TLS

Mutual TLS authenticates the client with a certificate in addition to authenticating the server.

Server

Configure the CA that issues permitted client certificates:

[mutual-tls-server]
accept = 0.0.0.0:8443
connect = 127.0.0.1:8080
cert = /etc/stunnel/server-fullchain.pem
key = /etc/stunnel/private/server.key
verifyChain = yes
CAfile = /etc/stunnel/client-ca.pem

verifyChain = yes implies requireCert = yes, so clients that do not present a valid certificate are rejected. Use a dedicated client CA where practical rather than trusting every certificate in a broad public root bundle.

Client

The client presents its certificate and key while independently verifying the server:

[mutual-tls-client]
client = yes
accept = 127.0.0.1:8080
connect = server.example.com:8443
cert = /etc/stunnel/client-fullchain.pem
key = /etc/stunnel/private/client.key
verifyChain = yes
CAfile = /etc/stunnel/server-ca.pem
checkHost = server.example.com
sni = server.example.com

Each client should have a distinct private key and certificate. Distinct identities make revocation, auditing, and incident response possible without replacing every client's credentials.

Certificate Pinning

Pinning trusts a locally installed leaf certificate instead of any certificate issued by a CA:

[pinned-client]
client = yes
accept = 127.0.0.1:8080
connect = server.example.com:8443
verifyPeer = yes
CAfile = /etc/stunnel/pinned-servers.pem
checkHost = server.example.com
sni = server.example.com

The file named by CAfile contains the permitted leaf certificate. It may contain both the current and replacement certificates during a planned rotation. checkHost also ensures that the pinned certificate identifies the intended service.

Pinning reduces the set of trusted certificates but creates an operational dependency: clients must receive a new pin before the server switches certificates. Monitor expiration dates and test the rollover procedure.

verifyPeer and verifyChain have different meanings:

The numeric verify option is obsolete and should not be used in new configurations.

Pre-Shared Keys

PSK authenticates both peers without certificates or a certificate authority. It is well suited to a closed set of stunnel clients when secrets can be distributed securely.

Generate an independent random key for each client:

openssl rand -hex 32

Store identities and keys in the server's secrets file:

client1:8f3f26f0d65b8f8c1d690de3f9fdd0e2d1c261573f7557406f068c3f8a355f78
client2:54f47f783aeb9ba534e85ad0c6f50ee343e7be79eecfc338de67a28a66734a33

Hexadecimal keys are converted to binary automatically. Keys must be at least 16 bytes; the example command generates 32-byte keys.

Server

[psk-server]
accept = 0.0.0.0:8443
connect = 127.0.0.1:8080
PSKsecrets = /etc/stunnel/server.psk
sslVersionMin = TLSv1.3

Client

The client file should contain only that client's identity and key:

client1:8f3f26f0d65b8f8c1d690de3f9fdd0e2d1c261573f7557406f068c3f8a355f78

Configure the identity explicitly:

[psk-client]
client = yes
accept = 127.0.0.1:8080
connect = server.example.com:8443
PSKsecrets = /etc/stunnel/client.psk
PSKidentity = client1
sslVersionMin = TLSv1.3

Current stunnel and OpenSSL releases can negotiate TLS 1.3 PSK without setting the legacy ciphers option. A deployment that must support TLS 1.2 or older peers needs an explicit, separately reviewed cipher policy.

Protect PSK files:

chmod 600 /etc/stunnel/server.psk /etc/stunnel/client.psk

PSK files must be neither world-readable nor world-writable. Transfer them over an authenticated confidential channel, never send them in email or include them in logs, and keep them out of source control.

If a client key is compromised, revoke it by removing only that identity from the server file and reloading stunnel. Reusing one key across clients removes this advantage.

Revocation Checking

A valid chain does not prove that a certificate has not been revoked. Stunnel supports:

For example:

verifyChain = yes
CAfile = /etc/stunnel/client-ca.pem
CRLfile = /etc/stunnel/client-ca.crl

Revocation checks add availability and latency dependencies. Test responder outages, CRL expiration, clock errors, and renewal behavior before enabling them in production.

Certificate and Key Rotation

A safe rotation procedure is:

  1. Install the new certificate chain and private key with restrictive permissions.
  2. For pinning, distribute a trust bundle containing both old and new leaf certificates.
  3. Replace configuration paths or atomically replace the files.
  4. Reload stunnel with SIGHUP on Unix or stunnel -reload for a Windows service.
  5. Confirm in the log and with an independent TLS client that the new certificate is active.
  6. Remove the old certificate or pin after all clients have migrated.

Some global options are not reloadable, but certificate, key, and service configuration changes are reloaded. Keep the previous files available for rollback until validation succeeds.

Hardware and Provider-Backed Keys

The cert, key, and CAstore options can use URIs supported by OpenSSL providers or engines. Typical integrations include PKCS#11 modules, hardware security modules, smart cards, TPM-backed keys, and Microsoft CNG.

For new OpenSSL 3 deployments, prefer providers configured with provider and, on supported OpenSSL releases, providerParameter. Engines are primarily a compatibility mechanism.

Provider URI, PIN, login, and trust-store behavior is implementation-specific. Protect PINs as secrets and verify that unattended startup, reload, failover, and key rotation work before production deployment.

Diagnostics

Use informational logs while configuring authentication:

foreground = yes
debug = info

Useful external checks include:

openssl s_client -connect server.example.com:8443 \
  -servername server.example.com \
  -verify_hostname server.example.com \
  -CAfile trusted-ca-bundle.pem

openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName

Typical failures include a missing intermediate certificate, the wrong CA bundle, a hostname absent from the SAN extension, an expired certificate, an incorrect system clock, mismatched certificate and key files, unreadable secret files, or a stale certificate pin.

See the FAQ for additional troubleshooting guidance and man stunnel for the authoritative syntax supported by the installed build.

Security Checklist

Our supporters:
Go to the top