Self-hosted · Free · Secure

Team File Sync.
Simple. Secure.

Self-hosted — your data stays yours

Free, self-hosted file synchronization and sharing for teams. Deploy on your own infrastructure, keep full control of your data. One binary, zero external dependencies.

Why SyncBox

Self-Hosted

Your data, your infrastructure, your rules. Deploy on your own server with full control.

Real-Time Sync

Instant delta sync across all your devices via WebSocket. Always up to date.

Fine-Grained Permissions

Owner / Editor / Viewer + Group hierarchy. Precise access control for every file and folder.

File Versioning

Full version history with content-addressable storage. Restore any previous version instantly.

Lightweight

Go + SQLite. One binary, zero external dependencies. Deploy in seconds.

Cross-Platform

Native macOS app, Linux server, and CLI for both platforms. Sync everywhere.

Team Sharing

Create shared spaces, invite team members, and collaborate with granular access control.

Trash & Recovery

Deleted files go to trash first. Recover accidentally deleted files with one click.

Download

Download the right binary for your platform

macOS App

Apple Silicon (arm64)

Download .zip

Linux Server

amd64 binary

Download Binary

CLI (macOS)

darwin arm64

Download Binary

CLI (Linux)

linux amd64

Download Binary

Deployment Guide

Everything you need to go from a fresh VPS to a running SyncBox instance. Pick your deployment method.

Get SyncBox running in under 5 minutes. Good for testing and evaluation — for production, use the Production (VPS) tab.

1. Download the server binary

curl -L -o syncbox-server /downloads/syncbox-server-linux-amd64
chmod +x syncbox-server

2. Generate a JWT secret

openssl rand -hex 32

Save this output — you'll paste it into your config file below.

3. Create a minimal config.yaml

cat <<'EOF' > config.yaml
server:
  addr: "0.0.0.0:8080"

storage:
  type: "local"
  path: "./data/storage"

database:
  path: "./data/syncbox.db"

auth:
  jwt_secret: "PASTE_YOUR_64_CHAR_HEX_HERE"

admin:
  email: "[email protected]"
EOF

4. Start the server

mkdir -p ./data/storage
./syncbox-server --config config.yaml

5. Verify it's running

curl http://localhost:8080/health
# → {"status":"ok","version":"3.0"}

Open http://YOUR_IP:8080 in a browser. Register with your admin email to become the first admin user.

Complete production setup on Ubuntu/Debian with systemd, Nginx, and HTTPS. Tested on Ubuntu 22.04/24.04.

A. System preparation

# Install dependencies
sudo apt update && sudo apt install -y ca-certificates curl ufw nginx certbot python3-certbot-nginx

# Create a dedicated user (no login shell)
sudo useradd -r -s /usr/sbin/nologin -m -d /opt/syncbox syncbox

# Create directories
sudo mkdir -p /opt/syncbox/data/storage /opt/syncbox/web
sudo chown -R syncbox:syncbox /opt/syncbox

B. Download binary & web frontend

# Download server binary
sudo curl -L -o /opt/syncbox/syncbox-server /downloads/syncbox-server-linux-amd64
sudo chmod +x /opt/syncbox/syncbox-server

# Download and extract web frontend
sudo curl -L -o /tmp/syncbox-web.tar.gz /downloads/syncbox-web.tar.gz
sudo tar -xzf /tmp/syncbox-web.tar.gz -C /opt/syncbox/web

sudo chown -R syncbox:syncbox /opt/syncbox

C. Create config.yaml

Generate a JWT secret first, then create the full config:

# Generate JWT secret
openssl rand -hex 32
# → copy the output for jwt_secret below
sudo tee /opt/syncbox/config.yaml > /dev/null <<'EOF'
# ==================================================
# SyncBox Server Configuration — Production
# ==================================================

server:
  # Listen on localhost only — Nginx handles public traffic
  addr: "127.0.0.1:8081"
  # CORS origins: add your actual domain
  allowed_origins:
    - "https://sync.example.com"

storage:
  type: "local"                          # "local" or "s3"
  path: "/opt/syncbox/data/storage"      # Writable path for file storage

database:
  path: "/opt/syncbox/data/syncbox.db"   # SQLite database file

auth:
  jwt_secret: "PASTE_YOUR_64_CHAR_HEX_HERE"   # REQUIRED — from openssl rand -hex 32

# --- Email: choose ONE of smtp or resend ---
smtp:
  host: "smtp.example.com"
  port: 465
  username: "[email protected]"
  password: "your-smtp-password"
  from: "SyncBox <[email protected]>"

# resend:
#   api_key: "re_xxxxx"
#   from: "SyncBox <[email protected]>"

admin:
  email: "[email protected]"   # First user with this email becomes admin

rate_limit:
  auth:
    rate: 10
    interval: "1s"
    burst: 100
  api:
    rate: 100
    interval: "1s"
    burst: 1000
EOF

sudo chown syncbox:syncbox /opt/syncbox/config.yaml
sudo chmod 600 /opt/syncbox/config.yaml

D. systemd service

sudo tee /etc/systemd/system/syncbox.service > /dev/null <<'EOF'
[Unit]
Description=SyncBox File Sync Server
After=network.target

[Service]
Type=simple
User=syncbox
WorkingDirectory=/opt/syncbox
ExecStart=/opt/syncbox/syncbox-server --config /opt/syncbox/config.yaml
Restart=on-failure
RestartSec=5
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable syncbox

E. Firewall

sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable

F. Nginx reverse proxy + HTTPS

Replace sync.example.com with your actual domain. Point your DNS A record to the server IP first.

sudo tee /etc/nginx/sites-available/syncbox > /dev/null <<'EOF'
server {
    listen 80;
    server_name sync.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name sync.example.com;

    ssl_certificate /etc/letsencrypt/live/sync.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sync.example.com/privkey.pem;

    add_header X-Robots-Tag "noindex, nofollow, noarchive" always;

    root /opt/syncbox/web;
    index index.html;

    # API + WebSocket proxy
    location /api/ {
        client_max_body_size 50m;
        proxy_pass http://127.0.0.1:8081;
        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 https;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;
    }

    location /health {
        proxy_pass http://127.0.0.1:8081;
    }

    # Prevent SPA fallback for missing static assets
    location = /favicon.ico {
        try_files $uri =204;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot|map)$ {
        try_files $uri =404;
    }

    # SPA fallback
    location / {
        try_files $uri $uri/ /index.html;
    }
}
EOF

sudo ln -sf /etc/nginx/sites-available/syncbox /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
# Get SSL certificate from Let's Encrypt
sudo certbot --nginx -d sync.example.com

G. Start and verify

# Start the service
sudo systemctl start syncbox

# Check status
sudo systemctl status syncbox

# Test health endpoint
curl https://sync.example.com/health
# → {"status":"ok","version":"3.0"}

H. First login

Open https://sync.example.com in your browser. Register with the email address you set in admin.email — that account automatically becomes the admin. You'll receive an email verification code to complete registration.

Deploy with Docker Compose. The official image uses a multi-stage build (golang:1.24 + node:20 + alpine:3.20 runtime).

1. Create project directory

mkdir -p /opt/syncbox && cd /opt/syncbox

2. Create config.yaml

Inside the container, the config lives at /etc/syncbox/config.yaml and data is stored at /data.

cat <<'EOF' > config.yaml
server:
  addr: "0.0.0.0:8080"
  allowed_origins:
    - "https://sync.example.com"

storage:
  type: "local"
  path: "/data/storage"

database:
  path: "/data/syncbox.db"

auth:
  jwt_secret: "PASTE_YOUR_64_CHAR_HEX_HERE"

smtp:
  host: "smtp.example.com"
  port: 465
  username: "[email protected]"
  password: "your-smtp-password"
  from: "SyncBox <[email protected]>"

admin:
  email: "[email protected]"

rate_limit:
  auth:
    rate: 10
    interval: "1s"
    burst: 100
  api:
    rate: 100
    interval: "1s"
    burst: 1000
EOF

3. Create docker-compose.yml

cat <<'EOF' > docker-compose.yml
version: "3.8"

services:
  syncbox:
    image: syncbox/syncbox:latest
    container_name: syncbox
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config.yaml:/etc/syncbox/config.yaml:ro
      - syncbox-data:/data
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"

volumes:
  syncbox-data:
EOF

4. Start

docker compose up -d

# Verify
docker compose ps
curl http://localhost:8080/health
# → {"status":"ok","version":"3.0"}

For HTTPS, put Nginx or Caddy in front. See the Production (VPS) tab for the Nginx config — just change proxy_pass to http://127.0.0.1:8080.

Switch from local disk to S3-compatible storage (AWS S3, MinIO, Cloudflare R2, etc.). Change the storage block in config.yaml:

AWS S3

storage:
  type: "s3"
  s3:
    endpoint: "https://s3.amazonaws.com"
    region: "us-east-1"
    bucket: "my-syncbox-files"
    access_key: "AKIAIOSFODNN7EXAMPLE"
    secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

MinIO (self-hosted)

storage:
  type: "s3"
  s3:
    endpoint: "https://minio.internal:9000"
    region: "us-east-1"
    bucket: "syncbox"
    access_key: "minioadmin"
    secret_key: "minioadmin"

Cloudflare R2

storage:
  type: "s3"
  s3:
    endpoint: "https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
    region: "auto"
    bucket: "syncbox"
    access_key: "your-r2-access-key"
    secret_key: "your-r2-secret-key"
Note: The SQLite database (database.path) always stays on local disk. Only file content is stored in S3. Make sure your S3 bucket exists before starting the server.

SyncBox needs email for user registration (verification codes) and team invitations. Choose ONE of SMTP or Resend.

Gmail (App Password)

Enable 2FA on your Google account, then generate an App Password at myaccount.google.com → Security → App Passwords.

smtp:
  host: "smtp.gmail.com"
  port: 465
  username: "[email protected]"
  password: "xxxx xxxx xxxx xxxx"    # 16-char app password
  from: "SyncBox <[email protected]>"

AWS SES

smtp:
  host: "email-smtp.us-east-1.amazonaws.com"
  port: 465
  username: "AKIAIOSFODNN7EXAMPLE"     # SES SMTP credentials (not IAM keys)
  password: "your-ses-smtp-password"
  from: "SyncBox <[email protected]>"

Resend

No SMTP config needed. Get an API key from resend.com/api-keys and verify your sending domain.

# Remove the smtp: block and use this instead:
resend:
  api_key: "re_123456789"
  from: "SyncBox <[email protected]>"
Tip: For the Quick Deploy without email configured, users won't receive verification codes. Configure email before inviting your team.

Once your server is running, set up the desktop app or CLI on each device.

macOS App

# Download and install
curl -L -O /downloads/SyncBox-macOS-arm64.zip
unzip SyncBox-macOS-arm64.zip
mv SyncBox.app /Applications/

# Open the app
open /Applications/SyncBox.app

On first launch, enter your server URL (e.g. https://sync.example.com), then log in with your email. Files sync to ~/SyncBox/ by default.

CLI (macOS / Linux)

# macOS (Apple Silicon)
curl -L -o syncbox /downloads/syncbox-cli-darwin-arm64

# — OR — Linux (amd64)
curl -L -o syncbox /downloads/syncbox-cli-linux-amd64

chmod +x syncbox
sudo mv syncbox /usr/local/bin/
# Log in — you'll receive a verification code via email
syncbox login https://sync.example.com

# Start the background sync daemon
syncbox start

# Check sync status
syncbox status

# Stop syncing
syncbox stop

Regular maintenance ensures data safety and smooth upgrades.

SQLite database backup

Use SQLite's built-in .backup command for a consistent snapshot — never copy the .db file while the server is running.

# One-time backup
sqlite3 /opt/syncbox/data/syncbox.db ".backup /opt/syncbox/backups/syncbox-$(date +%Y%m%d).db"

# Cron job: daily at 2 AM
echo '0 2 * * * syncbox sqlite3 /opt/syncbox/data/syncbox.db ".backup /opt/syncbox/backups/syncbox-$(date +\%Y\%m\%d).db"' | sudo tee /etc/cron.d/syncbox-backup

Storage directory backup

# rsync to a backup location (local or remote)
rsync -a /opt/syncbox/data/storage/ /mnt/backup/syncbox-storage/

# Or tar archive
tar -czf /mnt/backup/syncbox-storage-$(date +%Y%m%d).tar.gz -C /opt/syncbox/data storage/

Log rotation

SyncBox logs via systemd journal. Configure rotation:

# View logs
sudo journalctl -u syncbox -f

# Limit journal size (in /etc/systemd/journald.conf)
# SystemMaxUse=500M

Upgrade procedure

# 1. Download new binary
sudo curl -L -o /opt/syncbox/syncbox-server-new /downloads/syncbox-server-linux-amd64
sudo chmod +x /opt/syncbox/syncbox-server-new

# 2. Swap binary (keep the old one for rollback)
sudo mv /opt/syncbox/syncbox-server /opt/syncbox/syncbox-server-old
sudo mv /opt/syncbox/syncbox-server-new /opt/syncbox/syncbox-server

# 3. Restart
sudo systemctl restart syncbox

# 4. Verify
curl https://sync.example.com/health

# Rollback if needed:
# sudo mv /opt/syncbox/syncbox-server-old /opt/syncbox/syncbox-server
# sudo systemctl restart syncbox

Quick Start

From zero to syncing in 6 steps

1

Deploy Server

Download the Linux binary, create config.yaml, and start the server.

2

Register Admin

Open the web UI and register with your admin email to become the first admin.

3

Create a Space

Create a shared space for your team's files. Set permissions as needed.

4

Invite Team

Invite team members via email. They'll receive a link to register and join.

5

Install Client

Download the macOS app or CLI, enter your server URL, and log in.

6

Start Syncing

Your files sync automatically. Changes propagate instantly across all devices.