Skip to content

Nextcloud · deploy guide

Self-host Nextcloud on a VPS with Docker Compose and Caddy

Run Nextcloud (files, calendar, contacts) on a bashrack VPS with MariaDB, Redis and automatic HTTPS from Caddy.

about 20 minutes of hands-on time

Who it's for

Families and teams replacing a public cloud drive with storage they control.

You'll need

  • An Ubuntu or Debian VPS with your SSH key
  • A domain, e.g. cloud.example.com, with an A record to the VPS IP

Steps

  1. step 1

    Open only SSH and HTTPS

    Enable the firewall before exposing anything. Port 80 is needed for the certificate challenge and the redirect to HTTPS.

    bash
    sudo apt-get update && sudo apt-get install -y ufw
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw --force enable
  2. step 2

    Install Docker

    Log in to the VPS as your sudo user and install Docker Engine with the official convenience script, then allow your user to run it.

    bash
    curl -fsSL https://get.docker.com | sudo sh
    sudo usermod -aG docker "$USER"
    newgrp docker
    docker compose version
  3. step 3

    Create the Compose stack

    Create a directory with the Compose file and a Caddyfile. Caddy obtains and renews the certificate automatically.

    yaml
    # ~/nextcloud/compose.yaml
    services:
      db:
        image: mariadb:lts
        restart: unless-stopped
        command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
        environment:
          MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
          MYSQL_DATABASE: nextcloud
          MYSQL_USER: nextcloud
          MYSQL_PASSWORD: ${DB_PASSWORD}
        volumes:
          - db:/var/lib/mysql
      redis:
        image: redis:alpine
        restart: unless-stopped
      app:
        image: nextcloud
        restart: unless-stopped
        depends_on: [db, redis]
        environment:
          MYSQL_HOST: db
          MYSQL_DATABASE: nextcloud
          MYSQL_USER: nextcloud
          MYSQL_PASSWORD: ${DB_PASSWORD}
          REDIS_HOST: redis
          NEXTCLOUD_TRUSTED_DOMAINS: ${DOMAIN}
          OVERWRITEPROTOCOL: https
        volumes:
          - nextcloud:/var/www/html
      caddy:
        image: caddy:2
        restart: unless-stopped
        ports:
          - 80:80
          - 443:443
        volumes:
          - ./Caddyfile:/etc/caddy/Caddyfile:ro
          - caddy_data:/data
    volumes:
      db:
      nextcloud:
      caddy_data:
  4. step 4

    Add the Caddyfile and secrets

    Replace the domain, then generate the passwords into a .env file next to compose.yaml.

    bash
    cd ~/nextcloud
    cat > Caddyfile <<'EOF'
    cloud.example.com {
        reverse_proxy app:80
    }
    EOF
    cat > .env <<EOF
    DOMAIN=cloud.example.com
    DB_PASSWORD=$(openssl rand -hex 24)
    DB_ROOT_PASSWORD=$(openssl rand -hex 24)
    EOF
  5. step 5

    Start and finish the installer

    Start the stack, open https://cloud.example.com and create the admin account in the web installer.

    bash
    docker compose up -d
    docker compose logs -f app

Security and upkeep

  • Finish the web installer immediately so nobody else can create the admin account.
  • Back up the nextcloud and db volumes; files live in the nextcloud volume.
  • Upgrade one major version at a time, as Nextcloud requires.

Official documentation