# Nginx + Certbot + ACME‑DNS Proxy Stack > **A batteries‑included reverse‑proxy scaffold that Just Works™ on a single node or a Docker Swarm.** > > *Old‑school Unix philosophy under the hood, modern container workflow on top.* --- ## ✨ What you get | Component | Job | | ---------------------------- | --------------------------------------------------------------------------- | | **Nginx** | Serves HTTP/S, terminates TLS, proxies upstreams, handles TCP/UDP streams | | **Certbot** | Automates Let’s Encrypt certificate issuance / renewal | | **acme‑dns‑auth.py** | ACME‑DNS helper for DNS‑01 challenges (wildcards, no public port 80 needed) | | **Docker (image & compose)** | Reproducible environment; optional Swarm placement rules | --- ## 🗺️ Repo layout ``` . ├── acme-dns-auth.py # DNS‑01 hook script (public upstream helper) ├── certbot-runner # Convenience wrapper for interactive work inside the image ├── new-domain-runner # Example one‑shot script for ad‑hoc certs ├── compose.yml # Single‑service stack definition ├── dockerfile.debian # Image build (Debian slim + Nginx + Certbot) ├── conf.d/ # Per‑vhost HTTP configs ├── stream.d/ # TCP/UDP proxy configs (PostgreSQL, MQTT, …) ├── letsencrypt/ # **Empty dir – private keys & certs live here at runtime** ├── work/ # Certbot working directory (also ignored by Git) └── lib/backups/ # Optional local backup dumps (ignored by Git) ``` --- ## 🚀 Quick start > **Prerequisites**: Docker (24 +) & Docker Compose v2, or Docker Swarm if you want clustering. ```bash # 1. Clone $ git clone https://github.com/youruser/proxy-stack.git $ cd proxy-stack # 2. Create empty state dirs so the volume binds succeed $ mkdir -p letsencrypt work lib/backups $ touch letsencrypt/.gitkeep work/.gitkeep lib/backups/.gitkeep # 3. (Optional) Build your own image $ docker build -t my-proxy:latest -f dockerfile.debian . # 4. Launch the stack (Compose) $ IMAGE_NAME=my-proxy:latest docker compose up -d # 5. Obtain the first certificate (DNS‑01) $ DOMAIN=my.example.com ./new-domain-runner # Follow the prompts → add the TXT record → hit ``` ### Swarm mode ```bash # Initialize swarm once per host (if not already a manager) $ docker swarm init # Deploy with placement label (edit compose.yml if needed) $ docker stack deploy -c compose.yml proxy ``` --- ## 🔐 TLS & certificates * **Automatic renewals** – A cron inside the container runs `certbot renew` and hot‑reloads Nginx. * **No secrets in Git** – `letsencrypt/` is `gitignored`; keys stay on disk only. * **acme‑dns** – Ideal when ports 80/443 are busy or you need wildcard certs. Change `ACMEDNS_URL` via env var if you self‑host acme‑dns. --- ## ⚙️ Configuration knobs | Variable | Default | Purpose | | --------------- | ------------------------------- | -------------------------------------------------------- | | `IMAGE_NAME` | `ghcr.io/youruser/proxy:latest` | Override in scripts / compose to point at your own build | | `ACMEDNS_URL` | `https://auth.acme-dns.io` | Where `acme-dns-auth.py` registers & updates records | | `CERTBOT_EMAIL` | – | Address Certbot uses for expiry mails | | Swarm label | `node.labels.server_id==lnd1` | Example placement constraint – comment or change | Edit `conf.d/*.conf` and `stream.d/*.conf` to define your virtual hosts and upstreams. --- ## 🛠️ Maintenance | Task | Old‑school command | Modern alternative | | ---------------------------------------- | ---------------------------------------- | --------------------------------------------- | | Rebuild image after Nginx or OpenSSL CVE | `docker build -t my-proxy .` | GitHub Actions → `docker buildx build --push` | | List certs expiring in ≤30 days | `docker exec proxy certbot certificates` | Prometheus + exporter | | Tail logs | `docker compose logs -f proxy` | Grafana Loki | --- ## 🤝 Contributing Patches and issues are welcome – just follow the **kernel‑style rule**: *one patch, one purpose.* 1. Fork → branch → commit (signed‑off) 2. Make sure `pre-commit run --all` passes (gitleaks, shellcheck, etc.) 3. Open a PR. --- ## 📜 License This project is released under the **GNU General Public License v2.0** – see [`LICENSE`](LICENSE) for details.