feat: add HTTP auth and Sablier scale-to-zero to VERT stack

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 <noreply@anthropic.com>
This commit is contained in:
2025-11-06 17:22:48 +01:00
parent d986b365e2
commit 9cf0d160b4
4 changed files with 23 additions and 3 deletions

View File

@@ -256,11 +256,16 @@ VERT universal file format converter:
- No file size limits - No file size limits
- Privacy-focused: all conversions happen in the browser - Privacy-focused: all conversions happen in the browser
- No persistent data storage required - 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**: **Configuration**:
- **PUB_HOSTNAME**: `vert.pivoine.art` (for proper URL generation) - **PUB_HOSTNAME**: `vert.pivoine.art` (public hostname)
- **PUB_ENV**: `production` - **PUB_ENV**: `production` (environment mode)
- **PUB_DISABLE_ALL_EXTERNAL_REQUESTS**: `true` (privacy 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**: **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. 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.

View File

@@ -115,6 +115,7 @@ envs:
VERT_COMPOSE_PROJECT_NAME: vert VERT_COMPOSE_PROJECT_NAME: vert
VERT_IMAGE: ghcr.io/vert-sh/vert:latest VERT_IMAGE: ghcr.io/vert-sh/vert:latest
VERT_TRAEFIK_HOST: vert.pivoine.art VERT_TRAEFIK_HOST: vert.pivoine.art
VERT_SABLIER_ENABLED: true
# Proxy # Proxy
PROXY_COMPOSE_PROJECT_NAME: proxy PROXY_COMPOSE_PROJECT_NAME: proxy
PROXY_DOCKER_IMAGE: traefik:latest PROXY_DOCKER_IMAGE: traefik:latest

View File

@@ -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

View File

@@ -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.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.tls.certresolver=resolver'
- 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure' - '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.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.http.services.${VERT_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=80'
- 'traefik.docker.network=${NETWORK_NAME}' - 'traefik.docker.network=${NETWORK_NAME}'
- 'sablier.enable=${VERT_SABLIER_ENABLED}'
- 'sablier.group=${VERT_COMPOSE_PROJECT_NAME}'
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
networks: networks: