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
Rangerequests so HTML5 video can seek. - Background sweeper deletes expired files every 5 min.
- Per-upload
deleteTokenlets 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)
- Push this repo to Gitea:
git.montlab.dev/JosLe/video-share. - 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)
- Persistent storage → add a volume:
- Source:
share_data(named volume, or a host path you prefer) - Destination:
/data
- Source:
- Environment variables (optional override):
MAX_FILE_SIZE=524288000
- Set up the Gitea webhook exactly like the other apps in
INFRASTRUCTURE.md. - 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.