diff --git a/CLAUDE.md b/CLAUDE.md index f752aac..60f725c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,6 +25,7 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul - **vert**: VERT file format converter (WebAssembly-based, stateless) - **paint**: miniPaint web-based image editor (built from GitHub) - **jelly**: Jellyfin media server with hardware transcoding +- **drop**: PairDrop peer-to-peer file sharing - **restic**: Backrest backup system with restic backend - **sablier**: Dynamic scaling plugin for Traefik - **vpn**: WireGuard VPN (wg-easy) @@ -322,6 +323,33 @@ Access https://jelly.pivoine.art to browse and stream your media. Jellyfin will **Note**: Jellyfin requires the HiDrive WebDAV mount to be active on the host at `/mnt/hidrive`. +### PairDrop (drop/compose.yaml) +PairDrop peer-to-peer file sharing service: +- **pairdrop**: PairDrop app exposed at `drop.pivoine.art:3000` + - Local network file sharing between devices + - Peer-to-peer file transfer via WebRTC + - No file size limits + - Works across platforms (desktop, mobile, tablets) + - End-to-end encrypted transfers + - No file uploads to server (direct peer connections) + - Rate limiting enabled for security + - Stateless architecture (no data persistence) + +**Features**: +- Share files by opening the same URL on multiple devices +- Devices on the same network automatically discover each other +- Works across different networks via public room codes +- Text messages and file sharing support +- Progressive Web App (PWA) installable on mobile + +**Usage**: +1. Open https://drop.pivoine.art on your device +2. Open the same URL on another device +3. Devices will appear and you can share files directly +4. Files transfer peer-to-peer without uploading to server + +**Note**: PairDrop is stateless and doesn't require backups as no data is persisted. All transfers happen directly between devices. + ### Restic (restic/compose.yaml) Backrest backup system with restic backend: - **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898` diff --git a/arty.yml b/arty.yml index 646d4a9..e2e39c0 100644 --- a/arty.yml +++ b/arty.yml @@ -124,6 +124,10 @@ envs: JELLY_TRAEFIK_ENABLED: true JELLY_COMPOSE_PROJECT_NAME: jelly JELLY_TRAEFIK_HOST: jelly.pivoine.art + # PairDrop + DROP_TRAEFIK_ENABLED: true + DROP_COMPOSE_PROJECT_NAME: drop + DROP_TRAEFIK_HOST: drop.pivoine.art # Proxy PROXY_COMPOSE_PROJECT_NAME: proxy PROXY_DOCKER_IMAGE: traefik:latest diff --git a/compose.yaml b/compose.yaml index 1c23a4b..0960a7b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -13,6 +13,7 @@ include: - vert/compose.yaml - paint/compose.yaml - jelly/compose.yaml + - drop/compose.yaml - restic/compose.yaml - umami/compose.yaml - sablier/compose.yaml diff --git a/drop/compose.yaml b/drop/compose.yaml new file mode 100644 index 0000000..c0e36ae --- /dev/null +++ b/drop/compose.yaml @@ -0,0 +1,36 @@ +services: + pairdrop: + image: lscr.io/linuxserver/pairdrop:latest + container_name: ${DROP_COMPOSE_PROJECT_NAME}_app + restart: unless-stopped + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TIMEZONE:-Europe/Berlin} + RATE_LIMIT: true + WS_FALLBACK: false + networks: + - compose_network + labels: + - 'traefik.enable=${DROP_TRAEFIK_ENABLED}' + # HTTP to HTTPS redirect + - 'traefik.http.middlewares.${DROP_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web.middlewares=${DROP_COMPOSE_PROJECT_NAME}-redirect-web-secure' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web.rule=Host(`${DROP_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web.entrypoints=web' + # HTTPS router + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${DROP_TRAEFIK_HOST}`)' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure' + - 'traefik.http.middlewares.${DROP_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true' + - 'traefik.http.routers.${DROP_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${DROP_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file' + # Service + - 'traefik.http.services.${DROP_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=3000' + - 'traefik.docker.network=${NETWORK_NAME}' + # Watchtower + - 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}' + +networks: + compose_network: + name: ${NETWORK_NAME} + external: true