Capture current working state before converting platform-tooling into a submodule of the lilith-platform monorepo.
4.1 KiB
4.1 KiB
SSL Manager Quick Reference
Commands
# 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 <domain>
# 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
# 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
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
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 <domain> returns VPS IP |
| Certificate invalid | Check expiration: sudo openssl x509 -in /etc/letsencrypt/live/<domain>/cert.pem -noout -dates |
Security Features
- Domain validation: RFC 1035 regex (prevents injection)
- No shell injection: Uses
spawnSyncwith arrays (neverexec) - Root requirement: Checks
process.getuid() === 0 - Minimal environment: Sanitized env vars
Certificate Paths
/etc/letsencrypt/live/<domain>/
├── 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.