feat: add VERT file converter stack

Added VERT universal file format converter deployed at vert.pivoine.art:

**Vert stack** (vert.pivoine.art):
- vert: WebAssembly-based file converter
  - Supports 250+ file formats (images, audio, documents, video)
  - Client-side processing for privacy
  - No file size limits
  - No persistent data storage (stateless)

Infrastructure updates:
- Created vert/compose.yaml with Vert configuration
- Added VERT_* environment variables to arty.yml
- Updated compose.yaml to include vert stack
- Updated README.md and CLAUDE.md documentation
- No backup needed (stateless service)

All services integrated with Traefik for SSL termination and include
Watchtower auto-update labels.

🤖 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:09:52 +01:00
parent a59c6bb2af
commit d986b365e2
5 changed files with 58 additions and 0 deletions

View File

@@ -22,6 +22,7 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul
- **links**: Linkwarden bookmark manager (PostgreSQL + Meilisearch) - **links**: Linkwarden bookmark manager (PostgreSQL + Meilisearch)
- **vault**: Vaultwarden password manager (SQLite) - **vault**: Vaultwarden password manager (SQLite)
- **joplin**: Joplin Server note-taking and sync platform (PostgreSQL) - **joplin**: Joplin Server note-taking and sync platform (PostgreSQL)
- **vert**: VERT file format converter (WebAssembly-based, stateless)
- **restic**: Backrest backup system with restic backend - **restic**: Backrest backup system with restic backend
- **sablier**: Dynamic scaling plugin for Traefik - **sablier**: Dynamic scaling plugin for Traefik
- **vpn**: WireGuard VPN (wg-easy) - **vpn**: WireGuard VPN (wg-easy)
@@ -247,6 +248,25 @@ Joplin Server note-taking and synchronization platform:
4. Enter server URL: `https://joplin.pivoine.art` 4. Enter server URL: `https://joplin.pivoine.art`
5. Enter email and password created in step 1 5. Enter email and password created in step 1
### Vert (vert/compose.yaml)
VERT universal file format converter:
- **vert**: VERT app exposed at `vert.pivoine.art:80`
- WebAssembly-based file conversion (client-side processing)
- Supports 250+ file formats (images, audio, documents, video)
- No file size limits
- Privacy-focused: all conversions happen in the browser
- No persistent data storage required
**Configuration**:
- **PUB_HOSTNAME**: `vert.pivoine.art` (for proper URL generation)
- **PUB_ENV**: `production`
- **PUB_DISABLE_ALL_EXTERNAL_REQUESTS**: `true` (privacy mode)
**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.
**Note**: VERT is stateless and doesn't require backups as no data is persisted.
### Restic (restic/compose.yaml) ### Restic (restic/compose.yaml)
Backrest backup system with restic backend: Backrest backup system with restic backend:
- **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898` - **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898`

View File

@@ -54,6 +54,7 @@ The **Falcon** is a state-of-the-art containerized starship, powered by Docker's
| **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) | | **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) |
| **VAULT** | *Encrypted password vault* | [vault.pivoine.art](https://vault.pivoine.art) | | **VAULT** | *Encrypted password vault* | [vault.pivoine.art](https://vault.pivoine.art) |
| **JOPLIN** | *Note-taking server & sync hub* | [joplin.pivoine.art](https://joplin.pivoine.art) | | **JOPLIN** | *Note-taking server & sync hub* | [joplin.pivoine.art](https://joplin.pivoine.art) |
| **VERT** | *Universal file format converter* | [vert.pivoine.art](https://vert.pivoine.art) |
| **RESTIC** | *Automated backup vault system* | [restic.pivoine.art](https://restic.pivoine.art) | | **RESTIC** | *Automated backup vault system* | [restic.pivoine.art](https://restic.pivoine.art) |
| **PROXY** | *Shield control dashboard* | [proxy.pivoine.art](https://proxy.pivoine.art) | | **PROXY** | *Shield control dashboard* | [proxy.pivoine.art](https://proxy.pivoine.art) |
| **VPN** | *Cloaking device network* | [vpn.pivoine.art](https://vpn.pivoine.art) | | **VPN** | *Cloaking device network* | [vpn.pivoine.art](https://vpn.pivoine.art) |
@@ -209,6 +210,7 @@ THE FALCON (falcon_network)
│ ├─ Linkwarden Marks [links.pivoine.art] │ ├─ Linkwarden Marks [links.pivoine.art]
│ ├─ Vaultwarden Vault [vault.pivoine.art] │ ├─ Vaultwarden Vault [vault.pivoine.art]
│ ├─ Joplin Sync Server [joplin.pivoine.art] │ ├─ Joplin Sync Server [joplin.pivoine.art]
│ ├─ Vert Converter [vert.pivoine.art]
│ ├─ Backrest Backups [restic.pivoine.art] │ ├─ Backrest Backups [restic.pivoine.art]
│ └─ WireGuard VPN [vpn.pivoine.art] │ └─ WireGuard VPN [vpn.pivoine.art]

View File

@@ -110,6 +110,11 @@ envs:
JOPLIN_TRAEFIK_HOST: joplin.pivoine.art JOPLIN_TRAEFIK_HOST: joplin.pivoine.art
JOPLIN_APP_PORT: 22300 JOPLIN_APP_PORT: 22300
JOPLIN_DB_NAME: joplin JOPLIN_DB_NAME: joplin
# Vert
VERT_TRAEFIK_ENABLED: true
VERT_COMPOSE_PROJECT_NAME: vert
VERT_IMAGE: ghcr.io/vert-sh/vert:latest
VERT_TRAEFIK_HOST: vert.pivoine.art
# Proxy # Proxy
PROXY_COMPOSE_PROJECT_NAME: proxy PROXY_COMPOSE_PROJECT_NAME: proxy
PROXY_DOCKER_IMAGE: traefik:latest PROXY_DOCKER_IMAGE: traefik:latest

View File

@@ -10,6 +10,7 @@ include:
- links/compose.yaml - links/compose.yaml
- vault/compose.yaml - vault/compose.yaml
- joplin/compose.yaml - joplin/compose.yaml
- vert/compose.yaml
- restic/compose.yaml - restic/compose.yaml
- umami/compose.yaml - umami/compose.yaml
- sablier/compose.yaml - sablier/compose.yaml

30
vert/compose.yaml Normal file
View File

@@ -0,0 +1,30 @@
services:
vert:
image: ${VERT_IMAGE:-ghcr.io/vert-sh/vert:latest}
container_name: ${VERT_COMPOSE_PROJECT_NAME}_app
restart: unless-stopped
environment:
PUB_HOSTNAME: ${VERT_TRAEFIK_HOST}
PUB_ENV: production
PUB_DISABLE_ALL_EXTERNAL_REQUESTS: true
networks:
- compose_network
labels:
- 'traefik.enable=${VERT_TRAEFIK_ENABLED}'
- 'traefik.http.middlewares.${VERT_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https'
- 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web.middlewares=${VERT_COMPOSE_PROJECT_NAME}-redirect-web-secure'
- 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web.rule=Host(`${VERT_TRAEFIK_HOST}`)'
- 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web.entrypoints=web'
- '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}-web-secure-compress.compress=true'
- 'traefik.http.routers.${VERT_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${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}'
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
networks:
compose_network:
name: ${NETWORK_NAME}
external: true