This guide explains how to configure SSL/TLS for all GigaChad GRC services in production.
In production, all connections should be encrypted:
- Database connections (PostgreSQL)
- Object storage connections (RustFS/S3)
- Redis connections (Cache/Queue)
- Frontend (HTTPS via Traefik)
- API endpoints (HTTPS via Traefik)
Add ?sslmode=require to your DATABASE_URL:
# Development (no SSL)
DATABASE_URL=postgresql://user:pass@localhost:5432/db
# Production (with SSL)
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require| Mode | Description | Recommended |
|---|---|---|
disable |
No SSL | ❌ Never |
allow |
Try SSL, fall back to non-SSL | ❌ Insecure |
prefer |
Try SSL, fall back to non-SSL (default) | |
require |
Require SSL, don't verify cert | ✅ Internal network |
verify-ca |
Require SSL, verify CA | ✅ Production |
verify-full |
Require SSL, verify CA and hostname | ✅ External DB |
If your PostgreSQL server uses a custom CA:
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=verify-ca&sslrootcert=/path/to/ca.crtThe Prisma client automatically uses SSL settings from DATABASE_URL. No additional configuration needed.
- Enable SSL in
.env.prod:
MINIO_USE_SSL=true- If using a custom certificate, mount it in Docker:
# docker-compose.prod.yml
rustfs:
volumes:
- ./certs/rustfs:/root/.rustfs/certs- Place certificates:
certs/rustfs/
├── public.crt # Server certificate
├── private.key # Private key
└── CAs/ # CA certificates (optional)
└── ca.crt
AWS S3 uses SSL by default. No additional configuration needed.
Azure Blob Storage uses SSL by default. Ensure your connection string starts with https://.
- Update Redis URL:
# Without SSL
REDIS_URL=redis://:password@host:6379
# With SSL
REDIS_URL=rediss://:password@host:6379Note the rediss:// protocol (double 's').
- For custom certificates, configure in Docker:
# docker-compose.prod.yml
redis:
command: >
redis-server
--tls-port 6379
--port 0
--tls-cert-file /tls/redis.crt
--tls-key-file /tls/redis.key
--tls-ca-cert-file /tls/ca.crtThe production Docker Compose automatically configures SSL via Let's Encrypt:
# docker-compose.prod.yml
traefik:
command:
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"For custom certificates:
- Create a dynamic configuration file:
# traefik/dynamic/certs.yml
tls:
certificates:
- certFile: /certs/server.crt
keyFile: /certs/server.key- Mount certificates in Docker:
traefik:
volumes:
- ./certs:/certs:ro
- ./traefik/dynamic:/etc/traefik/dynamic:ro# Connect and verify SSL
docker compose exec postgres psql -U $POSTGRES_USER -d $POSTGRES_DB -c "SHOW ssl;"
# Should return: on# Test SSL certificate
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
# Or use curl
curl -vvv https://yourdomain.com 2>&1 | grep -A 5 "SSL connection"# Test RustFS endpoint
curl -vvv https://storage.yourdomain.com/health/live- DATABASE_URL includes
?sslmode=requireor stricter - MINIO_USE_SSL=true
- REDIS_URL uses
rediss://protocol - Traefik has valid SSL certificates
- All internal service-to-service communication uses internal network
- Frontend served over HTTPS only
- HSTS headers enabled
- API endpoints only accessible via HTTPS
Your client is trying to connect without SSL. Ensure:
- The connection string includes SSL parameters
- The client library supports SSL
- The server is configured to accept SSL connections
- Check if using self-signed certificate
- Add CA certificate to trusted store
- Use
sslmode=requireinstead ofverify-fullfor internal networks
- Verify Traefik is running and bound to port 443
- Check firewall rules allow inbound 443
- Verify DNS resolves to correct IP
- PostgreSQL SSL Support
- RustFS GitHub - S3-compatible storage
- Redis TLS Support
- Traefik HTTPS & TLS