platform-tooling/scripts/security/SSL_CERTIFICATES.md
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

4.5 KiB

SSL Certificate Management

Overview

We use Let's Encrypt certificates with DNS-01 validation via PowerDNS.

This approach works for:

  • VPN-only domains (no HTTP access from internet)
  • Wildcard certificates
  • Multi-domain SAN certificates

Architecture

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   acme.sh       │────▶│   PowerDNS API  │────▶│   Let's Encrypt │
│   (on host)     │     │   (ns1/ns2)     │     │   (ACME)        │
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │
        ▼
┌─────────────────┐
│   nginx ssl/    │
│   (certs)       │
└─────────────────┘

Quick Reference

Issue Certificate

# From lilith-platform/infrastructure directory
./scripts/security/issue-letsencrypt-cert.sh <host> <cert-name> <domain1> [domain2] ...

Examples

# Staging: atlilith.com domains on black
./scripts/security/issue-letsencrypt-cert.sh black next.atlilith.com \
    next.atlilith.com next.status.atlilith.com next.www.atlilith.com

# Staging: trustedmeet.com domains on black
./scripts/security/issue-letsencrypt-cert.sh black next.trustedmeet.com \
    next.trustedmeet.com next.www.trustedmeet.com

# Production: atlilith.com domains on 0
./scripts/security/issue-letsencrypt-cert.sh 0 atlilith.com \
    atlilith.com www.atlilith.com status.atlilith.com api.atlilith.com

# Production: trustedmeet.com domains on 0
./scripts/security/issue-letsencrypt-cert.sh 0 trustedmeet.com \
    trustedmeet.com www.trustedmeet.com

Current Certificates

black (Staging)

Certificate Domains Nginx Config
next.atlilith.com next.atlilith.com, next.www.atlilith.com, next.status.atlilith.com /bigdisk/forgejo/ssl/next.atlilith.com.{crt,key}

0 (Production)

Certificate Domains Nginx Config
atlilith.com (to be issued) /etc/nginx/ssl/atlilith.com.{crt,key}

Certificate Locations

Host SSL Directory Reload Command
black /bigdisk/forgejo/ssl/ docker exec forgejo-nginx nginx -s reload
0 /etc/nginx/ssl/ systemctl reload nginx

Renewal

acme.sh automatically configures a cron job for renewal. Certificates renew ~30 days before expiry.

Check renewal status:

ssh black "~/.acme.sh/acme.sh --list"
ssh 0 "~/.acme.sh/acme.sh --list"

Force renewal:

ssh black "~/.acme.sh/acme.sh --renew -d next.atlilith.com --force"

Prerequisites

First-time Setup (per host)

# SSH to target host
ssh black  # or ssh 0

# Install acme.sh
curl https://get.acme.sh | sh -s email=admin@atlilith.com
source ~/.bashrc

PowerDNS API Access

The script reads PowerDNS API credentials from:

vault/dns-servers-powerdns.txt

PowerDNS API must be accessible from the target host via VPN (10.0.0.11:8081).

Nginx Configuration

After issuing a certificate, update nginx config:

server {
    listen 443 ssl;
    server_name example.atlilith.com;

    ssl_certificate /path/to/ssl/cert-name.crt;
    ssl_certificate_key /path/to/ssl/cert-name.key;

    # Modern SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # ... rest of config
}

Troubleshooting

DNS propagation issues

# Check if TXT record was created
dig +short TXT _acme-challenge.example.atlilith.com @ns1.nasty.sh

PowerDNS API connectivity

# Test API from target host
ssh black "curl -H 'X-API-Key: <key>' http://10.0.0.11:8081/api/v1/servers"

Certificate verification

# Check certificate details
ssh black "openssl x509 -in /bigdisk/forgejo/ssl/next.atlilith.com.crt -noout -text"

# Check expiry
ssh black "openssl x509 -in /bigdisk/forgejo/ssl/next.atlilith.com.crt -noout -enddate"
  • infrastructure/docker/forgejo/nginx.conf - Nginx config for black (Docker)
  • infrastructure/nginx/ - Nginx configs for production
  • vault/dns-servers-powerdns.txt - PowerDNS API credentials