Minimal effort, maximum personal cloud infrastructure

Introduction

I never really enjoy blogs with paragraphs of philosophical explanations of why one should use the presented solution so I’ll get down to business right away and address some of the philosophy later.

Goal

To create as much high quality personal (cloud) infrastructure with as little effort as possible.

I’ll focus on getting Nextcloud running as minimum viable personal cloud infrastructure (MVPCI). The methods used to get Nextcloud running are easily extended to other services as well, I’ll present some examples later on.

Hardware

I recently bough new-home server hardware, the goal was to strike a balance between power and power consumption. These are the specs:

Part Model Price Date purchased
CPU Intel Core i3-9100 Boxed €122.32 2020-12-15
Motherboard Fujitsu D3644-B €157.45 2020-12-15
RAM Crucial CT2K8G4DFS824A €57.45 2020-12-15
Power Supply be quiet! Pure Power 11 400W €53.91 2020-12-15
SSD Samsung 970 EVO 1TB €125 2020-12-15
Case Fractal Design Define R3 €93.50 2010-12-23
Total €609.63
The URLs link to tweakers.net’s price comparison section, this is a popular comparison site for hardware in the Netherlands. I didn’t include any cables, since the motherboard is for OEMs, it does not come with any but I had them lying around from my previous server build.

Tools

Linux

I’ll use Ubuntu Desktop because I can get it up and running within about 10 min and so far it has worked flawlessly on any hardware I tried it on (and indeed it works perfectly with the hardware mentioned above). Ubuntu Desktop presents a desktop so I can easily open some terminals and drag some files around and use VNC to do the same after I stowed the server away in the basement. But since we are going to use Docker Compose, it really does not matter which distribution you choose; after you booted it, everything will be the same as described here.

Docker Compose

When I first tried to use Docker for my personal infrastructure, I concluded that it make things more complicated. When I first heard the term Docker Compose, I thought “hmm, another layer of complexity”, but no, Docker Compose = Docker for Dummies. One can simply write down (in Yaml) what services one wants and Docker Compose will download them down and make them run.

Traefik proxy

Traefik is a reverse proxy and can seamlessly integrate Let’s Encrypt to get you valid certificates for your (sub) domains. It can be fully configured from within a Docker Compose yaml file and allows you to run multiple services in the same port, routing requests based on the contacted (sub) domain.

VSCode (optional)

Whenever I work on a server, I use VSCode with the remote-ssh plugin, then I can open files on the remote server and start using them in a ssh session directly. I highly recommend it. Does require you apt install openssh-server on the server.

Building your personal infrastructure

Getting the Linux Server up and running

Pick whatever GNU/Linux distribution that you prefer, and install it on your hardware.

Install Docker and Docker Compose

Both Docker and Docker Compose are best installed not from your distributions repositories (unless you run Arch maybe) but using direct methods. First we install Docker (instructions optimized for Ubuntu 20.04) (source: digitalocean.com/community/tutorials), run the following commands in succession, see the source for more details

sudo apt update

sudo apt install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

sudo apt update

apt-cache policy docker-ce

sudo apt install docker-ce

sudo usermod -aG docker ${USER}

su - ${USER}

Verify that you can use docker by issuing the following command, you should see a version number printed

docker --version

Now we install Docker Compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/

docker-compose

sudo chmod +x /usr/local/bin/docker-compose

Verify that you can use docker-compose by issuing the following command, you should see a version number printed

docker-compose --version

Running Nextcloud

Make a new directory, the name is not important, I usually use “docker”

mkdir docker

Open a text file called docker-compose.yaml and paste the following content into it:

version: "3.9"
services:
  traefik:
    image: traefik:latest
    container_name: traefik
    command:
      - --log.level=DEBUG
      - --api.insecure=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.mytlschallenge.acme.tlschallenge=true
      - --certificatesresolvers.mytlschallenge.acme.email=you@email.nl
      - --certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json
      - --serversTransport.insecureSkipVerify=true
    ports:
      - 80:80
      - 443:443
      - 8888:8080
    volumes:
      - ./letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro

  nextcloud_db:
    container_name: nextcloud_db
    image: mariadb
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    volumes:
      - ./cloud.yourdomain.nl/db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=your_MYSQL_ROOT_PASSWORD
      - MYSQL_PASSWORD=your_MYSQL_PASSWORD
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

  nextcloud_app:
    container_name: nextcloud_app
    image: nextcloud
    restart: always
    depends_on:
      - nextcloud_db
    volumes:
      - ./cloud.yourdomain.nl/nextcloud:/var/www/html
    environment:
      - MYSQL_PASSWORD=your_MYSQL_PASSWORD
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=nextcloud_db
    labels:
      - traefik.enable=true
      - traefik.http.routers.nextcloud_app-http.entrypoints=web
      - traefik.http.routers.nextcloud_app-http.rule=Host(`cloud.yourdomain.nl`)
      - traefik.http.routers.nextcloud_app-http.middlewares=nextcloud_app-https
      - traefik.http.middlewares.nextcloud_app-https.redirectscheme.scheme=https
      - traefik.http.routers.nextcloud_app.entrypoints=websecure
      - traefik.http.routers.nextcloud_app.rule=Host(`cloud.yourdomain.nl`)
      - traefik.http.routers.nextcloud_app.tls=true
      - traefik.http.routers.nextcloud_app.tls.certresolver=mytlschallenge

But before we can use this we need to do some things.

  • Make sure you have a valid A record for your (sub) domain pointing to the IP address of your server.
  • Set port-forwarding on you router such that requests on ports 80 (http) and 443 (https) point to the IP address of your server. It’s best if you also give it a fixed IP address within your network.
  • Replace the following values in the yaml text:
    • you@email.nl: your email address
    • your_MYSQL_ROOT_PASSWORD: A mysql root password, it can be whatever you want
    • your_MYSQL_PASSWORD: The password for the nextcloud mysql user, make up a nice one
    • cloud.yourdomain.nl: Set the domainname you made an A record for, pointing to your server

Save the modified file. Now we are ready to pull down and start Nextcloud by issuing:

docker-compose up -d

You will see the containers being pulled down. When they are started, visit your Nextcloud install on https://cloud.yourdomain.nl.