TLS Certificates
Miren automatically provisions TLS certificates for your applications using Let's Encrypt. By default, no configuration is needed — when you set a route for your app, Miren obtains a certificate automatically.
How It Works
When a request arrives for a hostname with a configured route, Miren provisions a TLS certificate from Let's Encrypt using the ACME protocol. Certificates are cached on disk and renewed automatically before they expire.
Hostnames without a configured route are served with a self-signed fallback certificate (browsers will show a warning).
For wildcard routes (e.g., *.myapp.example.com), TLS certificates are provisioned for each matching subdomain as requests arrive. See Wildcard Routes for details.
Challenge Types
Let's Encrypt needs to verify that you control the domain before issuing a certificate. Miren supports two verification methods.
HTTP-01 Challenge (Default)
The default method. Let's Encrypt makes an HTTP request to your server on port 80 to verify domain ownership.
Requirements:
- Your server must be reachable from the public internet on ports 80 and 443
- DNS for your domain must point to the server's public IP
This is the zero-configuration option — it works out of the box with miren server install.
DNS-01 Challenge
If your server isn't publicly reachable (e.g., it's behind a VPN like Tailscale, on a private network, or doesn't have ports 80/443 open to the internet), you can use DNS-01 challenges instead. This method proves domain ownership by creating a DNS TXT record, so it works regardless of whether your server is reachable from the internet.
Miren uses lego for DNS challenges, which supports 90+ DNS providers.
Configuration
Add the DNS provider and ACME email to your server config file:
[tls]
acme_dns_provider = "dnsimple"
acme_email = "you@example.com"
Each DNS provider requires credentials passed via environment variables. Create an environment file for the Miren service:
DNSIMPLE_OAUTH_TOKEN=your-token-here
Then update the systemd service to load the environment file and config:
sudo systemctl edit miren --force
Add the environment file:
[Service]
EnvironmentFile=/var/lib/miren/server/env
Restart to pick up the changes:
sudo systemctl restart miren
Provider Examples
Each provider needs different environment variables. Here are a few common ones:
DNSimple:
acme_dns_provider = "dnsimple"
DNSIMPLE_OAUTH_TOKEN=your-token
Cloudflare:
acme_dns_provider = "cloudflare"
CF_DNS_API_TOKEN=your-token
Route 53 (AWS):
acme_dns_provider = "route53"
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_REGION=us-east-1
See the lego DNS provider documentation for the full list of supported providers and their required environment variables.
Ingress Modes and TLS
Whether Miren terminates TLS at all (and on which ports) is set by ingress.mode. The default tls-autoprovision mode is what this page has been describing: TLS on :443, plus :80 for the HTTPS redirect and HTTP-01 ACME challenges.
Two other modes are available for deployments where Miren sits behind a TLS-terminating proxy (nginx, Caddy, Cloudflare Tunnel, ALB):
| Mode | What Miren does | Cert source |
|---|---|---|
tls-autoprovision (default) | Binds :443 for TLS and :80 for redirect / HTTP-01 ACME | [tls] (ACME or self-signed) |
behind-proxy-http | Plain HTTP at the configured address (default 127.0.0.1:80); TLS lives at the proxy | n/a (proxy terminates TLS) |
behind-proxy-https | TLS terminated at the configured address (default 127.0.0.1:443); no :80 listener, so no HTTP-01 ACME | [tls] self-signed or DNS-01 ACME only |
See Server Configuration Reference → [ingress] for the full schema. The HTTP-01 ACME flow described above only applies under tls-autoprovision; under behind-proxy-https, certs must come from DNS-01 ACME or be self-signed because Miren doesn't bind :80 in that mode (and the public DNS for the hostname points at the proxy anyway, not at Miren).
TLS Settings Reference
All TLS settings live under the [tls] section of the server config file (typically /var/lib/miren/server/config.toml). The three ingress-cert settings below are consulted only under TLS-terminating ingress modes:
| Setting | CLI Flag | Description |
|---|---|---|
acme_email | --acme-email | Email for Let's Encrypt account registration and expiry notifications |
acme_dns_provider | --acme-dns-provider | DNS provider name for DNS-01 challenges (e.g., cloudflare, route53, dnsimple) |
self_signed | --self-signed-tls | Use a self-signed cert instead of ACME (development, or behind a non-verifying TLS proxy) |
Two additional [tls] settings apply to the API server and etcd certs rather than ingress, so they're valid under any ingress mode:
| Setting | CLI Flag | Description |
|---|---|---|
additional_names | --dns-names | Extra DNS names appended to the API server and etcd cert SANs |
additional_ips | --ips | Extra IPs appended to the API server and etcd cert SANs |
Troubleshooting
Certificate Not Provisioning
Check the server logs for ACME errors:
sudo journalctl -u miren | grep -i acme
HTTP-01 challenges: Ensure ports 80 and 443 are reachable from the public internet. See Firewall Configuration for cloud provider-specific guidance.
DNS-01 challenges: Verify your DNS provider credentials are correct and the environment file is loaded:
sudo systemctl show miren | grep EnvironmentFile
Wrong Certificate / Self-Signed Warning
If you're seeing a self-signed certificate warning for a domain that should have a real certificate, check that a route is configured for that hostname:
miren route
Miren only provisions ACME certificates for hostnames with explicitly configured routes. All other hostnames get the self-signed fallback.