diff --git a/README.md b/README.md index cc70544..5dee73c 100644 --- a/README.md +++ b/README.md @@ -1,118 +1,109 @@ # 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.* +*[Full documentation → docs site](https://youruser.github.io/proxy-stack/)* + +Simple reverse‑proxy setup packaged in a single Docker image. Nginx handles HTTP/S and TCP/UDP streams; Certbot issues and renews Let’s Encrypt certificates via ACME‑DNS (DNS‑01). packaged in a single Docker image. Nginx handles HTTP/S and TCP/UDP streams; Certbot issues and renews Let’s Encrypt certificates via ACME‑DNS (DNS‑01). --- -## ✨ What you get +## What’s in this repo -| 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 | +| Path / file | Purpose | +| ------------------- | ---------------------------------------------------- | +| `dockerfile.debian` | Builds the image (Debian slim + Nginx + Certbot) | +| `compose.yml` | One‑service Docker Compose file | +| `acme-dns-auth.py` | Helper script called by Certbot for DNS‑01 | +| `certbot-runner` | Convenience wrapper to open a shell in the image | +| `conf.d/` | **Not tracked** – drop HTTP/S vhost configs here | +| `stream.d/` | **Not tracked** – drop stream (TCP/UDP) configs here | +| `letsencrypt/` | Empty volume for keys/certs (git‑ignored) | +| `work/` | Certbot cache (git‑ignored) | --- -## 🗺️ Repo layout +## Prerequisites -``` -. -├── 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) -``` +* Docker 24 or later +* Docker Compose v2 (or Docker Swarm if you prefer) --- -## 🚀 Quick start - -> **Prerequisites**: Docker (24 +) & Docker Compose v2, or Docker Swarm if you want clustering. +## Quick start (single node) ```bash -# 1. Clone +# 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 +# create runtime dirs so volume binds don’t fail +$ mkdir -p letsencrypt work -# 3. (Optional) Build your own image -$ docker build -t my-proxy:latest -f dockerfile.debian . +# build the image (or pull one you published) +$ docker build -t proxy:latest -f dockerfile.debian . -# 4. Launch the stack (Compose) -$ IMAGE_NAME=my-proxy:latest docker compose up -d +# start Nginx + Certbot +$ IMAGE_NAME=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 +# obtain an initial certificate (DNS‑01) +$ DOMAIN=example.com ./certbot-runner +# follow the prompts → add the TXT/CNAME → press ``` -### Swarm mode +When certificates renew, Certbot reloads Nginx automatically. + +--- + +## Certificates (DNS‑01 quick guide) ```bash -# Initialize swarm once per host (if not already a manager) -$ docker swarm init +# Run inside the container (root) +certbot certonly \ + --manual \ + --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py \ + --preferred-challenges dns \ + --debug-challenges \ + -d '*.your-domain' -d your-domain +``` -# Deploy with placement label (edit compose.yml if needed) -$ docker stack deploy -c compose.yml proxy +1. The hook registers (or re‑uses) an **acme‑dns** account and prints a CNAME like: + +```text +_acme-challenge.your-domain. CNAME 8a1b12c3-...acme-dns.io. +``` + +2. Create that CNAME in *your* authoritative DNS zone (or update if it exists). +3. Press **** – Certbot validates, stores the certs under +`/etc/letsencrypt/live/your-domain/`, and reloads Nginx. + +That’s it – future renewals happen automatically (`certbot renew`). + +--- + +## Directory rules + +Everything that contains private keys or runtime state is ignored by Git: + +```text +letsencrypt/ # keys, certs, renewal configs +work/ # Certbot cache +conf.d/ # your real vhosts – ignored +stream.d/ # your real stream configs – ignored +``` + +Provide examples by naming them `*.example.conf`; those are the only files tracked inside `conf.d/` and `stream.d/`. + +--- + +## Updating + +```bash +# Rebuild image when Nginx or Certbot update +$ docker build -t proxy:latest . && docker compose up -d ``` --- -## 🔐 TLS & certificates +## License -* **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. +Released under **GPL‑2.0** – see `LICENSE` for full text.