Deployment & phone testing
Run CrossUpload with Docker Compose, configure S3 and CloudFront, and test with a real phone on your LAN.
Local: one command
git clone … crossupload && cd crossupload
docker compose up
This starts the Rust app (port 8080, download origin 8081), PostgreSQL, a MinIO-compatible object store (9000) and ClamAV. Migrations, buckets, versioning and CORS are initialized automatically. No .env is needed. ClamAV downloads signatures on first start and can take a few minutes to become ready; files wait in “Checking file…” until it is.
Testing with a real phone
localhost on a phone means the phone. To test QR uploads from a real device, both the mobile page and the storage endpoint must be reachable from the phone:
# .env (replace with your computer's LAN IP)
PUBLIC_BASE_URL=http://192.168.1.20:8080
MOBILE_BASE_URL=http://192.168.1.20:8080
DOWNLOAD_BASE_URL=http://192.168.1.20:8081
STORAGE_ENDPOINT_PUBLIC=http://192.168.1.20:9000
Put the phone on the same Wi-Fi, run docker compose up again and open /demo on the computer using the LAN address. Some phone features (camera capture, clipboard) require HTTPS; for those, use a tunnel or a local TLS proxy and set the URLs to the HTTPS addresses.
Production
- Use
compose.prod.yamlwith the bundled Caddy reverse proxy (HTTPS, SSE without buffering). PostgreSQL and storage admin ports are not published. - The public site is static: a one-shot
siteservice runscrossupload export-static /siteon each deploy, and Caddy serves those files directly. Login, dashboard, API, SSE, the phone page and the SDK are proxied to the app. - Set
APP_ENV=production. The app refuses to start with development passwords, the default signing key, disabled scanning, the log email sink, private webhook destinations or non-HTTPS URLs. - Storage: Amazon S3 with two private buckets (quarantine and delivery), versioning on, Block Public Access, SSE encryption. Credentials come from the AWS provider chain (instance role recommended).
- Delivery: CloudFront with Origin Access Control to the delivery bucket only, and a trusted key group for signed URLs (
DELIVERY_MODE=cloudfront). - Billing: Stripe keys and three price IDs; point a Stripe webhook at
/webhooks/stripe. - Email: an SMTP URL for password resets.
Example IAM, bucket, CORS and CloudFront configuration lives in deploy/aws/.
Backups
docker compose exec -T postgres pg_dump -U crossupload -Fc crossupload > backup.dump
docker compose exec -T postgres pg_restore -U crossupload -d crossupload --clean < backup.dump
Back up the object store volume (or rely on S3 versioning and replication in production). A single-host deployment is a single point of failure; it is not highly available.
Something unclear or wrong? Email master@crossupload.com.