All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m38s
- Add `WARPBOX_TRUSTED_PROXIES` configuration to restrict accepted forwarded client IP headers to specific proxy IPs/CIDRs, securing client IP resolution. - Integrate `BanService` into the background cleanup job to automatically purge expired abuse and ban evidence events. - Update documentation with reverse proxy security guidelines and a production systemd deployment guide.
238 lines
10 KiB
Markdown
238 lines
10 KiB
Markdown
# Warpbox.dev
|
|
|
|
This repository contains the Go backend base for `warpbox.dev`, a self-hosted transfer-first file sharing application.
|
|
|
|
## Run
|
|
|
|
```bash
|
|
./scripts/run/dev.sh
|
|
```
|
|
|
|
The default server listens on `:8080`.
|
|
|
|
Upload size limits are configured in megabytes through `WARPBOX_MAX_UPLOAD_SIZE_MB`.
|
|
Fractions are supported, so `0.5Mb` is 512 KiB and `1.5Mb` is 1536 KiB.
|
|
|
|
Upload policy defaults are also configured in megabytes and can later be changed from
|
|
`/admin/settings`:
|
|
|
|
- `WARPBOX_ANONYMOUS_UPLOADS_ENABLED=true`
|
|
- `WARPBOX_ANONYMOUS_MAX_UPLOAD_MB=512`
|
|
- `WARPBOX_ANONYMOUS_DAILY_UPLOAD_MB=2048`
|
|
- `WARPBOX_USER_DAILY_UPLOAD_MB=8192`
|
|
- `WARPBOX_DEFAULT_USER_STORAGE_MB=51200`
|
|
- `WARPBOX_USAGE_RETENTION_DAYS=30`
|
|
- `WARPBOX_LOCAL_STORAGE_MAX_GB=100`
|
|
- `WARPBOX_ANONYMOUS_MAX_DAYS=30`
|
|
- `WARPBOX_USER_MAX_DAYS=90`
|
|
- `WARPBOX_ANONYMOUS_DAILY_BOXES=100`
|
|
- `WARPBOX_USER_DAILY_BOXES=250`
|
|
- `WARPBOX_ANONYMOUS_ACTIVE_BOXES=500`
|
|
- `WARPBOX_USER_ACTIVE_BOXES=1000`
|
|
- `WARPBOX_SHORT_WINDOW_REQUESTS=60`
|
|
- `WARPBOX_SHORT_WINDOW_SECONDS=60`
|
|
- `WARPBOX_ANONYMOUS_STORAGE_BACKEND=local`
|
|
- `WARPBOX_USER_STORAGE_BACKEND=local`
|
|
- `WARPBOX_TRUSTED_PROXIES=` controls whether forwarded client IP headers are accepted only from specific proxy IPs/CIDRs. See [SECURITY_PROXY.md](./SECURITY_PROXY.md).
|
|
|
|
Runtime data is configured with `WARPBOX_DATA_DIR` and defaults to `./data` in the dev environment.
|
|
The dev script resolves that path from the repository root.
|
|
|
|
Background jobs are enabled with `WARPBOX_JOBS_ENABLED=true`. Individual jobs can be toggled with
|
|
`WARPBOX_CLEANUP_ENABLED` and `WARPBOX_THUMBNAIL_ENABLED`, and their schedules are configured with
|
|
`WARPBOX_CLEANUP_EVERY` and `WARPBOX_THUMBNAIL_EVERY`.
|
|
|
|
On a fresh data directory, visit `/register` to create the first account. That first user becomes
|
|
the instance admin and normal registration closes after bootstrap. Admins can create copyable invite
|
|
links from `/admin/users`.
|
|
|
|
The env admin token still exists as emergency fallback access. Set `WARPBOX_ADMIN_TOKEN` and use it
|
|
at `/admin/login` if you need to recover access without a user session.
|
|
|
|
For one-off Go commands, run them from the backend module:
|
|
|
|
```bash
|
|
cd backend
|
|
go run ./cmd/warpbox
|
|
```
|
|
|
|
## Docker / Podman
|
|
|
|
Copy the example environment file and adjust values such as `WARPBOX_BASE_URL` and
|
|
`WARPBOX_ADMIN_TOKEN` before running the container:
|
|
|
|
Copy the example [docker-compose.example.yml](./docker-compose.example.yml) to [docker-compose.yml](./docker-compose.yml), modify as need-be
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
docker compose -f docker-compose.yml up --build
|
|
```
|
|
|
|
The compose example also works with Podman compatible compose tools. Its data volume uses
|
|
`./data:/data:Z` for SELinux relabeling, and the container overrides runtime paths to use
|
|
`/data`, `/app/static`, and `/app/templates`.
|
|
|
|
The image exposes `/health`, `/healthz`, and `/api/v1/health`. Docker and compose healthchecks
|
|
use `/health`.
|
|
|
|
## Reverse Proxy Security
|
|
|
|
Warpbox uses the resolved client IP for anonymous limits, manual bans, and automatic bans. The
|
|
default behavior trusts `X-Forwarded-For` and `X-Real-IP` so a normal Caddy reverse proxy works
|
|
without extra setup. For hardened deployments where the app port might be reachable from more than
|
|
one network, set `WARPBOX_TRUSTED_PROXIES` to trusted proxy IPs/CIDRs. See
|
|
[SECURITY_PROXY.md](./SECURITY_PROXY.md) for Caddy examples and Docker/systemd notes.
|
|
|
|
## Systemd
|
|
|
|
Build the binary on the server, create a dedicated user, and keep runtime data outside the repo:
|
|
|
|
```bash
|
|
cd /opt/warpbox-dev/backend
|
|
go build -o /usr/local/bin/warpbox ./cmd/warpbox
|
|
sudo useradd --system --home /var/lib/warpbox --shell /usr/sbin/nologin warpbox
|
|
sudo mkdir -p /var/lib/warpbox /etc/warpbox
|
|
sudo chown -R warpbox:warpbox /var/lib/warpbox
|
|
sudo cp /opt/warpbox-dev/.env.example /etc/warpbox/warpbox.env
|
|
```
|
|
|
|
Example `/etc/warpbox/warpbox.env` values:
|
|
|
|
```env
|
|
WARPBOX_ENV=production
|
|
WARPBOX_ADDR=127.0.0.1:6070
|
|
WARPBOX_BASE_URL=https://warpbox.dev
|
|
WARPBOX_DATA_DIR=/var/lib/warpbox
|
|
WARPBOX_STATIC_DIR=/opt/warpbox-dev/backend/static
|
|
WARPBOX_TEMPLATE_DIR=/opt/warpbox-dev/backend/templates
|
|
WARPBOX_TRUSTED_PROXIES=127.0.0.1,::1
|
|
```
|
|
|
|
Example `/etc/systemd/system/warpbox.service`:
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=Warpbox file sharing service
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
User=warpbox
|
|
Group=warpbox
|
|
EnvironmentFile=/etc/warpbox/warpbox.env
|
|
ExecStart=/usr/local/bin/warpbox
|
|
Restart=always
|
|
RestartSec=5
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=strict
|
|
ReadWritePaths=/var/lib/warpbox
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Then enable it:
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now warpbox
|
|
sudo systemctl status warpbox
|
|
```
|
|
|
|
Put Caddy in front of `127.0.0.1:6070` and keep the Warpbox port closed to the public internet.
|
|
|
|
## Layout
|
|
|
|
- `backend/cmd/warpbox` - main application entry point.
|
|
- `backend/libs/config` - environment-backed configuration.
|
|
- `backend/libs/httpserver` - server construction and route composition.
|
|
- `backend/libs/handlers` - HTTP handlers for pages, API, health, static files.
|
|
- `backend/libs/jobs` - background job registration and job loop definitions.
|
|
- `backend/libs/middleware` - request logging, recovery, security headers, gzip, request IDs.
|
|
- `backend/libs/services` - business logic boundaries, starting with upload limits.
|
|
- `backend/libs/helpers` - small reusable helpers.
|
|
- `backend/libs/web` - Go template renderer.
|
|
- `backend/templates` - server-rendered Go templates.
|
|
- `backend/static/css`, `backend/static/js`, `backend/static/img`, `backend/static/fonts` - public assets served from `/static/`.
|
|
- `scripts/run/dev.sh` - local development runner.
|
|
- `scripts/env/dev.env.example` - tracked development environment template.
|
|
- `scripts/env/dev.env` - local development environment, ignored by git.
|
|
|
|
## Stage 2 Operator Tools
|
|
|
|
- `/admin/login` - token-based admin login.
|
|
- `/admin` - overview metrics: boxes, files, storage, recent uploads, protected/expired boxes.
|
|
- `/admin/files` - recent upload table with view and delete actions.
|
|
- Expired boxes and boxes that have reached their download limit are cleaned on startup and then every `WARPBOX_CLEANUP_EVERY` when `WARPBOX_CLEANUP_ENABLED=true`.
|
|
- Missing image/video thumbnails are generated in a background worker every `WARPBOX_THUMBNAIL_EVERY` when `WARPBOX_THUMBNAIL_ENABLED=true`.
|
|
|
|
## Stage 3 Anonymous Integrations
|
|
|
|
Anonymous uploads now return a private management link at creation time. Keep that link secret:
|
|
anyone with it can delete the entire upload box. The raw delete token is not stored and cannot be
|
|
recovered later.
|
|
|
|
Browser uploads still show `Open box` and `Copy URL` as the primary actions, with a smaller
|
|
`Manage or delete this upload` link in the completion panel.
|
|
|
|
Curl and custom uploaders can use the same endpoint:
|
|
|
|
```bash
|
|
# Terminal-friendly output: one plain box URL.
|
|
curl -F file=@./report.pdf http://localhost:8080/api/v1/upload
|
|
|
|
# JSON output with boxUrl, manageUrl, deleteUrl, zipUrl, and file entries.
|
|
curl -F sharex=@./screenshot.png \
|
|
-H 'Accept: application/json' \
|
|
http://localhost:8080/api/v1/upload
|
|
```
|
|
|
|
The upload endpoint accepts multipart fields named `file` and `sharex`. ShareX users can start
|
|
from `examples/sharex/warpbox-anonymous.sxcu`; update `RequestURL` to match your instance URL.
|
|
|
|
## Stage 4 Accounts + Personal Boxes
|
|
|
|
- `/register` bootstraps the first admin account only when no users exist.
|
|
- `/login` and `/logout` provide cookie-based web sessions.
|
|
- `/app` is the personal dashboard for logged-in users, showing owned boxes, storage usage, upload
|
|
history, and flat collections. Uploading still happens from the homepage.
|
|
- `/admin/users` lets admins create invite links, disable/reactivate users, and generate reset links.
|
|
- Logged-in browser uploads from `/` still use `POST /api/v1/upload`, but the resulting box is
|
|
stored with owner and optional collection metadata.
|
|
- Admin users are exempt from the global max upload size on the homepage upload flow. Future
|
|
per-user quotas should apply to this same upload path rather than creating a second uploader.
|
|
- `/admin/settings` controls anonymous uploads, anonymous max upload size, daily upload caps, default
|
|
user storage quota, and usage retention.
|
|
- `/admin/users` shows storage/daily usage and lets admins set per-user storage quota overrides.
|
|
- `/admin/storage` manages the built-in local file backend and S3-compatible bucket backends.
|
|
- `/admin/bans` manages manual IP/CIDR bans and optional automatic bans for suspicious probes and
|
|
repeated login failures. Auto-ban is off by default and configured from the admin UI.
|
|
- Upload limits now include daily bytes, daily box counts, active box counts, short-window request
|
|
limits, max expiration days, local storage capacity in GB, and per-user policy overrides.
|
|
- Uploaded file content, thumbnails, and private box metadata use the selected storage backend.
|
|
The bbolt database and JSON logs remain local under `./data/db` and `./data/logs`.
|
|
- Anonymous uploads, ShareX uploads, unlisted public box links, password protection, expiry, delete
|
|
tokens, thumbnails, and cleanup continue to work as before.
|
|
|
|
Email delivery is intentionally deferred. Invite and reset links are copyable today; future SMTP
|
|
support will power public forgot-password and optional email delivery.
|
|
|
|
## Runtime Data
|
|
|
|
Warpbox keeps local runtime data under the configured data directory:
|
|
|
|
- `data/files/{box_id}/@each@{file_id}.ext` - uploaded file contents when the local backend is selected.
|
|
- `data/files/{box_id}/@thumb@{file_id}.jpg` - generated previews when the local backend is selected.
|
|
- `data/db/warpbox.bbolt` - bbolt metadata database for boxes and file records.
|
|
- `data/db/warpbox.bbolt` also stores users, sessions, invites, and collections.
|
|
- `data/db/warpbox.bbolt` stores upload policy settings and daily usage records keyed by plain IP
|
|
for anonymous uploads and user ID for signed-in uploads.
|
|
- `data/db/warpbox.bbolt` stores manual bans, automatic ban settings, abuse counters, and malicious
|
|
path rules.
|
|
- `data/logs/{YYYY-MM-DD}.log` - JSONL logs, one event per line.
|
|
|
|
## Static Asset Policy
|
|
|
|
The static handler sets long-lived immutable caching for images, video, audio, and fonts, shorter caching for CSS/JS, and gzip compression for compressible responses.
|