SafeBucket logo

SafeBucket

On-prem file sharing made simple, fast and safe

Alternative to: WeTransfer, ShareFile, Dropbox Transfer

SafeBucket screenshot

SafeBucket is an open source file sharing platform with pluggable infrastructure where files bypass the server via presigned uploads and downloads. It supports public share links with expiration and password protection, OIDC SSO with role-based access control, audit logging, and swappable storage, database, and cache backends.

SafeBucket Docker Compose example

Self-host SafeBucket on your own server, homelab, or VPS starting from this Docker Compose example. It runs SafeBucket in Docker containers using the official ghcr.io/safebucket/safebucket:latest, rustfs/rustfs:latest, amazon/aws-cli:latest images, with persistent volumes and automatic restarts preconfigured. Review the environment variables and adjust them to your setup, save the file as compose.yml (or docker-compose.yml), and start the stack with docker compose up -d.

services:
  safebucket:
    image: ghcr.io/safebucket/safebucket:latest
    restart: unless-stopped
    environment:
      # Log verbosity (debug, info, warn, error).
      APP__LOG_LEVEL: "info"
      # Configuration profile.
      APP__PROFILE: "default"
      # Public URL of the API (usually the same host as the web UI).
      APP__API_URL: "https://safebucket.example.com"
      # Public URL where the web UI is reached (e.g. https://files.example.com).
      APP__WEB_URL: "https://safebucket.example.com"
      # Port the app listens on inside the container.
      APP__PORT: "8080"
      # CIDR ranges of trusted reverse proxies (X-Forwarded-* handling).
      APP__TRUSTED_PROXIES: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128"
      # Serve the bundled web UI from the app (keep true).
      APP__STATIC_FILES__ENABLED: "true"
      # Secret used to sign auth tokens. Use a long random string.
      APP__TOKEN_SECRET: "5ugUl8bMKAnm/I1ZpbJF3klvD/Q7d2g6vi8slufTMs0="
      # Email address of the initial admin account created on first boot.
      APP__ADMIN_EMAIL: "admin@safebucket.io"
      # Password of the initial admin account created on first boot.
      APP__ADMIN_PASSWORD: "changeme"
      # Comma-separated origins allowed for browser (CORS) requests; include your public URL.
      APP__ALLOWED_ORIGINS: "https://safebucket.example.com"
      # Days deleted files are kept in trash before permanent removal.
      APP__TRASH_RETENTION_DAYS: "7"
      # AES-256 key for MFA secrets — must be exactly 32 characters.
      APP__MFA_ENCRYPTION_KEY: "ChangeMe32CharacterKeyForAES256!"
      # Require multi-factor authentication for all users (true/false).
      APP__MFA_REQUIRED: "false"
      # Maximum upload size in bytes (default 50 GB).
      APP__MAX_UPLOAD_SIZE: "53687091200"
      # Storage backend type.
      STORAGE__TYPE: "rustfs"
      # Name of the S3 bucket used for object storage.
      STORAGE__RUSTFS__BUCKET_NAME: "safebucket"
      # Internal endpoint the app uses to reach the object store.
      STORAGE__RUSTFS__ENDPOINT: "bucket:9000"
      # Public URL of the object store that browsers use for presigned up/downloads.
      STORAGE__RUSTFS__EXTERNAL_ENDPOINT: "https://s3.example.com"
      # Object-store access key.
      STORAGE__RUSTFS__ACCESS_KEY: "rustfsadmin"
      # Object-store secret key.
      STORAGE__RUSTFS__SECRET_KEY: "changeme"
      # Metadata database type (self-contained SQLite by default).
      DATABASE__TYPE: "sqlite"
      # Path to the SQLite database file.
      DATABASE__SQLITE__PATH: "/app/data/safebucket.db"
      # Cache backend (in-memory by default).
      CACHE__TYPE: "memory"
      # Event bus backend (in-memory by default).
      EVENTS__TYPE: "memory"
      EVENTS__QUEUES__NOTIFICATIONS__NAME: "safebucket-notifications"
      EVENTS__QUEUES__BUCKET_EVENTS__NAME: "safebucket-bucket-events"
      EVENTS__QUEUES__OBJECT_DELETION__NAME: "safebucket-object-deletion"
      # Notifier backend and where it stores queued notifications.
      NOTIFIER__TYPE: "filesystem"
      NOTIFIER__FILESYSTEM__DIRECTORY: "/app/data/notifications"
      # Activity log backend and where it stores entries.
      ACTIVITY__TYPE: "filesystem"
      ACTIVITY__FILESYSTEM__DIRECTORY: "/app/data/activity"
      # Enabled authentication providers.
      AUTH__PROVIDERS__KEYS: "local"
      AUTH__PROVIDERS__LOCAL__NAME: "local"
      AUTH__PROVIDERS__LOCAL__TYPE: "local"
      # Allow local users to share files (true/false).
      AUTH__PROVIDERS__LOCAL__SHARING__ALLOWED: "true"
      # Go garbage-collector aggressiveness.
      GOGC: "50"
    volumes:
      - safebucket_data:/app/data
    depends_on:
      bucket-init:
        condition: service_completed_successfully

  bucket:
    image: rustfs/rustfs:latest
    restart: unless-stopped
    environment:
      # Object-store access key.
      RUSTFS_ACCESS_KEY: "rustfsadmin"
      # Object-store secret key.
      RUSTFS_SECRET_KEY: "changeme"
    volumes:
      - rustfs_data:/data
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:9000/health && curl -f http://localhost:9001/rustfs/console/health"]
      interval: 3s
      timeout: 2s
      retries: 10
      start_period: 2s

  bucket-init:
    image: amazon/aws-cli:latest
    environment:
      # Credentials and target used to create the bucket and apply its CORS policy.
      AWS_ACCESS_KEY_ID: "rustfsadmin"
      AWS_SECRET_ACCESS_KEY: "changeme"
      AWS_RETRY_MODE: "standard"
      AWS_MAX_ATTEMPTS: "5"
      AWS_REGION: "us-east-1"
      BUCKET_NAME: "safebucket"
      ENDPOINT_URL: "http://bucket:9000"
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        echo "Configuring RustFS buckets via aws-cli..."

        echo "Waiting for RustFS to be ready..."
        while ! aws s3api head-bucket --bucket $${BUCKET_NAME} --endpoint-url $${ENDPOINT_URL} 2>/dev/null; do
          echo "Checking if bucket exists... if not creating it."
          aws s3api create-bucket --bucket $${BUCKET_NAME} --endpoint-url $${ENDPOINT_URL} 2>/dev/null || true
          sleep 2
        done

        echo "RustFS is ready and bucket $${BUCKET_NAME} exists."

        echo "Applying CORS policy..."
        aws s3api put-bucket-cors --bucket $${BUCKET_NAME} --endpoint-url $${ENDPOINT_URL} --cors-configuration '{"CORSRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET","PUT","POST","DELETE","HEAD"],"AllowedOrigins":["*"],"ExposeHeaders":["ETag"]}]}'

        echo "Buckets configured successfully."
    depends_on:
      bucket:
        condition: service_healthy
    restart: "no"

volumes:
  safebucket_data:
  rustfs_data:

Values set to changeme are required — replace them with your own values before starting SafeBucket.

Prefer a managed setup? WinterFlow installs, configures, and updates SafeBucket for you using this same Docker Compose configuration.