Backup & Recovery
    Open Source

    Deploy Kopia Repository Server

    Per-user authenticated multi-client backups proxied through a central server — only the VPS holds the storage credentials and repository password.

    At a Glance

    ProjectKopia (server mode)
    LicenseApache 2.0
    Recommended PlanRamNode Cloud VPS 2 GB+
    OSUbuntu 24.04 LTS
    BackendsB2, S3, R2, Wasabi, GCS, Azure, SFTP

    Looking for the single-host backup client?

    See our Kopia (single-machine) guide. This page covers repository server mode for multi-client deployments.

    1

    Install Kopia + Service User

    Add APT repo
    sudo apt update && sudo apt -y full-upgrade
    sudo apt -y install ca-certificates curl gnupg apache2-utils ufw
    
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -s https://kopia.io/signing-key | sudo gpg --dearmor -o /etc/apt/keyrings/kopia-keyring.gpg
    echo "deb [signed-by=/etc/apt/keyrings/kopia-keyring.gpg] http://packages.kopia.io/apt/ stable main" \
      | sudo tee /etc/apt/sources.list.d/kopia.list
    sudo apt update && sudo apt -y install kopia
    kopia --version
    
    sudo useradd -r -m -d /var/lib/kopia -s /bin/bash kopia
    2

    Prepare the Repository Backend (Backblaze B2)

    Create or connect
    sudo -iu kopia
    
    # Create ONCE for a brand new repository:
    kopia repository create b2 \
      --bucket=my-backup-bucket \
      --key-id="$B2_KEY_ID" \
      --key="$B2_APPLICATION_KEY"
    # (Set a long passphrase — losing it means losing the data.)
    
    # Or connect to an existing repository:
    kopia repository connect b2 \
      --bucket=my-backup-bucket \
      --key-id="$B2_KEY_ID" \
      --key="$B2_APPLICATION_KEY"
    
    kopia repository status
    3

    Generate Internal TLS Material

    Self-signed cert (Caddy will validate publicly)
    sudo -iu kopia
    mkdir -p ~/.config/kopia/tls
    cd ~/.config/kopia/tls
    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout server.key -out server.cert -days 3650 \
      -subj "/CN=kopia-internal"
    chmod 600 server.key
    4

    Per-Client User Database (htpasswd)

    Use bcrypt (-B)
    htpasswd -cB ~/.config/kopia/htpasswd alice@laptop
    htpasswd -B ~/.config/kopia/htpasswd bob@desktop
    htpasswd -B ~/.config/kopia/htpasswd web01@production
    5

    systemd Service

    control password
    openssl rand -base64 32 > ~/.config/kopia/control.password
    chmod 600 ~/.config/kopia/control.password
    /etc/systemd/system/kopia-server.service
    [Unit]
    Description=Kopia Repository Server
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    User=kopia
    Group=kopia
    WorkingDirectory=/var/lib/kopia
    Environment=HOME=/var/lib/kopia
    
    ExecStart=/usr/bin/kopia server start \
      --address=127.0.0.1:51515 \
      --tls-cert-file=/var/lib/kopia/.config/kopia/tls/server.cert \
      --tls-key-file=/var/lib/kopia/.config/kopia/tls/server.key \
      --htpasswd-file=/var/lib/kopia/.config/kopia/htpasswd \
      --server-control-username=control \
      --server-control-password-file=/var/lib/kopia/.config/kopia/control.password \
      --no-ui
    
    Restart=on-failure
    RestartSec=10
    
    NoNewPrivileges=true
    PrivateTmp=true
    ProtectSystem=strict
    ProtectHome=true
    ReadWritePaths=/var/lib/kopia
    ProtectKernelTunables=true
    
    [Install]
    WantedBy=multi-user.target
    Enable
    sudo systemctl daemon-reload
    sudo systemctl enable --now kopia-server
    journalctl -u kopia-server -f
    6

    Caddy Reverse Proxy + Let's Encrypt

    Install Caddy
    sudo apt -y install debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
    sudo apt update && sudo apt -y install caddy
    /etc/caddy/Caddyfile
    backup.example.com {
      encode zstd gzip
      request_body { max_size 10GB }
    
      reverse_proxy 127.0.0.1:51515 {
        transport http {
          tls
          tls_insecure_skip_verify
          response_header_timeout 600s
          read_timeout 600s
          write_timeout 600s
        }
      }
    }
    Reload + firewall
    sudo systemctl reload caddy
    sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
    sudo ufw deny 51515/tcp && sudo ufw enable
    
    curl -v https://backup.example.com/api/v1/repo/status
    7

    Connect a Client

    From any machine with kopia installed
    kopia repository connect server \
      --url=https://backup.example.com \
      --override-username=alice \
      --override-hostname=laptop
    
    kopia snapshot create ~/Documents
    kopia policy set --global --keep-latest=10 --keep-hourly=24 --keep-daily=7

    The client never sees the backend credentials or the repository password — only its own htpasswd credential and the server URL.

    8

    Centralized Maintenance

    Make the server the maintenance owner
    sudo systemctl stop kopia-server
    sudo -iu kopia
    kopia maintenance set --owner=$(hostname)
    kopia maintenance set --enable-quick=true --enable-full=true
    kopia maintenance set --quick-interval=1h --full-interval=24h
    exit
    sudo systemctl start kopia-server

    Hardening Beyond Defaults

    • Object lock on B2 / S3 with retention exceeding your Kopia policy — strongest ransomware protection
    • Per-user ACLs via kopia server acl to scope users to their own sources
    • fail2ban on Caddy 401 responses
    • Off-host backup of /var/lib/kopia/.config/kopia/ (gpg-encrypted tar to a second bucket)