From 52ea52ed0794a8b436e5544dceef710bd237fdc8 Mon Sep 17 00:00:00 2001 From: Montoya Edu Date: Mon, 18 May 2026 15:07:48 +0200 Subject: [PATCH] feat: self-contained Docker build, no custom base image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `easy proxy build` required a custom base image `ethiclab/nginx-certbot:2.0` to exist first (built from a separate `Dockerfile.build`). Since that image was never on a registry, a fresh `npm install` could not build a working proxy without a manual, undocumented base-image build. Merge the two Dockerfiles into one self-contained `Dockerfile` that builds `FROM certbot/certbot:latest` — a public official image. Now `easy proxy build` is a single `docker build` from scratch, with no custom image to prepare. The `easy` CLI itself is unchanged. - Dockerfile: self-contained, FROM certbot/certbot:latest; adds nginx, Node, sudo and the certbot DNS plugins (the former Dockerfile.build content), plus ENTRYPOINT/VOLUME/EXPOSE/CMD - Dockerfile.build: removed - package.json: drop Dockerfile.build from the files allowlist - docs: CLAUDE.md, README.md, CHANGELOG.md, AGENTS.md, copilot-instructions.md, UC1_LOCAL_SSL_SETUP.md updated for the single-Dockerfile build Verified with a real `docker build`: image builds clean, all four certbot DNS plugins (ionos, route53, cloudflare, digitalocean) present. `npm run lint` exits 0; the bats suite passes 20/20. Co-Authored-By: Claude Opus 4.7 --- .github/copilot-instructions.md | 6 ++-- AGENTS.md | 18 +++++------ CHANGELOG.md | 6 ++-- CLAUDE.md | 34 ++++++++++---------- Dockerfile | 44 ++++++++++++++++++++++++-- Dockerfile.build | 56 --------------------------------- README.md | 11 +++---- UC1_LOCAL_SSL_SETUP.md | 5 ++- package.json | 1 - 9 files changed, 80 insertions(+), 101 deletions(-) delete mode 100644 Dockerfile.build diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e1571e2..0523eff 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -24,14 +24,14 @@ Versione: 2.0.0 | Stack: bash, Node.js 20, nginx 1.26, certbot, Docker Alpine. | `commands/proxy.sh` | Tutti i comandi `easy proxy *` | | `easyhome/skeleton.js` | Renderer template nginx (zero deps, Node.js) | | `easyhome/ionos-config-helper.sh` | Genera credenziali certbot-dns-ionos | -| `Dockerfile.build` | Build base image (aggiungere DNS providers qui) | +| `Dockerfile` | Build immagine `nginx-easy`, self-contained (aggiungere DNS providers qui) | ## Aggiungere un DNS provider (template) -1. `Dockerfile.build` → `pip install certbot-dns-` +1. `Dockerfile` → `pip install certbot-dns-` 2. `commands/proxy.sh` → aggiungi `if [[ "certbot-" == "$2" ]]` (copia da `certbot-ionos`) 3. `easyhome/-config-helper.sh` → crea file credenziali con `chmod 600` -4. Rebuild: `docker build -f Dockerfile.build -t ethiclab/nginx-certbot:2.0 .` +4. Rebuild: `easy proxy build` ## Test rapido (senza credenziali) diff --git a/AGENTS.md b/AGENTS.md index 01b0f97..3421fe7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,8 +29,7 @@ easy-proxy/ │ ├── add_subdomain_https # Genera vhost HTTPS │ ├── ionos-config-helper.sh # Helper credenziali IONOS │ └── easy-proxy-start # Entrypoint container -├── Dockerfile # Container easy-proxy (usa base v2.0) -├── Dockerfile.build # Build base image nginx-certbot:2.0 +├── Dockerfile # Build immagine nginx-easy, self-contained ├── CLAUDE.md # Guida per Claude Code ├── STATE.md # WIP corrente ├── UC1_LOCAL_SSL_SETUP.md # Quick start UC1 @@ -42,16 +41,15 @@ easy-proxy/ ## Stato attuale (2026-04-02) ### Già fatto ✅ -- Base image `ethiclab/nginx-certbot:2.0` costruita (Alpine + nginx 1.26 + certbot-dns-ionos + Node 20) +- Immagine `ethiclab/nginx-easy` da `Dockerfile` self-contained (`FROM certbot/certbot:latest` — nginx + certbot DNS plugins + Node 20) - `easy proxy certbot-ionos ` implementato — legge credenziali da `pass` o env vars - `skeleton.py` (Python 2) rimpiazzato da `skeleton.js` (Node.js, zero dipendenze) - Tutti i test locali passano ### Da fare 🔴 -1. **Push Docker Hub**: `docker push ethiclab/nginx-certbot:2.0` -2. **Test reale IONOS**: serve `pass insert ionos/api-key` + `pass insert ionos/api-secret` -3. **Split-view DNS** (Phase 2): dnsmasq locale per `*.dev.ethiclab.it → 127.0.0.1` -4. **Register.it support** (Phase 3): plugin certbot-dns-register-it +1. **Test reale IONOS**: serve `pass insert ionos/api-key` + `pass insert ionos/api-secret` +2. **Split-view DNS** (Phase 2): dnsmasq locale per `*.dev.ethiclab.it → 127.0.0.1` +3. **Register.it support** (Phase 3): plugin certbot-dns-register-it --- @@ -64,7 +62,7 @@ easy-proxy/ ### Aggiungere un nuovo DNS provider -1. Aggiungere plugin nel `Dockerfile.build`: +1. Aggiungere plugin nel `Dockerfile`: ```dockerfile pip install certbot-dns- ``` @@ -108,9 +106,9 @@ easy proxy destroy ## Architettura del container ``` -ethiclab/nginx-easy (FROM ethiclab/nginx-certbot:2.0) +ethiclab/nginx-easy (FROM certbot/certbot:latest) │ - ├─ nginx 1.26.3 (user: nginx, config: /usr/local/share/easy/nginx.conf) + ├─ nginx (user: nginx, config: /usr/local/share/easy/nginx.conf) │ └─ include /domains/*/*.conf ← vhost generati da skeleton.js │ ├─ certbot 5.4.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index d653339..0bde69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,8 +24,10 @@ A major release: automatic Let's Encrypt SSL with multi-DNS-provider support. fixed Docker name `easy-proxy`, queried directly from Docker, instead of a `.id` state file. A container created by `1.x` is not visible to `2.0`: remove it with `docker rm -f ` and run `easy proxy create` again ([#5]). -- **BREAKING — Docker base image.** Upgraded to `ethiclab/nginx-certbot:2.0` - (Alpine, nginx 1.26, Node 20, certbot + DNS plugins). Run `easy proxy build` +- **BREAKING — Docker image.** The container image is rebuilt from scratch on + `certbot/certbot:latest` — a single self-contained `Dockerfile` adds nginx, + Node and the certbot DNS plugins. `easy proxy build` produces it with one + `docker build`, with no custom base image required. Run `easy proxy build` to rebuild. - Template engine rewritten from Python 2 (`skeleton.py`) to a zero-dependency Node.js renderer (`skeleton.js`). diff --git a/CLAUDE.md b/CLAUDE.md index 2c2ed46..01bdbf2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,11 +43,11 @@ easy (bash entry point) ├─ reload → docker exec nginx -s reload └─ ... -CONTAINER: ethiclab/nginx-easy - └─ BASE: ethiclab/nginx-certbot:2.0 - ├─ nginx 1.26.3 +CONTAINER: ethiclab/nginx-easy (Dockerfile self-contained, un solo build) + └─ FROM certbot/certbot:latest (immagine pubblica ufficiale) + ├─ nginx (Alpine) ├─ bash, Node 20 - ├─ certbot + certbot-dns-ionos 2024.11.9 + ├─ certbot + certbot-dns-ionos ├─ certbot-dns-route53, cloudflare, digitalocean └─ ENTRYPOINT [] ← resettato (non eredita certbot entrypoint) @@ -112,12 +112,12 @@ Aggiungi queste righe a `~/.zshrc` o `~/.bashrc` per averle sempre disponibili. ### Build immagine locale -```bash -# Base image (solo se non esiste o vuoi rebuildarla) -docker build -f Dockerfile.build -t ethiclab/nginx-certbot:2.0 . +Il `Dockerfile` è self-contained (`FROM certbot/certbot:latest`): un solo build, +nessuna immagine base custom da preparare prima. -# Main image (sempre prima di easy proxy create) -docker build -t ethiclab/nginx-easy:latest . +```bash +easy proxy build # → ethiclab/nginx-easy +# oppure direttamente: docker build -t ethiclab/nginx-easy . ``` ### Avvio container @@ -254,11 +254,10 @@ easy proxy certbot-ionos dev.ethiclab.it openssl x509 -in ~/.easy-proxy/letsencrypt/live/dev.ethiclab.it/cert.pem -noout -dates ``` -### Rebuild immagini (dopo modifiche a Dockerfile.build) +### Rebuild immagine (dopo modifiche al Dockerfile) ```bash -docker build -f Dockerfile.build -t ethiclab/nginx-certbot:2.0 . -docker build -t ethiclab/nginx-easy:latest . +easy proxy build # Ricrea container easy proxy destroy easy proxy create @@ -275,8 +274,7 @@ easy proxy create | `easyhome/templates/*.conf` | Template nginx vhost | ✅ Sì | | `easyhome/nginx.conf` | Config nginx main | ⚠️ Con cautela | | `easyhome/ionos-config-helper.sh` | Helper credenziali IONOS | ✅ Sì | -| `Dockerfile` | Build nginx-easy (usa base v2.0) | ⚠️ Raro | -| `Dockerfile.build` | Build base image nginx-certbot:2.0 | ⚠️ Raro | +| `Dockerfile` | Build nginx-easy, self-contained (`FROM certbot/certbot:latest`) | ⚠️ Raro | | `easy` | CLI dispatcher bash | ⚠️ Non toccare | --- @@ -300,7 +298,6 @@ easy proxy create ### Subito (bloccante UC1) - [ ] Ottenere API key IONOS da pannello IONOS → configurare in `pass` - [ ] Eseguire `easy proxy certbot-ionos dev.ethiclab.it` (primo cert reale) -- [ ] Push `ethiclab/nginx-certbot:2.0` su Docker Hub + ghcr.io - [ ] Test UC1 end-to-end con ELEVEN locale ### Prossima sessione @@ -312,7 +309,7 @@ easy proxy create ### Futuro - [ ] `easy proxy certbot-route53` (per infra AWS) - [ ] `mini proxy [...]` wrapper in devel/bin/mini -- [ ] Docker Hub auto-build via GitHub Actions per base image +- [ ] (opz.) pubblicare `ethiclab/nginx-easy` su un registry per saltare il build locale --- @@ -323,8 +320,9 @@ Vedi `decisions.md` (da creare) per le scelte fatte. Principali: - **Bash CLI** mantenuto (non migrato a Node.js) — semplicità > ergonomia - **Zero-dependency skeleton.js** — evita yargs globale nel container -- **Alpine base** per nginx-certbot — immagine più piccola, ma richiede `user nginx;` invece di `www-data` -- **ENTRYPOINT []** resettato in base image — altrimenti CMD viene passato come arg a certbot +- **Dockerfile self-contained** (`FROM certbot/certbot:latest`) — un solo `docker build`, nessuna immagine base custom da preparare/pushare. Prima c'era un `Dockerfile.build` separato per `ethiclab/nginx-certbot:2.0`: rimosso, creava solo un problema di bootstrap senza registry +- **Alpine base** (da `certbot/certbot`) — immagine più piccola, ma richiede `user nginx;` invece di `www-data` +- **ENTRYPOINT []** resettato nel Dockerfile — altrimenti CMD viene passato come arg a certbot - **pass CLI** per credenziali — sicurezza > comodità env vars - **Container identificato per nome fisso** (`easy-proxy`), non da un file di stato `.id` — Docker è l'unica fonte di verità. Il vecchio `.id` veniva scritto nella install dir, root-owned dopo `npm install -g` → permission denied (issue #5) diff --git a/Dockerfile b/Dockerfile index 5fbc993..b7b557e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,43 @@ -FROM ethiclab/nginx-certbot:2.0 -VOLUME ["/domains", "/etc/letsencrypt", "/usr/local/share/easy"] +# Dockerfile — ethiclab/nginx-easy +# +# A self-contained image: nginx + certbot with multi-DNS provider support, +# built directly from the official certbot base. `easy proxy build` produces it +# with a single `docker build` — no pre-existing custom base image required. +# +# Build: +# easy proxy build +# # or, directly: docker build -t ethiclab/nginx-easy . + +FROM certbot/certbot:latest + +LABEL maintainer="EthicLab " +LABEL description="Nginx reverse proxy + Certbot with multi-DNS provider support (IONOS, Route53, Cloudflare, DigitalOcean, RFC2136)" +LABEL version="2.0" + +# nginx + system deps + certbot DNS provider plugins +RUN apk add --no-cache \ + nginx \ + bash \ + nodejs \ + npm \ + sudo \ + py3-pip \ + ca-certificates \ + && pip install --no-cache-dir \ + certbot-dns-ionos \ + certbot-dns-route53 \ + certbot-dns-cloudflare \ + certbot-dns-digitalocean \ + && rm -rf /var/cache/apk/* + +# Verify the install +RUN certbot plugins && nginx -v + +# Reset certbot's ENTRYPOINT so CMD runs directly +ENTRYPOINT [] + +VOLUME ["/domains", "/etc/letsencrypt", "/usr/local/share/easy", "/var/cache/certbot", "/var/www/certbot"] + +EXPOSE 80 443 + CMD ["/usr/local/share/easy/easy-proxy-start"] diff --git a/Dockerfile.build b/Dockerfile.build deleted file mode 100644 index 3446e08..0000000 --- a/Dockerfile.build +++ /dev/null @@ -1,56 +0,0 @@ -# Dockerfile.build — ethiclab/nginx-certbot:2.0 -# Based on official certbot image, adds nginx + all DNS provider plugins -# This is the base image used by easy-proxy -# -# Build: -# docker build -f Dockerfile.build -t ethiclab/nginx-certbot:2.0 . -# -# Push (requires Docker Hub credentials): -# docker push ethiclab/nginx-certbot:2.0 - -FROM certbot/certbot:latest - -LABEL maintainer="EthicLab " -LABEL description="Nginx + Certbot with multi-DNS provider support (IONOS, Route53, Cloudflare, DigitalOcean, RFC2136)" -LABEL version="2.0" - -ARG BUILD_DATE -ARG VCS_REF -LABEL org.label-schema.build-date=$BUILD_DATE \ - org.label-schema.vcs-ref=$VCS_REF - -# Install nginx + system deps + pip packages for DNS providers -RUN apk add --no-cache \ - nginx \ - bash \ - nodejs \ - npm \ - sudo \ - py3-pip \ - ca-certificates \ - && pip install --no-cache-dir \ - certbot-dns-ionos \ - certbot-dns-route53 \ - certbot-dns-cloudflare \ - certbot-dns-digitalocean \ - && rm -rf /var/cache/apk/* - -# www-data user is already in certbot base image - -# Verify plugins are installed -RUN certbot plugins - -# Verify nginx -RUN nginx -v - -# Reset certbot's ENTRYPOINT so nginx-easy can use CMD directly -ENTRYPOINT [] - -# Volume for letsencrypt persistence -VOLUME ["/etc/letsencrypt", "/var/cache/certbot", "/var/www/certbot"] - -# Listen ports (will be exposed in easy-proxy) -EXPOSE 80 443 - -# Default: run certbot (overridden in easy-proxy by easy-proxy-start) -CMD ["certbot", "--help"] diff --git a/README.md b/README.md index 335904f..c8d4af0 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,9 @@ easy proxy create # start the proxy on :80 and :443 easy proxy status # prints the container id when running ``` -> **Note — v2.0.0 is in active development.** The Docker images -> (`ethiclab/nginx-certbot:2.0`, `ethiclab/nginx-easy`) are not yet published to -> a registry, so they must be built locally. See [CLAUDE.md](CLAUDE.md) for the -> full build steps, including the base image. +> **Note — v2.0.0 is in active development.** `easy proxy build` builds the +> `ethiclab/nginx-easy` image locally from a single self-contained `Dockerfile` +> (`FROM certbot/certbot:latest`) — no custom base image and no registry needed. ## Quick start — HTTP @@ -117,8 +116,8 @@ Run `easy proxy help` for the full list. `easy-proxy` instead of a `.id` state file. A container created by `1.x` is not visible to `2.0` — remove it with `docker rm -f ` and run `easy proxy create` again. -- **Docker base image.** Upgraded to `ethiclab/nginx-certbot:2.0`. Run - `easy proxy build` to rebuild. +- **Docker image.** Rebuilt from scratch on `certbot/certbot:latest`, with nginx + and the DNS provider plugins. Run `easy proxy build` to rebuild. - **Template engine.** Rewritten from Python 2 to Node.js (internal). See **[CHANGELOG.md](CHANGELOG.md)** for the full history. diff --git a/UC1_LOCAL_SSL_SETUP.md b/UC1_LOCAL_SSL_SETUP.md index 32a144d..195f463 100644 --- a/UC1_LOCAL_SSL_SETUP.md +++ b/UC1_LOCAL_SSL_SETUP.md @@ -216,10 +216,9 @@ cd ~/ethiclab/lab/easy-proxy && npm list | head -1 # Should show "@ethiclab/easy-cli@2.0.0" ``` -**If stale**: Rebuild base image and easy-proxy +**If stale**: Rebuild the image ```bash -docker build -f Dockerfile.build -t ethiclab/nginx-certbot:2.0 . -docker build -t ethiclab/nginx-easy:dev . +easy proxy build ``` --- diff --git a/package.json b/package.json index 600dc8c..7d9773a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "commands/", "easyhome/", "Dockerfile", - "Dockerfile.build", "README.md", "CHANGELOG.md", "LICENSE"