It’s weird living in Indonesia right now. Anyway, due to the Covid-19 outbreak, businesses are relying more and more to collaborative suites, such as slack, Microsoft Team and Office 365, Salesforce’s quip, Google suites, or even the infamous Zoom.

..or you can host one on your on-premise infrastructure if you can spare some resources. One of them is an Open Source Project called NextCloud.

In that regards, we’ll be attempting to deploy a stack of consisting of NextCloud, MySQL, and Traefik on top of Docker Swarm cluster.

Prereqs

Preparation is straightforward, and I will refer to some of my previous articles on how to configure these things:

Configuring the node(s)

Out of our three components, only the nextcloud instance will benefit from the swarm, as Traefik should only be deployed on the manager node of the swarm, and MySQL on one specific member node. Here’s how I setup my directory structure:

On the node that will host our database container:

mkdir /data
mkdir /data/nc
mkdir /data/nc/db
mkdir /data/nc/db/data

On the manager node of the swarm:

mkdir /data
mkdir /data/nc
mkdir /data/nc/traefik
mkdir /data/nc/traefik/configuration

Stacking

Here is my Docker Stack Compose script:

version: "3.3"

services:
  traefik:
    image: "traefik:v2.0.0"
    networks:
      - nextcloud_external
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker=true
      - --providers.docker.swarmMode=true
      - --providers.docker.network=nextcloud_external
      - --providers.docker.exposedbydefault=false
      - --providers.file.directory=/configuration/
      - --providers.file.watch=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "/data/nc/traefik/configuration/:/configuration/"
    deploy:
      placement:
        constraints:
          - node.role == manager
  app:
    image: nextcloud:latest
    networks:
      - nextcloud_external
    depends_on:
      - db
    volumes:
      - nextcloud:/var/www/html
      - /etc/localtime:/etc/localtime:ro
    environment:
      - VIRTUAL_HOST=nc.aeon.co.id
    deploy:
      replicas: 1
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.my-app.rule=Host(`nc.mach5.web.id`)"
        - "traefik.http.routers.my-app.entrypoints=websecure"
        - "traefik.http.routers.my-app.tls=true"
        - "traefik.http.services.my-app.loadbalancer.server.port=80"
        - "traefik.http.services.my-app.loadbalancer.sticky=true"
        - "traefik.http.services.my-app.loadbalancer.sticky.cookie.name=StickyCookie"
        - "traefik.http.services.my-app.loadbalancer.sticky.cookie.secure=true"
        - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
        - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
        - "traefik.http.routers.redirs.entrypoints=web"
        - "traefik.http.routers.redirs.middlewares=redirect-to-https"
  db:
    image: mysql:5.7
    networks:
      - nextcloud_external
    volumes:
      - /data/nc/db/data:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro
    environment:
      - MYSQL_ROOT_PASSWORD=pokopendarega
      - MYSQL_PASSWORD=tsuitsuita
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    deploy:
      placement:
        constraints:
          - node.labels.db == true
volumes:
  nextcloud:
networks:
  nextcloud_external:
     external: true

Before executing the stack deploy script above, we need to do some additional steps:

Docker

On the “networks” side of thing, we are going to use external overlay network that we need to create prior deploying the stack. To do that, do:

sudo docker network create --driver=overlay nextcloud_external

Traefik

I have finally moved on from 1.7 to 2.0. As you can see, we will be exposing port 80 (web) and 443 (websecure) to accept request from the internet with this command:

 - --entrypoints.web.address=:80
 - --entrypoints.websecure.address=:443

And integrate Traefik to Docker:

 - --providers.docker=true
 - --providers.docker.swarmMode=true
 - --providers.docker.network=nextcloud_external
 - --providers.docker.exposedbydefault=false

As you can see, we are telling our Traefik instance to run in Swarm Mode, and avoid exposing services by default.

Another important point is that I’m using the file providers to configure the certificate used by Traefik TLS termination.

 - --providers.file.directory=/configuration/ 
 - --providers.file.watch=true

The certificate configuration is stored on the host at “/data/nc/traefik/configuration” which is then mounted as “/configuration” on the Traefik containter. On the manager node of our swarm, do:

cd /data/nc/traefik/configuration/
sudo nano certificates.toml

This is how my certificates.toml looks like:

[[tls.certificates]]
   certFile = "/configuration/nc.mach5.web.id.pem"
   keyFile = "/configuration/nc.mach5.web.id.key"

Replace nc.mach5.web.id.pem and nc.mach5.web.id.key with your own certificate and key. Save and close the file. Finally, copy your SSL certificate and files to key files to /data/nc/traefik/configuration.

MySQL

The two things that we need to note on the configuration above is that MySQL data files will be locally stored on the node that we have selected to host the database container, and the deployment constraint will limit the database container generation on the node with specific label, in this case “db=true”. To complete the configuration, on the manager node do:

sudo docker node update --label-add db=true NC03

Also pay attention the password to the root account, the database name and account (and its’ password) that we will use later on to configure our NextCloud node.

NextCloud

There’s not much to discuss on the NextCloud side of things, so I’ll walk us through the Traefik labels that we are going to use on our NextCloud container(s). The most obvious thing that you can see is that we are putting “labels” as a subset of “Deploy” instead of its’ own thing. This is because, instead of the containters, what we need to label is the service. Now, onto those labels, shall we

 - "traefik.enable=true"
 - "traefik.http.routers.my-app.rule=Host(`nc.mach5.web.id`)"
 - "traefik.http.routers.my-app.entrypoints=websecure"
 - "traefik.http.routers.my-app.tls=true"

The first line basically tells our traefik instance to expose this service. The second line tells Traefik that the service will only receive traffic addressed to “nc.mach5.web.id”. The last two lines are how we are telling Traefik that the service should be served via https on port 443

 - "traefik.http.services.my-app.loadbalancer.server.port=80"
 - "traefik.http.services.my-app.loadbalancer.sticky=true"
 - "traefik.http.services.my-app.loadbalancer.sticky.cookie.name=StickyCookie"
 - "traefik.http.services.my-app.loadbalancer.sticky.cookie.secure=true"

Since we are using Swarm Mode, it’s necessary to explicitly tell Traefik the port that is used by our NextCloud instance. That’s what the first line is doing. The last 3 lines are the configuration for the loadbalancer session persistency.

 - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
 - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
 - "traefik.http.routers.redirs.entrypoints=web"
 - "traefik.http.routers.redirs.middlewares=redirect-to-https"

Finally, the last 4 lines configure http redirection to https.

Deploying the Stack

Save the docker stack compose script to a file, let say docker-compose.yaml. It’s time to deploy our stack. Do:

sudo docker stack deploy --compose-file=/data/nc/docker/compose/docker-compose.yaml next

To check whether the services are actually deployed, do:

surfer@NC03:~$ sudo docker service ls
[sudo] password for surfer: 
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
h7zndebzf48f        next_app            replicated          1/1                 nextcloud:latest    
e2jew4v224bp        next_db             replicated          1/1                 mysql:5.7           
dwlc1llodjbj        next_traefik        replicated          1/1                 traefik:v2.0.0      *:80->80/tcp, *:443->443/tcp, *:8080->8080/tcp

If everything is going according to the plan, we should see 3 services up there. Fire up your browser of choice, and navigate to our NextCloud deployment, and you’ll be greeted with this screen:

The first portion of the screen is where you configure the initial admin of our NextCloud instance. The next one is to configure the data folder, we can leave it as default. The last part of the setup screen is where we put our database credentials. Consult our docker compose file for the exact values. Press “Finish Setup” button to start the deployment. Once it’s completed, you should be transported to your default page:

And we’re done!

By ikhsan

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.