Self-hosted, end-to-end encrypted file sharing in a single Docker container.
Features · Quickstart · Configuration · Security · API · License
🇩🇪 Auf Deutsch lesen → README.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/amd64only at the moment; arm64 returns when GitHub provides native arm64 runners.
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.
The image ships in three deployment modes. Pick the one that matches your environment.
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.
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.
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
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-sendWithout 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.xmlRepeat the wget + Apply + rm cycle for future releases. This work-around goes away once the project is published to Community Apps proper.
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
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) |
| 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 |
| 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.
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.
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.