Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nextcloud-object-storage #978

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 279 additions & 0 deletions tutorials/nextcloud-hetzner-object-storage/01.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
---
SPDX-License-Identifier: MIT
path: "/tutorials/nextcloud-hetzner-object-storage"
slug: "nextcloud-hetzner-object-storage"
date: "2024-11-13"
title: "Setup Nextcloud with S3-compatible object storage"
short_description: "This tutorial explains how to install Nextcloud via Docker Compose and setup S3-compatible object storage as a storage backend."
tags: ["Docker", "Nextcloud", "Object Storage"]
author: "Silviu Vulcan"
author_link: "https://github.com/filviu"
author_img: "https://avatars3.githubusercontent.com/u/2470335"
author_description: ""
language: "en"
available_languages: ["en"]
header_img: "header-7"
cta: "cloud"
---

## 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/](https://docs.nextcloud.com/server/latest/admin_manual/).

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

**Prerequisites**

* A server (e.g. with [Hetzner Cloud](https://www.hetzner.com/cloud/))
* A S3-compatible bucket (e.g. with [Hetzner](https://www.hetzner.com))
* 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](https://docs.hetzner.com/storage/object-storage/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](https://docs.hetzner.com/storage/object-storage/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](https://docs.hetzner.com/cloud/servers/getting-started/creating-a-server)"). If you want to install Docker and Docker Compose manually, follow the [official Docker documentation](https://docs.docker.com/engine/install/) 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:

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

### Step 3.1 - Create deployment and configuration files

`vim /opt/nextcloud/compose/compose.yaml`

```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`:

```ini
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`

```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`

```ini
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

```bash
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:

```php
'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](https://docs.hetzner.com/cloud/load-balancers/getting-started/creating-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

<!--

Contributor's Certificate of Origin

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I have
the right to submit it under the license indicated in the file; or

(b) The contribution is based upon previous work that, to the best of my
knowledge, is covered under an appropriate license and I have the
right under that license to submit that work with modifications,
whether created in whole or in part by me, under the same license
(unless I am permitted to submit under a different license), as
indicated in the file; or

(c) The contribution was provided directly to me by some other person
who certified (a), (b) or (c) and I have not modified it.

(d) I understand and agree that this project and the contribution are
public and that a record of the contribution (including all personal
information I submit with it, including my sign-off) is maintained
indefinitely and may be redistributed consistent with this project
or the license(s) involved.

Signed-off-by: Silviu Vulcan, https://github.com/filviu/

-->