Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Setup Nextcloud with S3-compatible object storage

profile picture
Author
Silviu Vulcan
Published
2024-12-03
Time to read
8 minutes reading time

Introduction

This tutorial will guide you to setup Nextcloud on a server using Docker Compose and S3-compatible object storage as a storage backend. The advantages of using an object storage as opposed to a bigger cloud server or a big volume is that you don't have to reserve and pay for capacity in advance and it can grow organically.

Nextcloud administration is a big topic. This tutorial will focus on using the Hetzner Object Storage as a backend and start a regular installation. This can be improved and extended by following the official Nextcloud documentation at https://docs.nextcloud.com/server/latest/admin_manual/.

The Docker images we will be using are further documented here: https://github.com/nextcloud/docker

Prerequisites

  • A server (e.g. with Hetzner Cloud)
  • A S3-compatible bucket (e.g. with Hetzner)
  • A domain you want to use for your Nextcloud instance (e.g. nextcloud.example.com) ideally with its DNS hosted with Hetzner.

Example terminology

  • Server IP: <server-ip>
  • Domain: nextcloud.example.com

Step 1 - Create Object Storage Bucket

Create a S3-compatible bucket. With Hetzner, see the getting started "Creating a Bucket". Give it a name, preferably a random UUID, like one returned by running uuidgen. Make sure it is set to private access permissions. We will refer to this bucket as <object-storage-bucket-name> in the following steps.

Create S3 credentials to access your bucket. With Hetzner, see the getting started "Generating S3 keys". Give the set a descriptive name e.g. nextcloud. Save the keys in a secure place (e.g. your password manager) as they are not retrievable once the popup is closed.

Further on we will refer to those credentials as <object-storage-access-key> and <object-storage-secret-key>.

Step 2 - Create Server

Create a new server. With Hetzner, you can select the Docker CE app as your image, so you don't need to install Docker yourself (see the getting started "Creating a Server"). If you want to install Docker and Docker Compose manually, follow the official Docker documentation after the server was created.

Select an appropriate machine size for your Nextcloud instance preferably from the same location as your storage bucket. Don't select the machine size based on root disk size, we won't be using that for data storage, just RAM and CPU.

Select or add your SSH public key.

Select or create an appropriate firewall. If you use a Hetzner cloud server and you will be following the optional step below of adding a Hetzner Load Balancer, you can deny access from everywhere except SSH from your location.

Step 3 - Deploy Nextcloud

SSH to your server ssh root@<server-ip>.

Create a directory for your Docker Compose files and folders for the persistent storage of the Nextcloud containers:

mkdir -p /opt/nextcloud/redis
mkdir -p /opt/nextcloud/compose

Step 3.1 - Create deployment and configuration files

vim /opt/nextcloud/compose/compose.yaml

services:
  db:
    image: mariadb:10.6
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    volumes:
      - "/opt/nextcloud/mysql:/var/lib/mysql"
    environment:
      - MYSQL_HOST=db
      - MYSQL_ROOT_PASSWORD=${NC_MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=${NC_MYSQL_PASSWORD}
  mysqlbackup:
    image: selim13/automysqlbackup:2.7.0
    restart: always
    volumes:
      - "/opt/nextcloud/mysql-backups:/backup"
    environment:
      CRON_SCHEDULE: "0 */4 * * *"
      USERNAME: "root"
      PASSWORD: "${NC_MYSQL_ROOT_PASSWORD}"
      DBHOST: "db"
      DBEXCLUDE: "performance_schema information_schema"
      EXTRA_OPTS: "--single-transaction"
    depends_on:
      - db
  redis:
    image: redis:alpine
    restart: always
    depends_on:
      - app
    volumes:
      - "/opt/nextcloud/redis:/data"
    environment:
      - REDIS_HOST=redis
      - REDIS_HOST_PORT=6379
    entrypoint: redis-server /data/redis.conf
  app:
    image: nextcloud:30
    restart: always
    environment:
      - NEXTCLOUD_ADMIN_USER=admin
      - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=${NC_MYSQL_PASSWORD}
      - REDIS_HOST=redis
      - REDIS_HOST_PORT=6379
      - REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
      - PHP_MEMORY_LIMIT=2G
      - PHP_UPLOAD_LIMIT=15G
      - OBJECTSTORE_S3_BUCKET=${OBJECTSTORE_S3_BUCKET}
      - OBJECTSTORE_S3_HOST=${OBJECTSTORE_S3_HOST}
      - OBJECTSTORE_S3_KEY=${OBJECTSTORE_S3_KEY}
      - OBJECTSTORE_S3_SECRET=${OBJECTSTORE_S3_SECRET}
      - OBJECTSTORE_S3_SSL=true
      - OBJECTSTORE_S3_PORT=443
    ports:
      - "80:80"
    volumes:
      - "/opt/nextcloud/html:/var/www/html"
      - "/opt/nextcloud/redis/redis-session.ini:/usr/local/etc/php/conf.d/redis-session.ini"
    depends_on:
      - db

Notes for the compose file above:

  • it includes automysqlbackup in order to generate regular snapshots of the database. If you use different backup methods, you might want to remove it
  • it uses the major version tag of the Nextcloud Docker image — 30 at the time of editing. This means it will update to whatever 30.x.x versions will be released but will require you to actively change it to 31, etc. when a next major version lands. This is by design, major version upgrades might need migration steps.

Create an .env file and add the following variables:

vim /opt/nextcloud/compose/.env:

COMPOSE_PROJECT_NAME=nextcloud

NC_MYSQL_ROOT_PASSWORD=mysql_securepass
NC_MYSQL_PASSWORD=mysql_pass

REDIS_PASSWORD=redispass

NEXTCLOUD_ADMIN_PASSWORD=ncpass

OBJECTSTORE_S3_HOST=fsn1.your-objectstorage.com
OBJECTSTORE_S3_BUCKET=<object-storage-bucket-name>
OBJECTSTORE_S3_KEY= <object-storage-access-key>
OBJECTSTORE_S3_SECRET=<object-storage-secret-key>

You will of course need to generate stronger passwords than the one in the .env example above.

Redis configuration files:

vim /opt/nextcloud/redis/redis-session.ini

session.save_handler = redis
session.save_path = "tcp://redis:6379?auth=redispass"
redis.session.locking_enabled = 1
redis.session.lock_retries = -1
redis.session.lock_wait_time = 10000

vim /opt/nextcloud/redis/redis.conf

dir /data
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
requirepass "redispass"

Note: Be sure to use exactly the same password for redis in those two configuration files as in the .env file above!

Step 3.2 - Start Nextcloud

cd /opt/nextcloud/compose
docker-compose up -d    # OR
docker compose up -d    # Depending on the way you installed Docker Compose

Edit /opt/nextcloud/html/config/config.php and add your trusted domains. The trusted_domains array should be similar to:

  'trusted_domains' => 
  array (
    0 => 'localhost',
    1 => '<server-ip>',
    2 => 'nextcloud.example.com',
  ),

In a browser, navigate to http://<server-ip>/ and verify that you can login using admin and the password set for NEXTCLOUD_ADMIN_PASSWORD in .env.

Note: If you navigate to http://something, modern browsers will immediately redirect to https://something if the response is not immediate. So while waiting for your containers to start, you will need to re-type (paste) http://<server-ip>/ instead of hitting reload.

Navigate to your bucket and doublecheck that files have appeared after you successfully logged in to your Nextcloud instance.

Step 4 - Add a Hetzner Load Balancer (Optional)

If you used a Hetzner cloud server, you can put it behind a Hetzner Load Balancer. To route via a private IP, create a new private Network, e.g. network-nextcloud, and attach your Nextcloud server to that Network.

Now create a Load Balancer:

  • Select the private Network of the Nextcloud server.

  • For Targets, select Cloud Servers and select the cloud server created in step 2.

  • Under Services select:

    • Protocol: https
    • Source port: 443
    • Destination port: 80

    Select + Add certificates. If example.com is configured in Hetzner DNS, you can select "Create certificate". Either nextcloud.example.com or a wildcard certificate like *.example.com will do.

Click on Create & Buy now.

Click on your newly created Load Balancer, Services then the edit pen-icon to set the health check advanced settings. Under domain, fill out nextclout.example.com. This is needed because the healthcheck is running via the private Network and the private IP of your server is not among the trusted domains.

This will only work if example.com is configured in Hetzner DNS. If not, or you prefer something like caddy or nginx-proxy-manager, you will have to adjust accordingly the way you setup SSL termination.

No matter your method, it is highly recommended to use SSL for your Nextcloud instance.

Conclusion

You are now the owner of a performant and extensible private cloud solution that is completely open source and free from tracking by big corporations.

But with great power comes great responsibility. As mentioned in the introduction, Nextcloud is a big topic so you are advised to consult the official documentation on further steps to improve and secure your instance. Ensuring firewall rules are correct, enabling 2FA for accounts and keeping your installation up-to-date are only the basics of a secure Nextcloud installation.

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get €20/$20 free credit!

Valid until: 31 December 2024 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more