How to Require Client Certificates (mTLS) on a Pangolin Resource
Most authentication on a public resource happens after the connection is open. A visitor signs in on the Pangolin login page or sends credentials in a header, and Pangolin decides whether to let the request through. Client certificate authentication (mTLS) moves the first check earlier. The browser or API client has to present a certificate signed by a CA you trust during the TLS handshake, and if it can't, the connection fails before any login page or application code is reached.
That makes mTLS a good fit for resources that only a known set of devices should ever touch: an admin panel used from company laptops, an internal API called by a handful of services, or a dashboard you want hidden from anyone who hasn't been issued a certificate. Pangolin lets you turn it on per resource and combine it with the other authentication methods you already use.
How mTLS Fits With Other Auth Methods
Pangolin does not issue or host client certificates by default (contact us for more information). You bring your own CA, upload its public certificate to the resource, and hand out client certificates signed by that CA to the people and machines that should connect.
Once a client completes the handshake with a valid certificate, every other method configured on the resource still runs. If Platform SSO is on, a browser user still has to sign in. If header auth is on, a script still has to send the right credentials. The certificate shows that you issued access to the device, and the second method identifies the person using it.
A few behaviors follow from the check happening at the TLS layer:
- There is no optional mode. When mTLS is enabled on a resource, a valid certificate is always required.
- Access rules cannot bypass it. A bypass-auth rule only skips the authentication stages that come after the handshake.
- A browser without a certificate gets a connection error (in the video, Chrome shows a "misdirected request" page) instead of the Pangolin login screen.
- Requests rejected for a missing or invalid certificate never reach Pangolin's proxy, so they do not appear in the HTTP request logs. Requests that pass the handshake are logged as usual.
This is separate from site mTLS, which authenticates a Newt site connector to the control plane.
Requirements
- An HTTPS public resource with SSL enabled
- At least one CA public certificate to upload
- A site connector that can reach the backend you want to protect
Step by Step
1. Create a site and a resource
If you already have a working HTTPS resource, skip to step 2.
In the Pangolin dashboard, open Sites, click Add Site, give it a name, and run the install command it generates on a machine inside the network that hosts your application. The site shows as connected once the connector is up. See installing a site for other install methods.
For testing, any small HTTP server will do. The video uses a whoami container on port 8000, which returns the request headers it receives and makes it easy to see what Pangolin forwards.
Next, open Public Resources, click Add Resource, and choose HTTPS. Assign a domain such as test.example.com and add a target on your site pointing at localhost:8000. Visit the URL to confirm the page loads. With the default settings, a fresh incognito window should send you to the Pangolin login page first.
2. Generate a CA and a client certificate
If you already run a PKI, use your existing CA and skip to step 3. Otherwise, three OpenSSL commands give you a CA and one client certificate.
Create the CA key and certificate. Change the CN to something you'll recognize later:
openssl req -x509 -newkey rsa:4096 -days 365 -nodes \
-keyout ca.key -out ca.crt \
-subj "/CN=My-Local-CA"
ca.crt is the file you upload to Pangolin. Keep ca.key off the server and somewhere safe, because anyone holding it can sign certificates your resource will accept.
Create a key and signing request for the client. Give each user or device its own key, and use a CN that identifies it, since that value is what your backend will see:
openssl req -newkey rsa:2048 -nodes \
-keyout client.key -out client.csr \
-subj "/CN=my-client-user"
Sign the client certificate with the CA:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 365
Repeat the last two commands for every additional client, using a different file name and CN each time.
You don't need a server certificate. Pangolin already serves the resource over HTTPS with its own certificate, and the CA you just made is only used to verify clients.
3. Enable Client Certificate (mTLS) on the resource
Open the resource's Authentication tab and enable Client Certificate (mTLS) under Other Methods. Upload ca.crt (PEM files ending in .pem, .crt, or .cer are accepted, and bundles work too), then save.
Upload only public CA certificates here, never a private key. A resource can trust up to 20 CA certificates, and removing the last one turns mTLS off.
If you protect many resources the same way, set this on a resource policy instead and attach the policy to each resource.
Reload the resource in a browser that has no client certificate installed. The connection should now fail before the login page appears.
4. Connect from the command line
curl can use the PEM files directly:
curl --cert client.crt --key client.key https://test.example.com
If Platform SSO is the only other method on the resource, this request will get through the handshake and then come back unauthorized. That result is expected. curl can't complete a browser sign-in flow, so for machine-to-machine access, add header auth to the resource and pass its credentials with -u:
curl --cert client.crt --key client.key \
-u username:password \
https://test.example.com
To confirm the certificate is doing its job, run the same command without --cert and --key. curl should fail with an SSL error before any HTTP response comes back.
5. Connect from Chrome
Browsers import client certificates as a single PKCS#12 file containing the certificate and its key. Build one from the files above:
openssl pkcs12 -export \
-in client.crt \
-inkey client.key \
-out client.p12
OpenSSL asks for an export password. Whoever imports the file will need it.
To import client.p12:
- Go to
chrome://certificate-manager, or open Settings > Privacy and security > Security > Manage certificates. - Open Your certificates.
- On Linux and ChromeOS, click Import, pick
client.p12, and enter the password. On Windows and macOS, Chrome reads from the operating system's certificate store, so double-clicking the file and following the system prompts also works. - Quit Chrome completely and reopen it.
The next time you open the resource, Chrome asks which certificate to use. Pick the one you imported, and you'll land on the Pangolin login page (or straight on the app, if you already have a session). If you pick the wrong certificate or dismiss the prompt, Chrome remembers that choice until it restarts.
If macOS rejects the file with a password or MAC verification error, re-export it with openssl pkcs12 -export -legacy .... OpenSSL 3 defaults to newer encryption that some versions of Keychain can't read.
Reading Certificate Details in Your Backend
After a successful handshake, Pangolin forwards the verified certificate's subject, issuer, serial number, validity dates, and SANs to your backend in the X-Forwarded-Tls-Client-Cert-Info header. Your application can read the CN you set when signing to tell clients apart in its logs or to make its own authorization decisions. This header is separate from the identity headers described in Forwarded Headers.
FAQ
Can I use mTLS together with Platform SSO or a PIN?
Yes. mTLS is checked during the TLS handshake, and every other configured method (Platform SSO, PIN, passcode, email OTP, header auth, shareable links, and access rules) runs afterward on connections that pass.
Can an access rule let some clients skip the certificate?
No. Bypass-auth rules only skip the authentication stages after the handshake. A client without a valid certificate is always rejected when mTLS is enabled.
What does a user without a certificate see?
A browser connection error. Because the request is rejected during the handshake, Pangolin never serves its login page to that client, and the attempt does not show up in the HTTP request logs.
Can I trust more than one CA on the same resource?
Yes. A resource or resource policy can hold up to 20 CA certificates, and you can upload a bundle containing several at once.
How do I revoke access for one client?
Since Pangolin trusts every certificate signed by an uploaded CA, the most direct way to cut off a single client is to issue certificates from a separate CA per group of users, then remove that CA from the resource. Setting short validity periods on client certificates also limits how long a lost certificate stays usable.
Is this the same as site mTLS?
No. Site mTLS authenticates a Newt site connector to the Pangolin control plane. Resource mTLS, covered here, authenticates browsers and API clients connecting to a public resource.
See Also
- Client Certificate (mTLS) docs: full reference for the feature
- Authentication for public resources: every method you can combine with mTLS
- Resource Policies: apply the same mTLS and auth settings across many resources
- Forwarded Headers: identity headers Pangolin sends to your backend
- How to Scrape Prometheus Metrics Behind a Firewall: a header auth walkthrough that pairs well with mTLS for machine clients
Pangolin is an open-source Secure Access Service Edge (SASE) platform built on WireGuard® that unifies modern networking and security for teams connecting to apps, infrastructure, and AI workloads. Designed as an open, self-hostable alternative to complex legacy suites, Pangolin brings together a zero-trust VPN, zero-trust reverse proxy, privileged access management, and an identity-aware AI gateway under a single identity and policy model. Whether deployed on-premises using a lightweight user-space connector or managed via Pangolin Cloud, it gives organizations transparent, auditable, and frictionless control over their entire digital footprint.
Keep reading
- How to Set Up HTTP Redirects With Pangolin
How to Set Up HTTP Redirects With PangolinSend any hostname or path to another URL from the Pangolin dashboard. Attach redirects to a domain or a public resource, match on path, rewrite the path, and choose between temporary and permanent status codes.
- Node2Shell: Protect Self-Hosted Apps from CVE-2026-111497
Node2Shell: Protect Self-Hosted Apps from CVE-2026-111497Node2Shell (CVE-2026-111497) is a high-severity Brotli flaw in Node.js that can allow remote code execution. Patch the runtime, then keep private apps behind auth or fully off the internet with an identity-based VPN and reverse proxy.
- PHP2Shell: Protect Self-Hosted Apps from CVE-2026-109618 and CVE-2026-109619
PHP2Shell: Protect Self-Hosted Apps from CVE-2026-109618 and CVE-2026-109619PHP2Shell (CVE-2026-109618, CVE-2026-109619) is under active exploit. Patch PHP, then keep private apps behind auth or fully off the internet with an identity-based VPN and reverse proxy.