Selfhosting a cloud. Part 3: Nextcloud - everything you need and more

Selfhosting a cloud

  1. Basic setup
  2. Reverse Proxy with Traefik v2
  3. Secure your services with HTTPS
  4. Nextcloud - everything you need and more (this post)
  5. Some nice services you might want
  6. Use keycloak for user management and SSO

Disclaimer

Due to how disorganised I am, there will be a lot of tangents and (more or less) off-topic paragraphs.

Any paragraph that looks like this is one of those paragraphs. You can ignore them and information on this page will still make sense.

I will sometimes use these paragraphs to explain something in more details.

Short intro to Nextcloud

Nextcloud started as a fork of Owncloud. They both allow anyone to easily setup a cloud file storage server. While Owncloud aims to replace services like Dropbox or Google Drive, Nextcloud expands on the whole "cloud" idea. Currently Nextcloud can replace most of the G-Suite (Google's all-in-one solution for business and enterprise): file storage, image management, music library (using your own music files), calendar, contacts, document editing, instant messaging (including voice and video calling) and much, much more.

The only thing that's really missing is a mail server, however given how easy it is to set up your own mail server, I don't think that's necessary.

It also lets anyone create their own plug-ins (called "apps") which can provide almost anything you might need.

I'm often using "containers" and "images" interchangeably. I know that they are not the same, however for the purpose of this guide the differences are irrelevant.

Run Nextcloud in Docker

Choose which container to use

If you were to google "Nextcloud docker" you would quickly find that there are two dominant containers which provide Nextcloud. One of them is the official container created by Nextcloud developers. The other one is created by Linuxserver, a group of developers who provide high quality containers for a lot of different apps.

It doesn't really matter which one you choose. They both give you a Nextcloud installation with the exact same features. There are some differences, though:

Ultimately the decission is yours. I prefer the Linuxserver container, so that's what I'll be using in this guide.

Writing a docker-compose file

Create a new folder to store your Nextcloud installation. In it create a docker-compose.yml file.

Let's start by pasting an empty skeleton with no services:


version: "3"
services:

networks:
  proxy:
    external: true

Now let's start by creating a database container. Nextcloud supports PostgreSQL and MySQL/MariaDB. I like MariaDB, so I'll be using that. You can choose whatever you want, but be aware that initial configuration for those containers can be different from what I write below.

The service definition isn't too complicated:


nc_db:
  # I know that using 'latest' tag is not recommended, but whatever
  image: mariadb
	container_name: nc_db
This is the bare minimum to run a database. Unfortunately, this will not work for us.

First, we need to use a volume for the database itself. Without it every time the container restarts all data would be lost. It's also a good idea to have the container worry about setting root (admin) password, creating a user for Nextcloud and creating an actual database based on environment variables. And it would be nice if the container restarted automatically after reboots.

In order to do all that we need to expand the docker compose file a bit:


version: "3"
services:
  nc_db:
	  image: mariadb
		container_name: nc_db
		env_file:
		  - nc.env # We'll create this file in a minute
		volumes:
		  - nc_db_data:/var/lib/mysql
		networks:
		  - nc
		restart: unless-stopped

volumes:
  nc_db_data:

networks:
  nc:
	proxy:
	  external: true
The only thing you might not know from before is the volumes: section. This allows you to create new volumes (persistent storage) managed by docker. By not providing any configuration to nc_db_data we tell docker-compose to use defaults, which work for 99% of cases.

Same goes for the networks: section. We need a network so that the database container and Nextcloud container can talk to each other. By default docker-compose puts every container from a single file in the same network, however the Nextcloud container will have to be in the proxy network so that it can be proxied by Traefik.

The env_file section might also be new to you. It simply lets you store environment variables in a separate file. This is really useful if you want to share your docker-compose files without worrying about leaking passwords.

You can run docker-compose config to verify the file.

Environment file

The nc.env file uses a key-value pair format. The contents of this file are as follows:


MYSQL_ROOT_PASSWORD=[Strong-and-complicated-password-123!@#]
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=[another-strong-password]

Nextcloud container

Like I said before, we'll be using Linuxserver image in this guide. Add the following service definition to docker-compose.yml:


nextcloud:
  image: linuxserver/nextcloud
	container_name: nextcloud
	volumes:
	  - ./data/data:/data # Yo dawg, I heard you like data...
		- ./data/conf:/config
  networks:
	  - proxy
		- nc
  environment:
	  - PUID=1000
		- PGID=1000
		- TZ={{TIMEZONE}}
  restart: unless-stopped
I didn't include Traefik configuration just yet, as it's a bit complex. Right now I want to focus on Nextcloud itself.

You can change the volumes section so that it uses docker volumes for /data and /config instead of local directories, but this way makes backing up easier - just tar the whole data folder and store it somewhere safe.

The environment variables PUID and PGID make it so that you can read and write directly to the data folder. TZ is your Time zone. Set it according to this table to make sure the container has correct date and time.

Apply Traefik proxy

Due to how Nextcloud works the Traefik configuration isn't as straightforward as it is for most applications:


labels:
  - "traefik.enable=true"
  - "traefik.http.routers.cloud.entrypoints=https"
  - "traefik.http.routers.cloud.rule=Host(`cloud.example.com`)"
  - "traefik.http.routers.cloud.tls=true"
  - "traefik.http.services.cloud.loadbalancer.server.port=443"
  - "traefik.http.services.cloud.loadbalancer.server.scheme=https"
  - "traefik.http.middlewares.nextcloud.headers.customFrameOptionsValue=ALLOW-FROM https://cloud.example.com"
  - "traefik.http.middlewares.nextcloud.headers.contentSecurityPolicy=frame-ancestors 'self' example.com,*.example.com"
  - "traefik.http.middlewares.nextcloud.headers.stsSeconds=155520011"
  - "traefik.http.middlewares.nextcloud.headers.stsPreload=true"
  - "traefik.http.middlewares.nextcloud-redirect.redirectregex.regex=/.well-known/(card|cal)dav"
  - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.regex=/.well-known/webfinger"
  - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.replacement=/public.php?service=webfinger"
  - "traefik.http.middlewares.nextcloud-redirect.redirectregex.replacement=/remote.php/dav"
  - "traefik.http.routers.cloud.middlewares=nextcloud,nextcloud-redirect,nextcloud-webfinger"
The first 5 lines you should be familiar with. Enable Traefik, listen on HTTPS for this domain and TLS. Container listens on port 443.

The next line means that the container expects to get HTTPS requests instead of HTTP (the port doesn't matter here). I have no idea why Linuxserver set it that way, but whatever. The next lines create and apply some middlewares, which set some headers for usage with other apps, and redirect some specific paths to correct destinations.

Running and testing everything

Start the containers with docker-compose up -d and go to cloud.example.com (or whatever you configured in the Host rule). Go through the installation wizard choosing the correct database. Set the data folder to /data.

The database host is nc_db and the database and username are both nextcloud using the password you set in MYSQL_PASSWORD.

You might want to untick the "Install recommended apps" checkbox. If it's checked then Nextcloud will install some apps you might not need, as well as a server for Onlyoffice or Collabora. Both of these servers are useless for real world usage and you can install Collabora in docker later.

Adding some recommended configuration to config.php

While this step isn't usually needed, it can help with some issues. Edit the file data/conf/www/nextcloud/config/config.php. The two important settings are trusted_domains and overwrite.cli.url.

The trusted_domains should be an array containing your domain. For example:


'trusted_domains' =>
  array (
    0 => 'cloud.example.com',
	),

overwrite.cli.url should be the full URL of your Nextcloud instance, for example:


'overwrite.cli.url' => 'https://cloud.example.com',

The one good thing about PHP is that you don't have to restart anything. Save and exit from the config file and refresh the page in your browser. If everything still works, then we're pretty much done.

The end

As you can see, installing Nextcloud is really easy, and it's probably one of the more difficult services to install. Most services will be installed in almost the same way: define the service, add database, create necessary volumes, add Traefik labels, and just docker-compose up -d.

Now all that's left for you is to go through available apps and installing the ones you want.

Addendum

If you want to use a centralised service for user management in Nextcloud and other services, you might want to look into Keycloak (which I'll cover in part 6) or Active Directory/OpenLDAP (which I'll cover if/when I get it working). In any case, I recommend you don't use Nextcloud too much untill you have the user management working, as messing with users can lead to data loss.