TLS
Clients may encrypt the connection to the proxy, on the same ports: a connection starting with a TLS handshake is decrypted, and HTTP or SOCKS5 is detected inside. Credentials then don’t travel in the clear. TLS is on while a certificate is active: add one under TLS certificates in the admin UI, the first one is activated right away. Without one, TLS clients get a handshake failure, plain HTTP and SOCKS5 keep working.
Certificates
Section titled “Certificates”The certificate must be for the host name clients connect to. One certificate is active at a time and serves all ports, for several names use one with all of them in it. Activating another one, on adding it or later on its page, turns the active one off: new connections get it within the certificate cache TTL (settings), open ones keep theirs, no restart needed. The proxy looks the certificate up once per that TTL, not on every connection: TLS clients can’t load the database before they authenticate.
The admin UI names the one turned off, and if another admin has activated one meanwhile, it refuses and shows the new state instead of turning off a certificate you haven’t seen. The active one can’t be deleted, deactivate it first.
Self-signed certificates
Section titled “Self-signed certificates”A self-signed certificate works too, the admin UI generates one for given names. Clients trust it only if told
to: download the certificate from its page for curl’s --proxy-cacert, or skip the check with --proxy-insecure.
Renewal with certbot
Section titled “Renewal with certbot”A renewed certificate, e.g. from Let’s Encrypt, goes in with importcert, see
Management commands. certbot can run it after every renewal, with
the same environment as the proxy:
certbot renew --deploy-hook 'cd /opt/proxium && uv run --env-file .env proxium-manage importcert --no-input \ --cert "$RENEWED_LINEAGE/fullchain.pem" --key "$RENEWED_LINEAGE/privkey.pem"'Encryption key
Section titled “Encryption key”Private keys are stored encrypted with ENCRYPTION_KEY, the API never returns them. Generate the key once and give
the same one to the proxy, the API and the management commands:
python3 -c "import base64, os; print(base64.urlsafe_b64encode(os.urandom(32)).decode())"To replace the key without downtime, e.g. after a leak:
-
Generate a new key. Set it as
ENCRYPTION_KEYand the current one asENCRYPTION_OLD_KEYSfor the proxy, the API and the management commands, then restart them. Both keys now decrypt, new secrets get the new one. -
Re-encrypt the stored secrets with the new key. Stopped halfway, it’s just run again:
Terminal window uv run --env-file .env proxium-manage rotateencryptionkey -
Remove
ENCRYPTION_OLD_KEYSeverywhere and restart again.
Temporary directory
Section titled “Temporary directory”The proxy needs a writable temporary directory: Python’s ssl loads a key only from a file, not from memory
(python/cpython#60691), so the decrypted key goes to a file
readable by the proxy’s user alone and is removed right after loading. In a container with a read-only root, point
TMPDIR to a tmpfs, e.g. an emptyDir with medium: Memory in Kubernetes: the key then never reaches a disk.
Without it, TLS clients are refused with “Can’t write the certificate to a temporary file” in the log.
Limitations
Section titled “Limitations”SOCKS5 inside TLS works too, but few clients support it, curl doesn’t. HTTP/2 to the proxy isn’t supported, clients fall back to HTTP/1.1.