119 lines
4.9 KiB
Markdown
119 lines
4.9 KiB
Markdown
![]() |
# 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 <Enter>
|
|||
|
```
|
|||
|
|
|||
|
### 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.
|
|||
|
|