Automatisierte Zertifikatserstellung

Reverse Proxy & SSL Automation Documentation

Target System: RHEL (edge.example.com)
Container Engine: Podman
SSL Provider: Let’s Encrypt

1. Environment Architecture

The system uses a Native Certbot installation on the RHEL host to manage certificates and a Podman Container to serve the Nginx reverse proxy.

  • Host Path: /etc/letsencrypt (Certificates)
  • Webroot Path: /var/www/letsencrypt (ACME Challenges)
  • Container Name: reverse-proxy
  • Image: quay.io/mshn/reverseproxy:latest

2. Infrastructure Prerequisites

Network & Firewall

Inbound traffic on Port 80 and 443 must be allowed through the RHEL firewall and forwarded from the external router to this host’s IP (85.195.230.53).

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Host Permissions & SELinux

Certbot directories are restricted by default. These commands allow the containerized Nginx process to traverse the directory tree and read the certificate files.

# Set directory traversal permissions
sudo chmod 755 /etc/letsencrypt /etc/letsencrypt/live /etc/letsencrypt/archive
sudo chmod 755 /etc/letsencrypt/live/mkdir-bundle /etc/letsencrypt/archive/mkdir-bundle

# Set file read permissions
sudo chmod 644 /etc/letsencrypt/archive/mkdir-bundle/*.pem

# Ensure challenge directory exists
sudo mkdir -p /var/www/letsencrypt
sudo chmod 755 /var/www/letsencrypt

# Apply SELinux labels for Podman volume access
sudo chcon -Rt svirt_sandbox_file_t /etc/letsencrypt
sudo chcon -Rt svirt_sandbox_file_t /var/www/letsencrypt

3. Nginx Configuration (nginx.conf)

The configuration must handle the .well-known/acme-challenge/ path locally to allow Certbot to verify domain ownership without interfering with proxied traffic.

# Example Server Block for Port 80 (Redirect & Challenge)
server {
    listen 80;
    server_name timeline.example.com immich.example.com www.goboi.ch trading.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# Example Server Block for Port 443 (SSL & Proxy)
server {
    listen 443 ssl;
    server_name immich.example.com;

    ssl_certificate     /etc/letsencrypt/live/mkdir-bundle/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mkdir-bundle/privkey.pem;

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        proxy_pass https://router-default.apps.mnp.example.com;
        # ... proxy headers ...
    }
}

4. Automation & Services

Systemd Container Service

Path: /etc/systemd/system/container-reverse-proxy.service

[Unit]
Description=Podman Nginx Reverse Proxy Container (Auto-Pull)
After=network-online.target
Wants=network-online.target

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
TimeoutStopSec=70

ExecStart=/usr/bin/podman run \
    --name reverse-proxy \
    --rm \
    --replace \
    --pull=always \
    -v /etc/letsencrypt:/etc/letsencrypt:Z \
    -v /var/www/letsencrypt:/var/www/letsencrypt:Z \
    -v /var/log/nginx:/var/log/nginx:Z \
    -p 80:80 -p 443:443 \
    quay.io/mshn/reverseproxy:latest

ExecStop=/usr/bin/podman stop -t 10 reverse-proxy
ExecStopPost=/usr/bin/podman rm -f reverse-proxy
Type=simple

[Install]
WantedBy=multi-user.target

Certbot Renewal Timer

The systemd timer handles automated renewal checks twice daily.

# Enable the timer
sudo systemctl enable --now certbot-renew.timer

5. Maintenance Commands

TaskCommand
Apply Nginx Config ChangesRebuild/Push Image then: sudo systemctl restart container-reverse-proxy
Dry-Run Renewalsudo certbot renew --dry-run
Check Active Timerssystemctl list-timers
View Container Logspodman logs -f reverse-proxy
Update Cert DomainsRun certbot certonly --webroot ... (with -d flags)

Troubleshooting

If the container fails to start with “Permission Denied” errors:

  1. Re-run the chmod commands in Section 2.
  2. Ensure the SELinux labels (chcon) are applied to the /etc/letsencrypt folder.
  3. Check the container logs using journalctl -u container-reverse-proxy -f.