share

Minimalist no-signup file/video drop. Upload a file, get a private UUID link, share it. Files self-destruct after a configurable TTL.

  • No accounts, no DB. Metadata is a tiny JSON sidecar per upload.
  • Streamed uploads (no in-memory buffering).
  • HTTP Range requests so HTML5 video can seek.
  • Background sweeper deletes expired files every 5 min.
  • Per-upload deleteToken lets the uploader revoke early.

Local dev

npm install
npm run dev
# http://127.0.0.1:3000

Files land in ./data/uploads.

Configuration

Env Default Notes
PORT 3000 HTTP port
HOST 0.0.0.0 Bind host
DATA_DIR /data/uploads Persisted directory (mount a volume here)
MAX_FILE_SIZE 524288000 500 MB. Bytes.
LOG_LEVEL info Fastify logger level

TTL options exposed in the UI: 30m / 1h / 6h / 24h. Edit TTL_OPTIONS in src/server.js to change.

Deploy on Coolify (montlab.dev)

Two ways. Pick one.

Option A — Dockerfile build pack (matches existing apps)

  1. Push this repo to Gitea: git.montlab.dev/JosLe/video-share.
  2. In Coolify, create a new app:
    • Build pack: Dockerfile
    • Source: Public Repository → https://git.montlab.dev/JosLe/video-share.git
    • Branch: main
    • Port: 3000
    • Domain: share.montlab.dev (Caddy + Let's Encrypt is automatic)
  3. Persistent storage → add a volume:
    • Source: share_data (named volume, or a host path you prefer)
    • Destination: /data
  4. Environment variables (optional override):
    • MAX_FILE_SIZE=524288000
  5. Set up the Gitea webhook exactly like the other apps in INFRASTRUCTURE.md.
  6. Deploy. First time may need "Force redeploy without cache".

Option B — Docker Compose build pack

Use the bundled docker-compose.yaml. Pick build pack Docker Compose in Coolify, point at this repo, set the domain on the app service to share.montlab.dev, port 3000. The named volume share_data is declared in the compose file.

Caddy / proxy notes

Coolify's Caddy fronts the app, so HTTPS, HTTP/2 and request body limits are handled there. caddy-docker-proxy v2.9 does not cap upload size by default for HTTP/2, but if a future config sets request_body { max_size ... }, bump it above MAX_FILE_SIZE.

Endpoints

Method Path Purpose
GET / Upload page
POST /upload multipart form: file + ttl (30m/1h/6h/24h)
GET /v/:id Viewer (HTML, video player)
GET /f/:id Raw file stream, supports Range
GET /f/:id?dl=1 Force download
GET /api/info/:id JSON metadata
DELETE /api/:id?token=... Revoke with the delete token
GET /healthz Liveness

Links use UUID v4. They are unguessable but not authenticated — anyone with the link can view. Send the link over a private channel.

Disk usage

A 500 MB upload at 1 h TTL uses ~500 MB until the sweep cycle picks it up (≤5 min after expiry). For peak sizing assume users × max_concurrent_uploads × MAX_FILE_SIZE × longest_TTL/sweep_interval. Coolify's CX22 has 40 GB SSD — keep an eye on it or lower MAX_FILE_SIZE.

Description
Minimalist no-signup file/video share with private UUID links and TTL
Readme 48 KiB
Languages
JavaScript 67.3%
CSS 19.8%
HTML 10.8%
Dockerfile 2.1%