feat: native HTTPS support with bundled snakeoil default cert
server/index.js:
- Import http and https modules
- Resolve TLS_ENABLED early (before Helmet) so upgradeInsecureRequests
CSP directive fires when TLS is active directly (not only via proxy)
- loadTlsCredentials() reads TLS_CERT/TLS_KEY (defaulting to bundled
snakeoil) and returns null on failure (graceful HTTP fallback)
- Start https.createServer or http.createServer depending on credentials
- Startup banner now shows protocol, TLS cert path, and snakeoil warning
certs/:
- Add bundled snakeoil self-signed certificate (RSA 2048, 10yr, SAN for
localhost + 127.0.0.1) for out-of-the-box HTTPS without configuration
- .gitignore allows only snakeoil.{crt,key} — real certs must not be
committed
Dockerfile:
- COPY certs/ into image so snakeoil default is always available
- HEALTHCHECK updated to https:// with --no-check-certificate
docker-compose.yaml:
- Port now exposes HTTPS directly by default
- TLS_CERT/TLS_KEY/TLS_ENABLED/TRUST_PROXY documented with Option A/B
- cert volume mount examples added (commented out)
- healthcheck updated to https with --no-check-certificate
.env.sample:
- New TLS/HTTPS section with TLS_ENABLED, TLS_CERT, TLS_KEY
- openssl self-signed cert generation example included
docs/ARCHITECTURE.md:
- Configuration table: TLS_ENABLED, TLS_CERT, TLS_KEY env vars added
- Docker image section: TLS default behaviour documented
- Docker Compose example: Option A (direct TLS) / Option B (proxy) layout
- Security checklist: HTTPS now first item, updated for TLS modes
This commit is contained in:
@@ -4,14 +4,23 @@ services:
|
||||
container_name: sofarr
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3001:3001" # bind to loopback only — expose via reverse proxy
|
||||
# Direct HTTPS (default — uses bundled snakeoil cert if TLS_CERT not set)
|
||||
- "3001:3001"
|
||||
# Uncomment the line below and comment out the above to bind to loopback
|
||||
# only when using a reverse proxy (set TLS_ENABLED=false in that case):
|
||||
# - "127.0.0.1:3001:3001"
|
||||
environment:
|
||||
- PORT=3001
|
||||
- NODE_ENV=production
|
||||
- LOG_LEVEL=info
|
||||
# Set to 1 when running behind a reverse proxy (Nginx, Caddy, Traefik)
|
||||
# so Express trusts X-Forwarded-For and X-Forwarded-Proto headers.
|
||||
- TRUST_PROXY=1
|
||||
# --- TLS ---
|
||||
# Default: TLS enabled using bundled snakeoil cert (self-signed).
|
||||
# Supply your own cert/key by mounting them and setting these paths:
|
||||
# - TLS_CERT=/app/certs/server.crt
|
||||
# - TLS_KEY=/app/certs/server.key
|
||||
# Set TLS_ENABLED=false if terminating TLS at a reverse proxy instead.
|
||||
# If using a reverse proxy, also set TRUST_PROXY=1 below.
|
||||
# - TRUST_PROXY=1
|
||||
# --- Replace placeholders with real values or use Docker secrets ---
|
||||
- COOKIE_SECRET=change-me-generate-with-openssl-rand-hex-32
|
||||
- EMBY_URL=https://emby.example.com
|
||||
@@ -21,8 +30,11 @@ services:
|
||||
- SABNZBD_INSTANCES=[{"name":"main","url":"https://sabnzbd.example.com","apiKey":"your-sabnzbd-api-key"}]
|
||||
- QBITTORRENT_INSTANCES=[{"name":"main","url":"https://qbittorrent.example.com","username":"admin","password":"your-password"}]
|
||||
volumes:
|
||||
# Persistent volume for SQLite token store and log file
|
||||
# Persistent volume for token store and log file
|
||||
- sofarr-data:/app/data
|
||||
# Mount your own TLS certificate and key (optional — snakeoil used if omitted)
|
||||
# - /path/to/your/server.crt:/app/certs/server.crt:ro
|
||||
# - /path/to/your/server.key:/app/certs/server.key:ro
|
||||
# Run as the built-in non-root 'node' user (UID/GID 1000)
|
||||
user: "1000:1000"
|
||||
# Read-only root filesystem; only the data volume is writable
|
||||
@@ -35,7 +47,9 @@ services:
|
||||
- ALL # drop all Linux capabilities
|
||||
cap_add: [] # add back none — Node.js needs no special caps
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:3001/health"]
|
||||
# Uses --no-check-certificate for self-signed / snakeoil certs.
|
||||
# Remove that flag if using a CA-signed certificate.
|
||||
test: ["CMD", "wget", "-qO-", "--no-check-certificate", "https://localhost:3001/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
Reference in New Issue
Block a user