From 9cf0d160b4d97d579466d0188f6e051b12621242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Thu, 6 Nov 2025 17:22:48 +0100 Subject: [PATCH] feat: add HTTP auth and Sablier scale-to-zero to VERT stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added authentication and scale-to-zero capabilities to VERT file converter service: **Authentication**: - Added HTTP Basic Auth middleware using VERT_AUTH_USERS - Auth middleware applied to web-secure router - Credentials configured via .env file (htpasswd format) **Sablier Scale-to-Zero**: - Added sablier.enable and sablier.group labels - Created proxy/dynamic/vert-sablier.yaml with Sablier middleware config - 1-hour session duration before automatic scale-down - Ghost theme with custom display name - Middleware chain: sablier-vert@file → auth → compress **Configuration Updates**: - Added VERT_SABLIER_ENABLED to arty.yml (default: true) - Updated CLAUDE.md with auth and Sablier documentation - Middleware order ensures Sablier wakes container before auth check Infrastructure: - Follows same pattern as Scrapy service for auth - Dynamic Traefik configuration for Sablier plugin - Container name: vert_app (referenced in Sablier config) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- CLAUDE.md | 9 +++++++-- arty.yml | 1 + proxy/dynamic/vert-sablier.yaml | 11 +++++++++++ vert/compose.yaml | 5 ++++- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 proxy/dynamic/vert-sablier.yaml diff --git a/CLAUDE.md b/CLAUDE.md index 51fd4e6..3e0bd5b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -256,11 +256,16 @@ VERT universal file format converter: - No file size limits - Privacy-focused: all conversions happen in the browser - No persistent data storage required + - Protected by HTTP Basic Auth (credentials in `.env`) + - Scale-to-zero enabled via Sablier (configurable via `VERT_SABLIER_ENABLED`) + - 1-hour session duration before automatic scale-down **Configuration**: -- **PUB_HOSTNAME**: `vert.pivoine.art` (for proper URL generation) -- **PUB_ENV**: `production` +- **PUB_HOSTNAME**: `vert.pivoine.art` (public hostname) +- **PUB_ENV**: `production` (environment mode) - **PUB_DISABLE_ALL_EXTERNAL_REQUESTS**: `true` (privacy mode) +- **VERT_SABLIER_ENABLED**: `true` (enable scale-to-zero) +- **VERT_AUTH_USERS**: HTTP Basic Auth credentials (htpasswd format in `.env`) **Usage**: Simply access https://vert.pivoine.art and drag/drop files to convert between formats. All processing happens in your browser using WebAssembly - no data is uploaded to the server. diff --git a/arty.yml b/arty.yml index 4684f8c..af2a9a1 100644 --- a/arty.yml +++ b/arty.yml @@ -115,6 +115,7 @@ envs: VERT_COMPOSE_PROJECT_NAME: vert VERT_IMAGE: ghcr.io/vert-sh/vert:latest VERT_TRAEFIK_HOST: vert.pivoine.art + VERT_SABLIER_ENABLED: true # Proxy PROXY_COMPOSE_PROJECT_NAME: proxy PROXY_DOCKER_IMAGE: traefik:latest diff --git a/proxy/dynamic/vert-sablier.yaml b/proxy/dynamic/vert-sablier.yaml new file mode 100644 index 0000000..170ea72 --- /dev/null +++ b/proxy/dynamic/vert-sablier.yaml @@ -0,0 +1,11 @@ +http: + middlewares: + sablier-vert: + plugin: + sablier: + names: vert_app + sablierUrl: http://sablier_app:10000 + sessionDuration: 1h + dynamic: + displayName: VERT File Converter + theme: ghost diff --git a/vert/compose.yaml b/vert/compose.yaml index 5d879da..16de1b8 100644 --- a/vert/compose.yaml +++ b/vert/compose.yaml @@ -18,10 +18,13 @@ services: - 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${VERT_TRAEFIK_HOST}`)' - 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver' - 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure' + - 'traefik.http.middlewares.${VERT_COMPOSE_PROJECT_NAME}-auth.basicauth.users=${VERT_AUTH_USERS}' - 'traefik.http.middlewares.${VERT_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true' - - 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${VERT_COMPOSE_PROJECT_NAME}-web-secure-compress' + - 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.middlewares=sablier-vert@file,${VERT_COMPOSE_PROJECT_NAME}-auth,${VERT_COMPOSE_PROJECT_NAME}-web-secure-compress' - 'traefik.http.services.${VERT_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=80' - 'traefik.docker.network=${NETWORK_NAME}' + - 'sablier.enable=${VERT_SABLIER_ENABLED}' + - 'sablier.group=${VERT_COMPOSE_PROJECT_NAME}' - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' networks: