# SSL Manager Quick Reference ## Commands ```bash # Check certificate status sudo pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts check # Request new certificate sudo pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts request # Renew expiring certificates sudo pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts renew # Validate all certificates sudo pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts validate ``` ## Initial Setup ```bash # 1. Install certbot sudo apt install certbot # Debian/Ubuntu sudo dnf install certbot # Fedora # 2. Create webroot sudo mkdir -p /var/www/certbot sudo chown -R lilith:lilith /var/www/certbot # 3. Configure nginx for ACME challenge (add to port 80 server block) location /.well-known/acme-challenge/ { root /var/www/certbot; try_files $uri =404; } # 4. Request certificates for all domains for domain in atlilith.com sso.atlilith.com admin.atlilith.com trustedmeet.com seo.atlilith.com analytics.atlilith.com profile.atlilith.com status.atlilith.com; do sudo pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts request $domain done # 5. Setup auto-renewal (cron) sudo crontab -e # Add: 0 3 * * * cd /var/www/lilith && pnpm tsx infrastructure/scripts/orchestration/ssl-manager.ts renew 30 3 * * * systemctl reload nginx ``` ## API Functions ```typescript import { checkCertificates, requestCertificate, renewCertificates, getCertificatePath, validateCertificates, } from './ssl-manager.js'; // Get paths for nginx config const paths = getCertificatePath('atlilith.com'); // paths.fullchainPath = /etc/letsencrypt/live/atlilith.com/fullchain.pem // paths.keyPath = /etc/letsencrypt/live/atlilith.com/privkey.pem // Pre-deployment validation const validation = await validateCertificates(); if (!validation.valid) { throw new Error(`Certificate validation failed: ${validation.errors.join(', ')}`); } // Check expiration const statuses = await checkCertificates(); for (const status of statuses) { if (status.daysUntilExpiry && status.daysUntilExpiry <= 7) { console.warn(`Certificate ${status.domain} expires in ${status.daysUntilExpiry} days`); } } ``` ## Nginx Configuration ```nginx server { listen 443 ssl http2; server_name atlilith.com www.atlilith.com; # SSL certificates ssl_certificate /etc/letsencrypt/live/atlilith.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/atlilith.com/privkey.pem; include snippets/ssl-params.conf; # ... } server { listen 80; server_name atlilith.com www.atlilith.com; # ACME challenge location /.well-known/acme-challenge/ { root /var/www/certbot; try_files $uri =404; } # Redirect to HTTPS location / { return 301 https://$server_name$request_uri; } } ``` ## Managed Domains | Domain | Aliases | Port | |--------|---------|------| | atlilith.com | www.atlilith.com | 3010 | | sso.atlilith.com | - | 4001 | | admin.atlilith.com | - | 3011 | | trustedmeet.com | www.trustedmeet.com | 3001 | | seo.atlilith.com | - | 3014 | | analytics.atlilith.com | - | 3012 | | profile.atlilith.com | - | 3110 | | status.atlilith.com | - | 5000 | ## Troubleshooting | Issue | Solution | |-------|----------| | certbot not found | `sudo apt install certbot` | | Permission denied | Run with `sudo` | | Port 80 not accessible | Check firewall: `sudo ufw allow 80/tcp` | | DNS not configured | Verify: `dig +short ` returns VPS IP | | Certificate invalid | Check expiration: `sudo openssl x509 -in /etc/letsencrypt/live//cert.pem -noout -dates` | ## Security Features - Domain validation: RFC 1035 regex (prevents injection) - No shell injection: Uses `spawnSync` with arrays (never `exec`) - Root requirement: Checks `process.getuid() === 0` - Minimal environment: Sanitized env vars ## Certificate Paths ``` /etc/letsencrypt/live// ├── cert.pem (certificate only - DO NOT USE) ├── chain.pem (intermediate CA - DO NOT USE alone) ├── fullchain.pem (cert + chain - USE THIS in nginx) └── privkey.pem (private key - USE THIS in nginx) ``` Always use `fullchain.pem` + `privkey.pem` in nginx configuration.