Skip to main content

TLS / HTTPS Configuration

Forja supports native TLS termination via axum-server + rustls (axum_server::bind_rustls). When TLS_CERT_PATH and TLS_KEY_PATH are both set, the backend binds HTTPS directly without a reverse proxy.

When to Use Application-Level TLS​

In most deployments, TLS is handled by the infrastructure layer:

  • Railway -- terminates TLS at the edge automatically. No application configuration needed.
  • Reverse proxy (nginx, Caddy, Traefik) -- terminates TLS before traffic reaches the application.
  • Load balancers (AWS ALB, Cloudflare) -- terminate TLS upstream.

You only need application-level TLS when the Forja binary is directly exposed to the internet without any proxy or platform handling HTTPS for you.

Configuration​

Set two environment variables pointing to your certificate and private key files:

VariableDescription
TLS_CERT_PATHAbsolute path to the TLS certificate file (PEM format)
TLS_KEY_PATHAbsolute path to the TLS private key file (PEM format)
export TLS_CERT_PATH=/etc/ssl/certs/forja.pem
export TLS_KEY_PATH=/etc/ssl/private/forja-key.pem

When both variables are set, the application starts with HTTPS enabled. When either variable is absent, the application starts in plain HTTP mode.

Supported Certificate Types​

Any PEM-encoded X.509 certificate chain works with Forja's TLS configuration.

Let's Encrypt (Certbot)​

Use Certbot to obtain free certificates from Let's Encrypt:

certbot certonly --standalone -d cms.yourdomain.com

Then set the paths:

TLS_CERT_PATH=/etc/letsencrypt/live/cms.yourdomain.com/fullchain.pem
TLS_KEY_PATH=/etc/letsencrypt/live/cms.yourdomain.com/privkey.pem
tip

Let's Encrypt certificates expire every 90 days. Set up a cron job or systemd timer to run certbot renew and restart the application.

Self-Signed Certificates​

For development or internal deployments, generate a self-signed certificate:

openssl req -x509 -newkey rsa:4096 \
-keyout key.pem -out cert.pem \
-days 365 -nodes \
-subj "/CN=localhost"
TLS_CERT_PATH=./cert.pem
TLS_KEY_PATH=./key.pem

Clients connecting to a self-signed certificate will see a browser warning unless the certificate is explicitly trusted.

Purchased / CA-Signed Certificates​

If you have a certificate from a commercial Certificate Authority, ensure the file includes the full chain (your certificate followed by any intermediate certificates):

cat your-domain.crt intermediate.crt > fullchain.pem
TLS_CERT_PATH=/path/to/fullchain.pem
TLS_KEY_PATH=/path/to/your-domain.key

Docker Deployments​

When using Docker, mount the certificate files into the container:

services:
app:
image: forja
ports:
- "443:8000"
environment:
TLS_CERT_PATH: /certs/fullchain.pem
TLS_KEY_PATH: /certs/privkey.pem
volumes:
- /etc/letsencrypt/live/cms.yourdomain.com:/certs:ro

Verifying TLS​

After starting the application with TLS enabled, verify the connection:

curl -v https://localhost:8000/health

The output should show a successful TLS handshake and a JSON health response.

Railway and Platform Deployments​

Railway handles TLS termination at the edge automatically. All traffic between Railway's edge and your application container travels over an internal network. Do not set TLS_CERT_PATH or TLS_KEY_PATH on Railway -- doing so would cause the application to expect HTTPS connections from Railway's internal routing, which sends plain HTTP.