SSL & Reverse Proxy
Configure HTTPS for production Sophon deployments with Caddy, Nginx, or Traefik.
Why HTTPS
Production deployments should always use HTTPS:
- Encrypts API keys and credentials in transit
- Required for secure WebSocket connections (SignalR uses
wss://) - Enables HTTP/2 for better performance
- Browsers block mixed content (HTTP API calls from HTTPS pages)
Sophon runs HTTP internally. A reverse proxy terminates SSL and forwards traffic to the Gateway (port 8081) and Dashboard (port 8080).
Caddy (Recommended)
Caddy provides automatic HTTPS via Let's Encrypt with zero configuration. It handles certificate issuance, renewal, and OCSP stapling automatically.
sophon.example.com {
# Dashboard (static SPA)
reverse_proxy localhost:8080
# Gateway API + SignalR WebSocket
@gateway path /api/* /hubs/*
handle @gateway {
reverse_proxy localhost:8081
}
}Run Caddy:
# Install
sudo apt install caddy # Debian/Ubuntu
brew install caddy # macOS
# Start (auto-obtains SSL certificate)
caddy run --config CaddyfileCaddy automatically handles WebSocket upgrades — no extra headers needed.
Nginx
server {
listen 443 ssl http2;
server_name sophon.example.com;
ssl_certificate /etc/ssl/certs/sophon.crt;
ssl_certificate_key /etc/ssl/private/sophon.key;
# Dashboard
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Gateway API
location /api/ {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# SignalR WebSocket — requires upgrade headers
location /hubs/ {
proxy_pass http://localhost:8081;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}
}
# HTTP redirect
server {
listen 80;
server_name sophon.example.com;
return 301 https://$host$request_uri;
}Key details:
- The
/hubs/location must includeproxy_http_version 1.1andUpgrade/Connectionheaders for SignalR WebSocket transport proxy_read_timeout 86400keeps long-lived WebSocket connections alive (24 hours)- For Let's Encrypt with Nginx, use Certbot
Enable the site:
sudo ln -s /etc/nginx/sites-available/sophon /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginxTraefik
If you're already running Traefik as your Docker ingress, add labels to the gateway and dashboard services in your compose file:
services:
sophon-gateway:
labels:
- "traefik.enable=true"
- "traefik.http.routers.sophon-api.rule=Host(`sophon.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/hubs`))"
- "traefik.http.routers.sophon-api.tls.certresolver=letsencrypt"
- "traefik.http.services.sophon-api.loadbalancer.server.port=8080"
sophon-dashboard:
labels:
- "traefik.enable=true"
- "traefik.http.routers.sophon-dashboard.rule=Host(`sophon.example.com`) && !PathPrefix(`/api`) && !PathPrefix(`/hubs`)"
- "traefik.http.routers.sophon-dashboard.tls.certresolver=letsencrypt"
- "traefik.http.services.sophon-dashboard.loadbalancer.server.port=80"Traefik handles WebSocket upgrades automatically when TLS is enabled.
Ensure your Traefik static configuration includes a certificate resolver:
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web