SSL/HTTPS Configuration
This guide explains how to enable HTTPS with Let’s Encrypt certificates for the University Inventory Management System using Nginx reverse proxy.
Overview
The HTTPS implementation provides:
SSL/TLS Termination: Nginx handles all certificate management
Automatic Certificate Renewal: Let’s Encrypt certificates auto-renew
Security Headers: Modern security practices with HSTS, CSP, etc.
Performance: HTTP/2, compression, and caching
Zero Downtime: No application code changes required
Architecture
Internet → Nginx (SSL Termination) → Express App (HTTP:5000)
↓
Let's Encrypt Certificates (Auto-renewal)
Components: - Nginx: Handles SSL certificates, HTTPS termination, security headers, rate limiting - Express App: Continues to run on HTTP internally (port 5000) - Let’s Encrypt: Provides free SSL certificates with automatic renewal - Certbot: Manages certificate lifecycle
Quick Start
The system supports three types of SSL certificates:
Let’s Encrypt: For public domains with automatic renewal
Self-signed: For development and internal testing
University-issued: For internal university domains requiring institutional certificates
Choose the appropriate method based on your deployment environment.
Local Development
For local development with self-signed certificates:
# Setup with self-signed certificates
make ssl-dev
# Or manually:
./scripts/setup-ssl.sh localhost.dev
docker-compose -f docker-compose.yml -f docker-compose.ssl.yml up -d
# Access at: https://localhost.dev
Production Deployment
For public domains with Let’s Encrypt:
# Set your domain and email
export DOMAIN="inventory.university.edu"
export EMAIL="admin@university.edu"
# Automated setup
make ssl-setup DOMAIN=$DOMAIN EMAIL=$EMAIL
# Start production services
make ssl-prod
# Or manually:
./scripts/setup-ssl.sh $DOMAIN $EMAIL
source .env.ssl
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
For internal university domains:
For domains like py-stores.lancaster.ac.uk, use university-issued certificates. See the University Certificate Authority section for the complete process.
# After obtaining university certificates
# Place certificates in ssl/university/ directory
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Staging Environment
For testing with Let’s Encrypt staging environment:
# Use staging certificates (higher rate limits)
export CERTBOT_STAGING=--staging
./scripts/setup-ssl.sh staging.inventory.university.edu admin@university.edu
# Start services
docker-compose -f docker-compose.yml -f docker-compose.ssl.yml up -d
Manual Setup
Prerequisites
Domain Configuration: Point your domain’s DNS A record to your server’s IP
Firewall: Ensure ports 80 and 443 are open
Docker: Docker and docker-compose installed
Server Access: Root or sudo access for certificate management
Step-by-Step Installation
Initial HTTP Setup
# Copy HTTP-only nginx config for initial setup cp nginx/nginx-http-only.conf nginx/nginx.conf # Start services without SSL first docker-compose up -d app db nginx # Verify app is accessible curl http://yourdomain.edu/health
Create SSL Directories
mkdir -p certbot/conf certbot/www logs/nginx logs/certbot
Obtain SSL Certificates
# Get Let's Encrypt certificates docker-compose run --rm certbot certonly \ --webroot \ --webroot-path=/var/www/certbot \ --email admin@university.edu \ --agree-tos \ --no-eff-email \ -d inventory.university.edu
Configure HTTPS
# Update nginx configuration with your domain sed "s/DOMAIN_PLACEHOLDER/inventory.university.edu/g" \ nginx/nginx.conf > nginx/nginx.conf.tmp mv nginx/nginx.conf.tmp nginx/nginx.conf # Restart nginx with HTTPS configuration docker-compose restart nginx
Enable Auto-Renewal
# Start certbot service for automatic renewal docker-compose -f docker-compose.yml -f docker-compose.ssl.yml up -d
Configuration Files
Docker Compose Configuration
The SSL setup uses multiple Docker Compose files:
- docker-compose.ssl.yml
SSL-enabled services for development/staging
- docker-compose.prod.yml
Production configuration with SSL and monitoring
Services added:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot:ro
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Nginx Configuration
The Nginx configuration includes:
SSL/TLS Security: - TLS 1.2 and 1.3 protocols only - Strong cipher suites with Perfect Forward Secrecy - OCSP stapling for certificate validation - SSL session caching
Security Headers:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; ..." always;
Performance Features: - HTTP/2 support - Gzip compression (70% bandwidth reduction) - Static file caching (1-year expires) - Keep-alive connections
Rate Limiting: - API endpoints: 10 requests/second (20 burst) - Authentication: 5 requests/minute (5 burst)
Environment Variables
The setup creates environment variables:
# SSL Configuration
HTTPS=true # Enable HTTPS mode in Express
FORCE_HTTPS=true # Force HTTPS redirects
DOMAIN=inventory.university.edu # Your domain name
EMAIL=admin@university.edu # Let's Encrypt contact email
Application Integration
The Express application automatically adapts to HTTPS with these settings:
// Session cookies become secure in production
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production' &&
(process.env.FORCE_HTTPS === 'true' || process.env.HTTPS === 'true'),
sameSite: process.env.NODE_ENV === 'production' ? 'strict' : 'lax',
}
Management Commands
Makefile Commands
The included Makefile provides convenient SSL management:
# Setup SSL for specific domain
make ssl-setup DOMAIN=inventory.university.edu EMAIL=admin@university.edu
# Local development setup
make ssl-dev
# Start production with SSL
make ssl-prod
# Manually renew certificates
make ssl-renew
# Test SSL configuration
make ssl-test
# Clean SSL certificates
make ssl-clean
# View logs
make logs
Manual Certificate Management
Certificate Renewal:
# Manual renewal
docker-compose exec certbot certbot renew
# Test renewal (dry run)
docker-compose exec certbot certbot renew --dry-run
# Reload nginx after renewal
docker-compose reload nginx
Certificate Verification:
# Check certificate files
ls -la certbot/conf/live/inventory.university.edu/
# Verify certificate chain
openssl verify -CApath /etc/ssl/certs/ \
certbot/conf/live/inventory.university.edu/fullchain.pem
# Test SSL connection
openssl s_client -connect inventory.university.edu:443 -servername inventory.university.edu
Monitoring and Maintenance
Health Checks
The system includes comprehensive health monitoring:
Nginx Health Check:
# Test nginx configuration
docker-compose exec nginx nginx -t
# Check nginx status
curl -I https://inventory.university.edu/health
SSL Certificate Monitoring:
# Check certificate expiration
echo | openssl s_client -servername inventory.university.edu \
-connect inventory.university.edu:443 2>/dev/null | \
openssl x509 -noout -dates
# SSL Labs test (external validation)
# Visit: https://www.ssllabs.com/ssltest/
Log Management
Logs are stored in organized directories:
logs/
├── nginx/
│ ├── access.log # HTTP access logs
│ └── error.log # Nginx error logs
├── certbot/ # Certificate management logs
└── app/ # Application logs
Log Commands:
# View recent nginx logs
docker-compose logs nginx | tail -50
# Monitor access logs in real-time
docker-compose exec nginx tail -f /var/log/nginx/access.log
# Check for SSL errors
docker-compose exec nginx grep -i ssl /var/log/nginx/error.log
Performance Monitoring
Expected performance improvements with HTTPS:
SSL/TLS: Modern TLS 1.3 for faster handshakes
HTTP/2: Request multiplexing and server push
Compression: ~70% bandwidth reduction via Gzip
Caching: Static assets cached for 1 year
Keep-Alive: Persistent connections reduce overhead
Security Features
SSL/TLS Configuration
Protocol Security: - TLS 1.2 and 1.3 only (older versions disabled) - Perfect Forward Secrecy (PFS) cipher suites - Strong key exchange algorithms - No weak or legacy ciphers
Certificate Security: - OCSP stapling for real-time certificate validation - Certificate chain verification - Automatic renewal before expiration - Secure private key storage
HTTP Security Headers
Strict Transport Security (HSTS):
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
Forces HTTPS for 2 years, includes subdomains, eligible for browser preload lists.
Content Security Policy (CSP):
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; object-src 'none'; frame-ancestors 'none';" always;
Prevents XSS attacks by controlling resource loading.
Additional Headers: - X-Frame-Options: Prevents clickjacking - X-Content-Type-Options: Prevents MIME sniffing - X-XSS-Protection: Enables browser XSS filter - Referrer-Policy: Controls referrer information
Rate Limiting
Protection against abuse and DoS attacks:
# API endpoint protection
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# Authentication endpoint protection
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
Troubleshooting
Common Issues
1. Certificate Not Found
# Symptoms: Nginx fails to start, SSL errors
# Check certificate files exist
ls -la certbot/conf/live/yourdomain.edu/
# Verify nginx configuration
docker-compose exec nginx nginx -t
# Re-obtain certificates if missing
./scripts/setup-ssl.sh yourdomain.edu admin@yourdomain.edu
2. Domain Validation Failed
# Symptoms: Let's Encrypt cannot validate domain
# Check DNS resolution
nslookup inventory.university.edu
# Verify port 80 accessibility
curl http://inventory.university.edu/.well-known/acme-challenge/test
# Check firewall settings
sudo ufw status
sudo iptables -L
3. SSL Handshake Errors
# Test SSL configuration
openssl s_client -connect inventory.university.edu:443
# Check certificate chain
openssl verify -CApath /etc/ssl/certs/ \
certbot/conf/live/inventory.university.edu/fullchain.pem
# Verify nginx SSL config
docker-compose exec nginx nginx -T | grep ssl
4. Mixed Content Warnings
# Symptoms: Browser shows "not secure" despite HTTPS
# Check for HTTP resources in HTTPS pages
# Update application to use HTTPS URLs
# Verify CSP headers allow HTTPS resources only
5. Certificate Renewal Failures
# Check certbot logs
docker-compose logs certbot
# Test renewal manually
docker-compose exec certbot certbot renew --dry-run
# Verify webroot permissions
ls -la certbot/www/
Recovery Procedures
Emergency HTTP Fallback:
# Switch to HTTP-only if SSL fails
cp nginx/nginx-http-only.conf nginx/nginx.conf
docker-compose restart nginx
# Re-setup SSL when ready
./scripts/setup-ssl.sh yourdomain.edu admin@yourdomain.edu
Certificate Reset:
# Complete SSL cleanup and restart
make ssl-clean
rm -rf certbot/conf/* certbot/www/*
./scripts/setup-ssl.sh yourdomain.edu admin@yourdomain.edu
Configuration Rollback:
# Restore from backup
git checkout nginx/nginx.conf
docker-compose restart nginx
Advanced Configuration
Load Balancer Integration
For deployment behind a load balancer (AWS ALB, Google Cloud Load Balancer):
Configure SSL at the load balancer level
Use HTTP-only nginx configuration
Set environment variables:
FORCE_HTTPS=false # Avoid double redirects TRUST_PROXY=true # Trust load balancer headers
Update nginx configuration:
# Remove SSL configuration, keep proxy settings real_ip_header X-Forwarded-For; set_real_ip_from 0.0.0.0/0; # Trust load balancer
Multi-Domain Setup
For multiple domains or subdomains:
# Obtain certificates for multiple domains
docker-compose run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
--email admin@university.edu \
--agree-tos \
-d inventory.university.edu \
-d staging.inventory.university.edu \
-d api.inventory.university.edu
Custom SSL Certificates
For custom or commercial SSL certificates:
Place certificate files:
mkdir -p ssl/custom/ cp your-cert.pem ssl/custom/fullchain.pem cp your-private-key.pem ssl/custom/privkey.pem
Update nginx configuration:
ssl_certificate /etc/ssl/custom/fullchain.pem; ssl_certificate_key /etc/ssl/custom/privkey.pem;
Mount in docker-compose:
nginx: volumes: - ./ssl/custom:/etc/ssl/custom:ro
Production Checklist
Pre-Deployment
[ ] Domain DNS configured (A record points to server)
[ ] Firewall configured (ports 80, 443 open)
[ ] Server resources adequate (CPU, memory, disk)
[ ] Backup strategy in place
[ ] Monitoring systems configured
SSL Setup
[ ] SSL certificates obtained successfully
[ ] Nginx configuration tested (nginx -t)
[ ] HTTPS redirect working
[ ] Security headers present
[ ] SSL Labs test passes (A+ rating)
Post-Deployment
[ ] Application accessible via HTTPS
[ ] All features working correctly
[ ] Performance benchmarks met
[ ] Certificate auto-renewal configured
[ ] Monitoring alerts configured
[ ] Documentation updated
Security Validation
[ ] SSL/TLS configuration secure (no weak ciphers)
[ ] HTTP Strict Transport Security enabled
[ ] Content Security Policy configured
[ ] Rate limiting functional
[ ] No mixed content warnings
[ ] Penetration testing completed
Best Practices
Certificate Management
Regular Monitoring: Set up alerts for certificate expiration
Backup Certificates: Keep secure backups of private keys
Test Renewals: Regular dry-run testing of certificate renewal
Multiple Certificates: Use different certificates for different environments
Security Maintenance
Regular Updates: Keep Nginx, OpenSSL, and base images updated
Security Headers: Review and update security headers regularly
Cipher Suites: Update cipher suites as security standards evolve
Penetration Testing: Regular security assessments
Performance Optimization
HTTP/2: Ensure HTTP/2 is enabled and working
Compression: Monitor compression ratios and adjust
Caching: Review cache headers and performance
Connection Pooling: Optimize upstream connections
Conclusion
The SSL/HTTPS implementation provides enterprise-grade security for the University Inventory Management System with:
Zero-downtime deployment with no application code changes
Automatic certificate management via Let’s Encrypt
Industry-standard security with modern TLS and security headers
High performance with HTTP/2, compression, and caching
Comprehensive monitoring and alerting
The solution is designed for easy maintenance and scales from development through production environments.
For additional support, refer to:
Production Deployment - Production deployment guide
Security - Security best practices
Monitoring - System monitoring and alerting