Nextcloud as a private file storage

Why Nextcloud

Nextcloud is a well-known private file cloud, that can be hosted on any your server. It’s also interesting for having clients to run on almost all platforms.

This cloud did much about security. The other side of this is the requirement to run Nextcloud under HTTPS protection, it can’t be used under unencrypted HTTP. Here provided the info on how to set it up behind quite complicated nginx-proxy-letsencrypt-companion, but it’s not my favourite solution, I like traefik much more. Here we’ll describe how did I set up Nextcloud with Traefik proxying.

Traefik configuration

First, you should create traefik/traefik.toml and traefik/acme.json files as described here. The traefik.toml that I used for Nextcloud:

logLevel = "ERROR"
defaultEntryPoints = ["http","https"]

[accessLog]
  filePath = "/dev/stdout"

[traefikLog]
   filePath = "/dev/stdout"

[entryPoints]
  [entryPoints.http]
    address = ":80"
  [entryPoints.https]
    address = ":443"
  [entryPoints.https.tls]

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "mszuyev.xyz"
watch = true
exposedbydefault = false

[acme]
email = "[email protected]"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true

[acme.httpChallenge]
entryPoint = "http"

Comparing to traefik.toml from here - only [docker].domain and [acme].email fields have changed, everything else remain intact.

Final docker-compose.yml (docker-compose.override.yml) part
version: '3.7'

services:
  traefik:
    image: traefik:alpine
    container_name: traefik
    command: --configFile=/traefik.toml
    restart: unless-stopped
    networks:
      - main
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik/traefik.toml:/traefik.toml
      - ./traefik/acme.json:/acme.json
    labels:
      - "traefik.enable=false"
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - db:/var/lib/mysql
    networks:
      main:
        ipv4_address: 172.31.0.31
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
  redis:
    image: redis:alpine
    container_name: redis
    restart: always
    networks:
      - main

  app:
    image: nextcloud
    links:
      - redis
    container_name: nextcloud
    environment:
      - REDIS_HOST=redis
    volumes:
      - nextcloud:/var/www/html
    networks:
      - main
    labels:
      - "traefik.enable=true"
      - "traefik.port=80"
      - "traefik.docker.network=main"
      - "traefik.frontend.rule=Host:$CLOUD_DOMAIN"
      - "traefik.frontend.headers.SSLRedirect=true"
      - "traefik.frontend.headers.SSLForceHost=true"
      - "traefik.frontend.priority=1"
    restart: always

volumes:
  nextcloud:
  db:

networks:
  main:
    external: true

Here $CLOUD_DOMAIN is a domain where our Nextcloud server is publicly available. It also should be used above in traefik/traefik.toml configuration

I used a static IPv4 address for MySQL server because Nextcloud can’t access MySQL server for some unknown (for me, of course) reason. Keep in mind that assigning static IPs is available only for custom networks, created with explicitly specfied subnet - that’s why we describe “main” network as external. To create it, run

docker network create --subnet="172.31.0.0/16" --gateway="172.31.0.1" main

Of course, you can use more narrow subnet, for example, 172.31.0.0/24.

Also, create .env file in the same dir as docker-compose.yml:

MYSQL_ROOT_PASSWORD=<YOUR_MYSQL_ROOT_PASSWORD>
Trouble shooting

In some cases you can get an infinite login procedure sequence (login page -> enter login && pass -> hit Enter -> login page -> enter login && pass -> hit Enter -> …) - here, for example, this problem has mentioned and the solution they suggest is to edit the Nextcloud config.

So, you need to replace

  'overwrite.cli.url' => 'https://$CLOUD_DOMAIN',

in the config/config.php file of your Nextcloud to

  'overwrite.cli.url' => 'https://$CLOUD_DOMAIN/',
  'overwritehost' => '$CLOUD_DOMAIN',
  'overwriteprotocol' => 'https',

Then, probably, the problem will go away.

The another possible reason is when you submitting your form, the error of kind “Refused to send form data to ‘http://cloud.domainname/' because it violates the following Content Security Policy directive: “form-action ‘self’”” occurs in your browser console. I actually don’t know the solution, and there are only two things that worked for me:

  • connect to the VPN, clean cookies and try again. Here is a brief help how to set up VPN on any VPS.
  • connect to another network, clean cookies and try again

The info from here, here, and so on - didn’t work for me, probably I’ve worked with insecure networks or incorrect routing (in 100% cases these issues was in public networks).