nself provides comprehensive SSL/TLS support with automatic certificate management for secure HTTPS connections. This guide covers SSL configuration for development, staging, and production environments.
# One command to set up trusted SSL for development
nself trust
# This:
# - Installs mkcert if not present
# - Creates local certificate authority
# - Generates certificates for *.local.nself.org
# - Installs CA in system trust store
# - Eliminates browser SSL warnings
# Your services are now accessible with green lock:
# https://api.local.nself.org
# https://auth.local.nself.org
# https://admin.local.nself.org# Request Let's Encrypt certificate
nself prod ssl request yourdomain.com --email admin@yourdomain.com
# Check certificate status
nself prod ssl status
# Renew when needed
nself prod ssl renewThe nself trust command provides one-click SSL setup for local development with browser trust.
# Install trusted SSL certificates
nself trust
# Output:
# Installing SSL certificate authority...
# ────────────────────────────────────
# ✓ mkcert installed
# ✓ Local CA created
# ✓ Certificates generated for:
# - local.nself.org
# - *.local.nself.org
# - localhost
# - *.localhost
# ✓ CA installed in system trust store
# ✓ CA installed in Firefox trust store
#
# Your services now have trusted SSL!The generated certificates cover all nself services:
# Covered domains
local.nself.org
*.local.nself.org # Wildcard for all subdomains
# Which enables:
https://api.local.nself.org # Hasura
https://auth.local.nself.org # Authentication
https://admin.local.nself.org # Admin UI
https://storage.local.nself.org # MinIO
https://mail.local.nself.org # MailPit
https://search.local.nself.org # MeiliSearch
https://[custom].local.nself.org # Any custom serviceIf you need manual control over certificate generation:
# Install mkcert manually
brew install mkcert # macOS
sudo apt install mkcert # Ubuntu/Debian
choco install mkcert # Windows
# Create local CA
mkcert -install
# Generate certificates
cd ssl/
mkcert local.nself.org "*.local.nself.org" localhost
# Configure nself
SSL_MODE=custom
SSL_CERT_PATH=ssl/local.nself.org+2.pem
SSL_KEY_PATH=ssl/local.nself.org+2-key.pem# Configuration in .environments/prod/.env
SSL_ENABLED=true
SSL_PROVIDER=letsencrypt
LETSENCRYPT_EMAIL=admin@yourdomain.com
# Request certificate
nself prod ssl request yourdomain.com
# Request with multiple domains (SAN)
nself prod ssl request yourdomain.com,www.yourdomain.com,api.yourdomain.com
# Use staging environment for testing (avoids rate limits)
nself prod ssl request yourdomain.com --staging# Check certificate status
nself prod ssl status
# Output:
# SSL Certificate Status
# ────────────────────────────────────
# Domain: yourdomain.com
# Issuer: Let's Encrypt Authority X3
# Valid From: 2026-01-24
# Valid Until: 2026-04-24
# Days Until Expiry: 89
# Chain Valid: Yes
# Status: Active
# Renew certificate
nself prod ssl renew
# Force renewal (even if not near expiry)
nself prod ssl renew --force
# Verify certificate chain
nself prod ssl verify# Automatic renewal is configured by default
# Certificates are checked daily and renewed if:
# - Less than 30 days until expiry
# - Certificate is valid
# Check renewal schedule
nself prod ssl status --verbose
# Manual renewal cron (if needed)
0 0 * * * /usr/local/bin/nself prod ssl renew --quiet# Configuration for custom certificates
SSL_MODE=custom
SSL_CERT_PATH=/path/to/certificate.crt
SSL_KEY_PATH=/path/to/private.key
SSL_CHAIN_PATH=/path/to/chain.crt # Optional CA chain
# Place certificates in ssl/ directory
mkdir -p ssl/
cp your-cert.crt ssl/certificate.crt
cp your-key.key ssl/private.key
cp your-chain.crt ssl/chain.crt
# Rebuild to apply
nself build
nself restart nginx# For wildcard certificates (*.yourdomain.com)
SSL_MODE=custom
SSL_CERT_PATH=ssl/wildcard.crt
SSL_KEY_PATH=ssl/wildcard.key
WILDCARD_CERT=true
# Note: Wildcard certificates require DNS validation
# with Let's Encrypt, which needs DNS API access# Using Cloudflare Origin Certificates
SSL_MODE=cloudflare
SSL_CERT_PATH=ssl/cloudflare-origin.pem
SSL_KEY_PATH=ssl/cloudflare-origin.key
# Cloudflare settings:
# - SSL/TLS: Full (strict)
# - Always Use HTTPS: On
# - Minimum TLS Version: 1.2# Recommended: TLS 1.2 and 1.3 only
SSL_PROTOCOLS="TLSv1.2 TLSv1.3"
# TLS 1.3 only (most secure, but less compatible)
SSL_PROTOCOLS="TLSv1.3"
# Legacy support (not recommended)
SSL_PROTOCOLS="TLSv1.2 TLSv1.3"# Strong cipher configuration
SSL_CIPHERS="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
# Prefer server ciphers
SSL_PREFER_SERVER_CIPHERS=true# Enable HSTS
HSTS_ENABLED=true
HSTS_MAX_AGE=31536000 # 1 year
HSTS_INCLUDE_SUBDOMAINS=true
HSTS_PRELOAD=true # For HSTS preload list
# Note: Only enable HSTS_PRELOAD if you're sure
# all subdomains will always have valid SSL# SSL session caching for performance
SSL_SESSION_CACHE=shared:SSL:10m
SSL_SESSION_TIMEOUT=10m
SSL_SESSION_TICKETS=on
# OCSP stapling for faster validation
SSL_STAPLING=on
SSL_STAPLING_VERIFY=on# Test with curl
curl -I https://api.local.nself.org
# Check certificate details
openssl s_client -connect api.local.nself.org:443 -servername api.local.nself.org
# Verify certificate
openssl x509 -in ssl/certificate.crt -text -noout
# Check expiration
openssl x509 -in ssl/certificate.crt -enddate -noout# Use nself built-in verification
nself prod ssl verify
# Test with SSL Labs (recommended)
# Visit: https://www.ssllabs.com/ssltest/
# Target: A+ rating
# Test with testssl.sh
docker run --rm -ti drwetter/testssl.sh yourdomain.com
# Check certificate chain
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com </dev/null 2>/dev/null | openssl x509 -text -nooutTo achieve an A+ rating on SSL Labs:
# Required configuration
SSL_PROTOCOLS="TLSv1.2 TLSv1.3"
SSL_PREFER_SERVER_CIPHERS=true
HSTS_ENABLED=true
HSTS_MAX_AGE=31536000
HSTS_INCLUDE_SUBDOMAINS=true
# Recommended additions
SSL_STAPLING=on
SSL_STAPLING_VERIFY=on
# Ensure no mixed content
FORCE_HTTPS=true# Reinstall trust
nself trust
# If Firefox still shows warning:
# 1. Open Firefox preferences
# 2. Search "certificates"
# 3. Click "View Certificates"
# 4. Import the CA from: ~/.local/share/mkcert/rootCA.pem
# Check CA installation
mkcert -CAROOT# If you hit rate limits:
# 1. Use staging environment for testing
nself prod ssl request yourdomain.com --staging
# 2. Wait for rate limit to reset
# - 5 certificates per week per domain
# - 50 certificates per week per account
# 3. Use staging certificates temporarily
LETSENCRYPT_STAGING=true# Check if certificate matches private key
openssl x509 -noout -modulus -in ssl/certificate.crt | openssl md5
openssl rsa -noout -modulus -in ssl/private.key | openssl md5
# The MD5 hashes should match
# Regenerate if they don't match
rm ssl/certificate.crt ssl/private.key
nself prod ssl request yourdomain.com# Check nginx configuration
nself exec nginx nginx -t
# View nginx error logs
nself logs nginx | grep -i ssl
# Common issues:
# - Wrong file permissions (should be 644 for certs, 600 for keys)
chmod 644 ssl/*.crt ssl/*.pem
chmod 600 ssl/*.key
# - Certificate file not found
ls -la ssl/# Ensure all resources use HTTPS
FORCE_HTTPS=true
HTTPS_REDIRECT=true
# Check for hard-coded HTTP URLs in:
# - Frontend code
# - API responses
# - Database content
# - External resources# .environments/dev/.env
SSL_MODE=mkcert
BASE_DOMAIN=local.nself.org
# Run once to set up
nself trust# .environments/staging/.env
SSL_ENABLED=true
SSL_PROVIDER=letsencrypt
LETSENCRYPT_EMAIL=admin@yourdomain.com
LETSENCRYPT_STAGING=true # Use staging certs
BASE_DOMAIN=staging.yourdomain.com# .environments/prod/.env
SSL_ENABLED=true
SSL_PROVIDER=letsencrypt
LETSENCRYPT_EMAIL=admin@yourdomain.com
LETSENCRYPT_STAGING=false # Use real certs
BASE_DOMAIN=yourdomain.com
HSTS_ENABLED=true
HSTS_MAX_AGE=31536000SSL works best with proper security headers:
# Enable all security headers
SECURITY_HEADERS_ENABLED=true
# HSTS
HSTS_ENABLED=true
HSTS_MAX_AGE=31536000
HSTS_INCLUDE_SUBDOMAINS=true
# Content Security Policy
CSP_ENABLED=true
CSP_UPGRADE_INSECURE_REQUESTS=true
# Other headers
X_FRAME_OPTIONS=DENY
X_CONTENT_TYPE_OPTIONS=nosniff
REFERRER_POLICY=strict-origin-when-cross-origin# Set up expiration alerts
SSL_MONITOR_ENABLED=true
SSL_EXPIRY_WARNING_DAYS=30
SSL_ALERT_EMAIL=admin@yourdomain.com
# Check certificate status regularly
nself prod ssl status
# Add to monitoring/cron
# Check weekly for approaching expiration
0 9 * * 1 nself prod ssl status --json | jq '.days_until_expiry < 30'SSL/TLS is essential for secure communication. Use nself trust for effortless development SSL and Let's Encrypt for production certificates.