SSL/TLS Configuration


v0.4.8Updated for nself v0.4.8

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.

SSL Commands (v0.4.8)

  • nself trust: Install local development certificates
  • nself prod ssl status: Check certificate status
  • nself prod ssl request: Request Let's Encrypt certificate
  • nself prod ssl renew: Renew certificates
  • nself prod ssl verify: Verify certificate chain

Quick Start

Development (Local)

# 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

Production

# 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 renew

Development SSL

The nself trust Command

The 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!

What nself trust Does

  1. Installs mkcert: Downloads and installs the mkcert tool if not present
  2. Creates Local CA: Generates a local certificate authority
  3. Generates Certificates: Creates certificates for local domains
  4. System Trust: Installs CA in macOS Keychain, Windows Certificate Store, or Linux CA bundle
  5. Browser Trust: Configures Firefox and Chrome to trust the CA

Certificate Coverage

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 service

Manual Certificate Setup

If 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

Production SSL

Let's Encrypt (Recommended)

# 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

Certificate Management

# 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

# 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

Custom Certificates

Using Your Own Certificates

# 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

Wildcard Certificates

# 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

Cloudflare Origin Certificates

# 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

SSL Configuration Options

TLS Protocol Versions

# 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"

Cipher Suites

# 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

HSTS (HTTP Strict Transport Security)

# 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

Session Configuration

# 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

Testing SSL

Local Testing

# 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

Production Testing

# 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 -noout

SSL Labs A+ Rating

To 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

Troubleshooting

Certificate Not Trusted (Local)

# 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

Let's Encrypt Rate Limits

# 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

Certificate Mismatch

# 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

Nginx SSL Errors

# 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/

Mixed Content Warnings

# 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

Environment-Specific Configuration

Development

# .environments/dev/.env
SSL_MODE=mkcert
BASE_DOMAIN=local.nself.org

# Run once to set up
nself trust

Staging

# .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

Production

# .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=31536000

Security Headers

SSL 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

Certificate Monitoring

# 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'

Best Practices

  • Use modern TLS: TLS 1.2 minimum, prefer TLS 1.3
  • Enable HSTS: Force HTTPS for all connections
  • Monitor expiration: Set up alerts for certificate expiry
  • Test regularly: Use SSL Labs to verify configuration
  • Automate renewal: Let nself handle automatic renewal
  • Secure private keys: Proper permissions (600) and backups
  • Use strong ciphers: Disable weak cipher suites
  • Enable OCSP stapling: Faster certificate validation

Next Steps

SSL/TLS is essential for secure communication. Use nself trust for effortless development SSL and Let's Encrypt for production certificates.