itsweber-send Svelte Themes

Itsweber Send

Self-hosted, end-to-end encrypted file sharing in a single Docker container.

ITSWEBER Send

Self-hosted, end-to-end encrypted file sharing in a single Docker container.

License: AGPL-3.0 Docker ready Made by ITSWEBER

Features · Quickstart · Configuration · Security · API · License

🇩🇪 Auf Deutsch lesenREADME.de.md


Status: v1.3.5 — three deployment modes (LAN direct with self-signed TLS, behind an existing reverse proxy, public with bundled Caddy + Let's Encrypt), Unraid template ready for Community Apps submission, mobile-responsive UI with hamburger drawer for account / admin, 2FA QR code, resumable chunked uploads for files of any size, FSA streaming downloads, SMTP notifications. All v1.0+ shares stay decryptable. Container image is linux/amd64 only at the moment; arm64 returns when GitHub provides native arm64 runners.


Screenshots

Upload

Drag & drop multi-file upload with expiry, download limit, password protection, 4-word code and notification settings.

All share options filled in: password, Markdown note for the recipient, notification on first download.

Share created

Ready to share: voice-readable 4-word code, scannable QR code, and the full encrypted link — all generated client-side.

Receive & Download

Recipients enter the share link, 24-character ID, or the 4-word handoff code to look up a share.

Files are listed with type and size. Download individually or grab all as a streaming ZIP. The server only ever sees ciphertext.

Admin panel

System overview: registered users, active and total shares, storage used. Links to health, readiness and OpenAPI endpoints.

Customise the on-first-download notification email with full HTML template editing and a live preview.


What it is

ITSWEBER Send is a modern, lightweight file-sharing service you run yourself. Files are encrypted in the browser (AES-256-GCM, key in URL fragment) before they touch the server — the server only ever sees ciphertext. Upload one or more files, get a link plus an optional QR code or four-word handoff phrase, and share it. After the configured number of downloads or expiry time, the share is permanently deleted.

Inspired by the original Firefox Send and the timvisee/send fork, but rebuilt from scratch with a modern stack and a wider feature set.

Features

Sharing

  • Drag-and-drop multi-file upload with resumable, chunked uploads — files of arbitrary size are streamed in 16 MiB ciphertext chunks, with pause / resume from the UI
  • Per-share password (layered on top of the URL key — when set, the share is decrypted via password only, no master key in the link)
  • Configurable expiry (1 h / 24 h / 7 d / 30 d) and download limit (1× to unlimited; counts per recipient share-download, not per blob)
  • QR code generated client-side for the share link
  • Four-word handoff code as an alternative to the long URL — combine with a password for fully voice-shareable transfers
  • Optional Markdown note for the recipient

Privacy & Security

  • Client-side AES-256-GCM encryption — the server never receives plaintext or filenames
  • Argon2id password hashing (OWASP 2026 defaults) for user accounts
  • Strict CSP, COOP/COEP, HSTS, Permissions-Policy — no third-party requests
  • Rate limiting and progressive backoff for brute-force attempts
  • Container runs as non-root with a read-only root filesystem and dropped capabilities
  • No telemetry, no trackers, no phone-home

UX

  • Light, dark and system-preference themes
  • German and English UI (i18n-ready)
  • Installable as a PWA
  • Anonymous by default; optional account adds upload history, higher quota and API token management

Operations

  • Single container, no external database or cache service required
  • SQLite by default
  • Health and readiness endpoints for container orchestrators
  • Webhooks for upload and download events
  • S3 / MinIO storage backend
  • SMTP notifications on first download

Quickstart

The image ships in three deployment modes. Pick the one that matches your environment.

Mode 1 — LAN direct (embedded Caddy, self-signed TLS)

For a home lab on a static LAN IP, with no public domain. The bundled Caddy terminates HTTPS on port 8443 with a self-signed certificate so Web Crypto works over the LAN.

docker run -d \
  --name itsweber-send \
  -p 8443:8443 \
  -v send-data:/data \
  -e SEND_HOST=192.168.1.100 \
  -e ORIGIN=https://192.168.1.100:8443 \
  -e BASE_URL=https://192.168.1.100:8443 \
  ghcr.io/itsweber-official/itsweber-send:latest

Open https://192.168.1.100:8443 and accept the self-signed certificate once. Compose alternative: docker/docker-compose.lan.yml.

Mode 2 — Behind your existing reverse proxy

For setups where Nginx Proxy Manager, Traefik, an Ingress controller or another upstream proxy already terminates HTTPS with a real certificate. The embedded Caddy is disabled so there is no double TLS termination.

docker run -d \
  --name itsweber-send \
  -p 3000:3000 \
  -v send-data:/data \
  -e REVERSE_PROXY_MODE=true \
  -e ORIGIN=https://send.example.com \
  -e BASE_URL=https://send.example.com \
  ghcr.io/itsweber-official/itsweber-send:latest

Forward your public hostname to port 3000 over plain HTTP. Compose alternative: docker/docker-compose.proxy.yml. Detailed snippets for NPM, Traefik, Caddy and Nginx: docs/REVERSE_PROXY.md.

Mode 3 — Public with bundled Caddy and Let's Encrypt

For single-server deployments with ports 80/443 free and no other proxy in front. A separate Caddy container fetches a Let's Encrypt certificate and proxies to the send container.

curl -O https://raw.githubusercontent.com/ITSWEBER-OFFICIAL/itsweber-send/main/docker/docker-compose.yml
curl -O https://raw.githubusercontent.com/ITSWEBER-OFFICIAL/itsweber-send/main/docker/Caddyfile.example

# Replace send.example.com with your domain in Caddyfile.example, then:
ORIGIN=https://send.example.com docker compose up -d

Unraid one-shot template

Drop the bundled XML template onto the Unraid USB so the container appears in the Docker → Container hinzufügen → Vorlage dropdown with everything pre-filled (image, volume, env vars, security flags):

wget -O /boot/config/plugins/dockerMan/templates-user/itsweber-send.xml \
  https://raw.githubusercontent.com/ITSWEBER-OFFICIAL/itsweber-send/main/unraid/itsweber-send.xml

Pre-chown the data directory before the first start. The image runs as the non-root UID 10001:10001, so the host bind-mount must be owned by that UID:

mkdir -p /mnt/user/appdata/itsweber-send
chown -R 10001:10001 /mnt/user/appdata/itsweber-send

Without this, SQLite refuses to open and the container exits on start.

Delete the source template after the first successful Apply. Unraid keeps both the source XML you wgot above and a my--prefixed copy of the user-applied state. When you later click Update / Force Update, Unraid can fall back to the source and overwrite your customisations (network, IP, public domain, ports). Remove the source after the first Apply so Unraid only reads the user-applied state on subsequent updates:

rm /boot/config/plugins/dockerMan/templates-user/itsweber-send.xml

Repeat the wget + Apply + rm cycle for future releases. This work-around goes away once the project is published to Community Apps proper.

Run from source

git clone https://github.com/ITSWEBER-OFFICIAL/itsweber-send
cd itsweber-send
pnpm install
pnpm dev

Web UI: http://localhost:5173 — API: http://localhost:3000


Configuration

All configuration is done via environment variables. Full reference: docs/CONFIG.md.

Variable Default Purpose
REVERSE_PROXY_MODE false When true, skip embedded Caddy and bind Node on 0.0.0.0:3000
ORIGIN http://localhost:3000 Public origin for share links and cookie scope
BASE_URL http://localhost:3000 Public URL the service is reachable under
SEND_HOST 192.168.0.10 LAN IP / hostname embedded into the embedded Caddy's self-signed cert
NODE_ENV development Set to production for production deployments
STORAGE_BACKEND filesystem filesystem (default) or s3 for S3/MinIO
STORAGE_PATH ./data/uploads Filesystem-backend upload directory
DB_PATH ./data/shares.db SQLite database path
RATE_LIMIT_PER_MIN 60 Per-IP request limit per minute
ENABLE_ACCOUNTS true Allow optional user accounts
REGISTRATION_ENABLED true Allow new registrations
DEFAULT_QUOTA_BYTES 5368709120 Per-user quota (default: 5 GB)

Documentation

Document Description
docs/INSTALL.md Installation guide for Docker and from source
docs/REVERSE_PROXY.md Running behind NPM, Traefik, Caddy or Nginx
docs/CONFIG.md Full environment variable reference
docs/API.md REST API reference
docs/SECURITY.md Security architecture and threat model
docs/ARCHITECTURE.md System design and component overview
docs/TROUBLESHOOTING.md Known issues and build/runtime pitfalls
packages/crypto-spec/README.md Cryptographic format specification
CHANGELOG.md Release history

Architecture

Layer Choice Notes
Backend Fastify 5 on Node.js 22 Resumable chunked uploads (custom protocol), S3 multipart
Frontend SvelteKit 2 + Svelte 5 + Vite TailwindCSS v4, svelte-i18n
Crypto Web Crypto API AES-256-GCM, PBKDF2 200 k iterations
DB better-sqlite3 Embedded; no separate service
Storage Filesystem (default) / S3 (MinIO) plugin Pluggable adapter
Container node:22-alpine, multi-stage Non-root UID 10001, read-only rootfs
Proxy Caddy 2 Automatic TLS, security headers

See docs/ARCHITECTURE.md for the full write-up.


License

AGPL-3.0-only. Running a modified version as a network service requires making the source of your modifications available to the users of that service.

Contributing

Pull requests are welcome. See CONTRIBUTING.md for the development setup and conventions. For security issues, use the private reporting process described in .github/SECURITY.md.

Top categories

Loading Svelte Themes