TLS and domains
Serve the panel over HTTPS with ACME, your own certificate, or a reverse proxy.
Overview
You should serve the panel over HTTPS in production, because secure session cookies require it. There are three ways to get there, and the app picks one at startup in a fixed order: manual certificate files → ACME → plain HTTP. This page is about TLS for the panel itself; certificates used by your proxy inbounds are managed on the Certificates page.
Before you start
- A domain whose DNS already points at the server, if you want ACME.
- The ACME challenge must be able to reach the server from the internet.
- Decide whether the panel terminates TLS itself or sits behind nginx, Caddy, Traefik or a CDN.
Steps
Automatic certificates with ACME
-
Point your domain at the server and confirm DNS has propagated.
-
Set the ACME keys in
.env:APP_BASE_URL=https://panel.example.com ACME_ENABLED=true ACME_EMAIL=you@example.com ACME_STAGING=true ACME_AUTO_RENEW=true ACME_CACHE_DIR=/app/data/acme JWT_COOKIE_DOMAIN=example.com JWT_COOKIE_SECURE=true -
Restart and confirm a staging certificate is issued. Then set
ACME_STAGING=falseand restart again for the real one. Staging first keeps you from burning Let’s Encrypt rate limits while you debug DNS. -
Issued certificates are cached in
ACME_CACHE_DIR, which is a persistent volume under Docker, so restarts do not re-issue.
ACME settings are also editable in Settings → Server → HTTPS and applied on
the next restart, so you can flip ACME on or off without touching .env.
Bringing your own certificate
Point the app at your PEM files. Manual files take precedence over ACME.
TLS_CERT_FILE=/path/to/fullchain.pem
TLS_KEY_FILE=/path/to/privkey.pem
Behind a reverse proxy
Terminate TLS at the proxy and let the app speak plain HTTP locally, but still
set APP_BASE_URL to the public HTTPS URL.
APP_BASE_URL=https://panel.example.com
ACME_ENABLED=false
JWT_COOKIE_SECURE=true
JWT_COOKIE_DOMAIN=example.com
The panel uses WebSockets and server-sent events for the live terminal, charts
and events, so the proxy must pass Upgrade and Connection headers and use a
generous read timeout.
server {
listen 443 ssl http2;
server_name panel.example.com;
ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9761;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Reference
| Goal | Set |
|---|---|
| Automatic HTTPS on a domain | ACME_ENABLED=true, ACME_EMAIL, APP_BASE_URL=https://… |
| Your own certificate | TLS_CERT_FILE, TLS_KEY_FILE |
| Behind a proxy or CDN | APP_BASE_URL=https://…, ACME off, secure cookies on |
| Plain IP, for testing only | APP_BASE_URL=http://ip:port, ACME off, JWT_COOKIE_SECURE=false |
| Variable | What it does | Default |
|---|---|---|
ACME_ENABLED |
Turns automatic issuance on. With it off, no certificate is issued even if APP_BASE_URL is HTTPS. |
false |
ACME_EMAIL |
Contact address for Let’s Encrypt notices. Required when ACME is on. | empty |
ACME_STAGING |
Uses the staging directory while you test. | false |
ACME_AUTO_RENEW |
Keeps the certificate renewed. | true |
ACME_CACHE_DIR |
Where issued certificates are cached. | /app/data/acme |
TLS_CERT_FILE |
Path to your certificate chain. Overrides ACME. | unset |
TLS_KEY_FILE |
Path to your private key. | unset |
JWT_COOKIE_SECURE |
Marks session cookies secure. Needs HTTPS. | false |
JWT_COOKIE_DOMAIN |
Cookie domain; leave empty in IP mode. | empty |
Troubleshooting
Certificate issuance fails. Confirm the domain resolves to this server and
that the ACME challenge can reach it, because a firewall or a proxy in front of the
panel that does not pass the challenge path is the usual cause. Test with
ACME_STAGING=true so failures do not count against your rate limit.