Skip to content

NextCloud Docker Compose / Swarm Install

NextCloud (now called "Nextcloud Hub II") has as grown from a humble fork of OwnCloud in 2016, to an industry-leading, on-premises content collaboration platform. NextCloud still does the traditional file-collaboration, but is now beefed-up with an app store supporting more than 100 apps, including text and video chats, calendaring, a mail client, and even an office editing suite.

It also now supports a sweet, customizable dashboard:

NextCloud Screenshot

This recipe uses the official NextCloud docker hub image, and includes separate docker containers for the database (MariaDB), Redis (for transactional locking), automated database backup, (you backup the stuff you care about, right?) and a separate cron container for running NextCloud's 15-min background tasks.

NextCloud Requirements

Ingredients

Already deployed:

Related:

Preparation

Setup data locations

We'll need several directories for static data to bind-mount into our container, so create them in /var/data/nextcloud (so that they can be backed up)

mkdir /var/data/nextcloud
cd /var/data/nextcloud
mkdir -p {html,apps,config,data,database-dump}

Now make more directories for runtime data (so that they can be not backed-up):

mkdir /var/data/runtime/nextcloud
cd /var/data/runtime/nextcloud
mkdir -p {db,redis}

Nextcloud environment variables

Create nextcloud.env, and populate with the following variables

/var/data/config/nextcloud/nextcloud.env
MYSQL_HOST=db
OVERWRITEPROTOCOL=https
REDIS_HOST=redis # (1)!

# For MariaDB
MYSQL_ROOT_PASSWORD=iliketogethaxed
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=haxmebaby
  1. Necessary to add Redis support

Now create a separate nextcloud-db-backup.env file, to capture the environment variables necessary to perform the backup. (If the same variables are shared with the mariadb container, they cause issues with database access)

/var/data/config/nextcloud/nextcloud-db-backup.env
# For database backup (keep 7 days daily backups)
MYSQL_PWD=<set to something secure, same as MYSQL_ROOT_PASSWORD above>
MYSQL_USER=root
BACKUP_NUM_KEEP=7
BACKUP_FREQUENCY=1d

Nextcloud Docker Compose

Create a docker swarm config file in docker-compose syntax (v3), something like the following example:

Fast-track with premix! 🚀

"Premix" is a git repository which includes necessary docker-compose and env files for all published recipes. This means that you can launch any recipe with just a git pull and a docker stack deploy 👍.

🚀 Update: Premix now includes an ansible playbook, enabling you to deploy an entire stack + recipes, with a single ansible command! (more here)

/var/data/config/nextcloud/nextcloud.yml
version: "3.0"

services:
  nextcloud:
    image: nextcloud
    env_file: /var/data/config/nextcloud/nextcloud.env
    networks:
      - internal
      - traefik_public
    deploy:
      labels:
      # traefik common
      - traefik.enable=true
      - traefik.docker.network=traefik_public

      # traefikv1
      - traefik.frontend.rule=Host:nextcloud.example.com
      - traefik.frontend.redirect.permanent=true
      - traefik.frontend.redirect.regex=https://(.*)/.well-known/(card|cal)dav
      - traefik.frontend.redirect.replacement=https://$$1/remote.php/dav/
      - traefik.port=80     

      # traefikv2
      - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.example.com`)"
      - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectRegex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.regex=^https://(.*)/.well-known/(card|cal)dav"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.replacement=https://$$1/remote.php/dav/"
      - "traefik.http.routers.nextcloud.middlewares=nextcloud-redirectregex@docker"

    volumes:
      - /var/data/nextcloud/html:/var/www/html
      - /var/data/nextcloud/apps:/var/www/html/custom_apps
      - /var/data/nextcloud/config:/var/www/html/config
      - /var/data/nextcloud/data:/var/www/html/data

  db:
    image: mariadb:10.5 #(1)!
    env_file: /var/data/config/nextcloud/nextcloud.env
    networks:
      - internal
    volumes:
      - /var/data/runtime/nextcloud/db:/var/lib/mysql

  db-backup:
    image: mariadb:10.5
    env_file: /var/data/config/nextcloud/nextcloud-backup.env
    volumes:
      - /var/data/nextcloud/database-dump:/dump
      - /etc/localtime:/etc/localtime:ro
    entrypoint: |
      bash -c 'bash -s <<EOF
      trap "break;exit" SIGHUP SIGINT SIGTERM
      sleep 2m
      while /bin/true; do
        mysqldump -h db --all-databases | gzip -c > /dump/dump_\`date +%d-%m-%Y"_"%H_%M_%S\`.sql.gz
        ls -tr /dump/dump_*.sql.gz | head -n -"$$BACKUP_NUM_KEEP" | xargs -r rm
        sleep $$BACKUP_FREQUENCY
      done
      EOF'
    networks:
      - internal

  redis:
    image: redis:alpine
    networks:
      - internal
    volumes:
      - /var/data/runtime/nextcloud/redis:/data

  cron:
    image: nextcloud
    volumes:
    - /var/data/nextcloud/html:/var/www/html
    - /var/data/nextcloud/apps:/var/www/html/custom_apps
    - /var/data/nextcloud/config:/var/www/html/config
    - /var/data/nextcloud/data:/var/www/html/data
    user: www-data
    networks:
      - internal
    entrypoint: |
      bash -c 'bash -s <<EOF
        trap "break;exit" SIGHUP SIGINT SIGTERM
        while [ ! -f /var/www/html/config/config.php ]; do
          sleep 1
        done
        while true; do
          php -f /var/www/html/cron.php
          sleep 15m
        done
      EOF'

networks:
  traefik_public:
    external: true
  internal:
    driver: overlay
    ipam:
      config:
        - subnet: 172.16.12.0/24
  1. MariaDB 10.5 is the latest supported version

Note

Setup unique static subnets for every stack you deploy. This avoids IP/gateway conflicts which can otherwise occur when you're creating/removing stacks a lot. See my list here.

Serving

Launch NextCloud Docker stack and setup

Launch the NextCloud stack by running docker stack deploy nextcloud -c <path -to-docker-compose.yml>

Log into your new instance at https://YOUR-FQDN, and setup your admin username and password.

Chef's notes 📓


  1. Since many of my other recipes use PostgreSQL, I'd have preferred to use Postgres over MariaDB, but MariaDB seems to be the preferred database type

  2. If you want better performance when using Photos in Nextcloud, have a look at this detailed write-up

Tip your waiter (sponsor) 👏

Did you receive excellent service? Want to compliment the chef? (..and support development of current and future recipes!) Sponsor me on Github / Ko-Fi / Patreon, or see the contribute page for more (free or paid) ways to say thank you! 👏

Employ your chef (engage) 🤝

Is this too much of a geeky PITA? Do you just want results, stat? I do this for a living - I'm a full-time Kubernetes contractor, providing consulting and engineering expertise to businesses needing short-term, short-notice support in the cloud-native space, including AWS/Azure/GKE, Kubernetes, CI/CD and automation.

Learn more about working with me here.

Flirt with waiter (subscribe) 💌

Want to know now when this recipe gets updated, or when future recipes are added? Subscribe to the RSS feed, or leave your email address below, and we'll keep you updated.

Your comments? 💬