Secure your environment with HTTPS using self-signed certificates for local development or Let’s Encrypt for production.
🔀 Multi-instance mode: everything below applies when
APP_MULTI_INSTANCE=0(the default, single-instance NGINX setup). WhenAPP_MULTI_INSTANCE=1, TLS is terminated by Traefik instead —make ssljust skips (production certs are issued and renewed by Traefik itself, stored in a Docker volume, no host files to manage), andmake local-certwrites its certificate underkit-modules/proxy/certs/local/instead ofconfig/ssl/live/. Seekit-modules/proxy/README.md.proxyis a paid kit-module, not included by default — see Infrastructure.
Production & Staging
1. Enable HTTPS in environment:
Set the protocol in your production or staging environment file:
APP_PROTOCOL=https
2. Issue TLS Certificates via Let’s Encrypt:
Run the built-in Certbot script (requires .env.runtime to already exist — run make env first if you haven’t):
make ssl
This will:
- Read
APP_DOMAINfrom.env.runtime - Generate a temporary 1-day dummy self-signed certificate
- Start NGINX (
docker compose up -d nginx) so it can serve the ACME challenge - Delete the dummy certificate, then run 🔐 Certbot (
certbot certonly) using the webroot authenticator configured inconfig/certbot/cli.ini(port 80must be reachable publicly). For an apex domain (e.g.example.com), the cert also coverswww.example.com; for a subdomain (e.g.dev.example.com), only that exact hostname is requested. - Save certificate files to:
config/ssl/live/<your-domain>/fullchain.pem
config/ssl/live/<your-domain>/privkey.pem
- Restart NGINX with HTTPS enabled
ℹ️ If the certificate already exists, the script skips renewal. ⚠️ Ensure
port 80is open and not blocked by a firewall or ISP.
3. Manual Certificates (optional):
You may manually place your certificates at:
config/ssl/live/<your-domain>/fullchain.pem
config/ssl/live/<your-domain>/privkey.pem
Local Development
Let’s Encrypt does not issue certificates for local domains like .localhost. Use self-signed certificates instead.
Option 1: mkcert (recommended)
The one-command path is make local-cert, which generates and installs a locally-trusted (mkcert) certificate for you. Prerequisite: mkcert must be on your host PATH, with mkcert -install run once beforehand (the script does not install mkcert itself). The command is idempotent — it skips regeneration if a valid certificate already exists; pass make local-cert force to regenerate anyway.
mkcert -install
make local-cert
If you prefer to run mkcert manually (or need to see what make local-cert does under the hood), install mkcert and run:
mkcert -install
mkcert myproject.localhost
This creates two files, e.g.:
myproject.localhost.pem
myproject.localhost-key.pem
Rename and copy them to:
config/ssl/live/myproject.localhost/fullchain.pem
config/ssl/live/myproject.localhost/privkey.pem
Then update your local environment type file at config/environment/.env.type.local, or create an override file atconfig/environment/.env.type.local.override.
➡️ See Environment Configuration and Secret Management for details.
APP_PROTOCOL=https
Start your environment:
make up
📌 Local HTTPS support assumes your domain matches the certificate. Adjust your
/etc/hostsaccordingly.
Option 2: Manual Self-Signed Certificates
Generate self-signed certificates using OpenSSL:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout config/ssl/live/myproject.localhost/privkey.pem \
-out config/ssl/live/myproject.localhost/fullchain.pem \
-subj "/CN=myproject.localhost"
This creates a self-signed certificate valid for 365 days.
⚠️ Self-signed certificates will trigger browser warnings. You can bypass them for local development. To avoid warnings, you can add the self-signed certificate to your system’s trusted certificates store.
See Letsencrypt Documentation for more details on using self-signed certificates locally.
↻ Switching to HTTPS and redirects
The NGINX setup supports both HTTP and HTTPS, with automatic redirection configured via:
config/nginx/config/http.conf.template— used whenAPP_PROTOCOL=httpconfig/nginx/config/https.conf.template— used whenAPP_PROTOCOL=https
Redirection behavior:
- HTTP → HTTPS
www.domain→domain
Configuration is automatically templated and mounted at container start. No manual edits are required in
*.conffiles.