Full install

A production-ready setup with TLS, a public hostname, DKIM-signed email, persistent storage on its own volume, and a hardened systemd service.

Architecture overview

Customer/Internet
        │
   :443 (TLS)
        │
       nginx ──→ /static/* served directly
        │
   :5300 (loopback)
        │
   uvicorn (SpeedyFiles)
        ├── SQLite at /data/app.db
        └── Files at /srv/files (or S3)
              │
              └── Magic-link emails sent via your SMTP relay

Prerequisites

1. DNS

Point an A record at your server's public IP:

files.example.com.   A   203.0.113.10
# (and ensure rDNS / PTR is set for your IP — important for email deliverability)

2. TLS cert (Let's Encrypt)

The simplest path is HTTP-01 with certbot:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d files.example.com

Or if you use Route 53 for DNS, DNS-01 is cleaner (no port :80 needed):

sudo apt install python3-certbot-dns-route53
# Place AWS creds in /root/.aws/credentials
sudo certbot certonly --dns-route53 -d files.example.com

3. Reverse proxy (nginx)

Example vhost at /etc/nginx/sites-available/speedyfiles:

server {
    server_name files.example.com;

    client_max_body_size 0;
    proxy_request_buffering off;
    proxy_buffering off;
    proxy_http_version 1.1;
    proxy_read_timeout 7200s;
    proxy_send_timeout 7200s;
    send_timeout 7200s;

    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        proxy_pass http://127.0.0.1:5300;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    listen 443 ssl;
    ssl_certificate     /etc/letsencrypt/live/files.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/files.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
}
server {
    if ($host = files.example.com) { return 301 https://$host$request_uri; }
    listen 80;
    server_name files.example.com;
    return 404;
}

The settings that matter for big uploads: client_max_body_size 0, proxy_request_buffering off, and large timeouts.

4. Run the app

Option A — Docker Compose (recommended)

cat > docker-compose.yml <<'EOF'
services:
  speedyfiles:
    image: ghcr.io/speedyfiles/speedyfiles:latest
    ports:
      - "127.0.0.1:5300:5300"   # bind to loopback only; nginx handles public
    volumes:
      - ./data:/data
      - ./files:/srv/files
    environment:
      SESSION_SECRET: ${SESSION_SECRET}
      PUBLIC_BASE_URL: https://files.example.com
      LOCAL_STORAGE_ROOT: /srv/files
      DATABASE_URL: sqlite+aiosqlite:////data/app.db
    restart: unless-stopped
EOF
echo "SESSION_SECRET=$(openssl rand -hex 32)" > .env
docker compose up -d

Option B — bare-metal

git clone https://github.com/speedyfiles/speedyfiles
cd speedyfiles
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

# Generate .env from template
cp .env.example .env
sed -i "s|change-me|$(openssl rand -hex 32)|" .env

# Initialize DB
.venv/bin/python -m app.cli init-db

# Run
.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 5300

Bare-metal users will typically want a systemd unit. A template is in deploy/systemd/speedyfiles.service.

5. Reload nginx and visit /setup

sudo nginx -t && sudo systemctl reload nginx
open https://files.example.com/setup

Complete the wizard — details here.

6. Configure mail

After the wizard, go to Settings → Mail and configure your SMTP server. Use the Send test button to verify. Details: Mail config.

Deliverability tip: for SMTP servers you control, make sure SPF, DKIM, and DMARC are set up for your sending domain. See Deliverability for the full checklist.

7. Send your first package

Click + Send files. Pick files, set TTL, click Send. Watch the per-file progress bars. Your recipient gets a magic-link email and can download from any browser.

Done

You have a production SpeedyFiles instance. Next: