Getting Started with Docker for Self Hosting All The Things

There is no doubt about it, if you're setting up a new server today to run your website or any service really you should be using Docker. The only problem is if you haven't used it before it is a little intimidating. I've been using Docker for the past couple years as in restarting containers and tweaking things here and there but this year I really decided to take the dive and learn all I could. Now that it has "clicked" in my head I wouldn't imagine running servers any other way.

I've found the best way to learn is to take an old computer you have laying around and install Ubuntu Server on it, if you don't have that option you could run something in AWS, a Raspberry PI (won't have the best performance depending on what you're doing) or even run a VM on your computer. I think it's best to have a solution that can be always on so you always have your Docker services running.

The next thing to do is to figure out what you need to run on a server so you have a reason at all to do this. Great resources for finding self hosted software are the Awesome-Selfhosted git repo and I like the /r/selfhosted subreddit. Across my servers I run the following in Docker; Plex, Minecraft, Nextcloud, Gitea, Rocket.Chat, DokuWiki and this website. I run more but those are probably good places to start and things you might interested in running as well.

For this tutorial we will focus on running DokuWiki because it's a singe container already setup that we don't need to build ourselves, we can make it world facing using nginx, give it a SSL with letsencrypt and is something you can do that's useful to store information in an organized matter. All files created in this tutorial are available on this gist.

Configuring your Ubuntu Server

There are many tutorials on how to install Ubuntu, and these days it's so easy you shouldn't need a tutorial, just plug in your USB installer and follow the prompts. After it's installed, now what? For the purposes of this tutorial the only extra things you will need are Docker itself. I personally am not a fan of installing Docker through the Ubuntu setup and running the Snap version of it, but you can if you want, if not you can follow Docker's tutorial on installing Docker. When you're done running docker ps should output the following, showing nothing is currently running.

That image above means you are successfully running Docker, it's just not doing anything yet! Next step is to get Docker Compose installed, which luckily is just a one liner you paste into your terminal and you're good to go.

The only other configuration you need to do is decide where on your server you want all your docker things to live. I put all of my docker things in /opt/docker-compose which is standardized for all my servers so if I SSH into one I know where I need to go. For this tutorial I'll assume that's what you're using but you can put them wherever you'd like.

Creating your Docker Compose file

Docker compose lets you have a YAML file that tells Docker what servers to spin up and what to do with them. This is super useful as YAML is built to be readable to anyone so it's not some new complicated thing you need to learn to manage your servers.

For DockuWiki I did some duckduckgoing for a docker container for DockuWiki and ran into one called ericbarch/dockuwiki which points at a git repo and auto pushes any changes you make back to that git repo, which is exactly what I wanted, so we'll use that.

Before we go too far into setting up DockuWiki there are some base things we will need for our Docker Compose file. We will need nginx-proxy and letsencrypt, which will let us serve up our website and gives it a SSL cert so it's available on https. To get those both running we need the following docker-compose.yaml file which is placed in /opt/docker-compose. It's downloadable as a gist as well.

version: '2'
services:
  nginx-proxy:
    container_name: nginx-proxy
    image: jwilder/nginx-proxy:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./letsencrypt/certs:/etc/nginx/certs
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt
    volumes_from:
      - nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./letsencrypt/certs:/etc/nginx/certs:rw

That file shows we have two containers running, nginx-proxy and letsencrypt. The volumes are the part you will want to pay attention to as that's mapping files on your local computer into the container. In that file above you can see it mentions the directory letsencrypt and the ./ means it's starting in your current directory that this file lives in. So you will need to create the directory /opt/docker-compose/letsencrypt.

Now that the base of your docker-compose file is in place the next thing is adding the lines needed for DockuWiki. In that repo Eric Barch shows how to spin this up with Docker, but not Docker Compose, that's fine we will learn how to convert it. He says you spin up DockuWiki with this docker command:

docker run -d --restart=always --name=wiki -e SSH_PORT=22 -e SSH_DOMAIN=bitbucket.org -e  REMOTE_URL=git@bitbucket.org:YOUR_BITBUCKET_USERNAME/wiki.git -p  3000:3000 ericbarch/dockuwiki

The fastest way to figure out how this converts is use a website to convert it. Pasting in the code above outputs the following:

version: '3.3'
services:
    dockuwiki:
        restart: always
        container_name: wiki
        environment:
            - SSH_PORT=22
            - SSH_DOMAIN=bitbucket.org
            - 'REMOTE_URL=git@bitbucket.org:YOUR_BITBUCKET_USERNAME/wiki.git'
        ports:
            - '3000:3000'
        image: ericbarch/dockuwiki

In the environment section you will need to change those to all point to your git repo for your wiki. It doesn't have to be bitbucket either that's just what was used in the sample given to us. We also want to add a couple lines to this for nginx-proxy and letsencrypt so we can serve this site and have an SSL cert. In the environment section you will need to add the following lines:

      - VIRTUAL_HOST=mycoolwiki.joshfabean.com
      - VIRTUAL_PORT=3000
      - LETSENCRYPT_HOST=mycoolwiki.joshfabean.com

VIRTUAL_HOST and VIRTUAL_PORT are used by nginx-proxy to know when traffic comes to the server with the domain name of mycoolwiki.joshfabean.com this is the container it needs to go to, and once in the container you need to serve port 3000, which is nice so your users don't need to put the port in their browser. The line LETSENCRYPT_HOST always needs to match your VIRTUAL_HOST or the SSL cert won't work, and this will only work if your domains DNS actually points to this server, or letencrypt won't issue you the cert. Once that section is all modified it should look like the following:

wiki:
    container_name: wiki
    image: ericbarch/dockuwiki
    environment:
      - SSH_PORT=22
      - SSH_DOMAIN=github.com
      - REMOTE_URL=git@github.com:fabean/wiki.git
      - VIRTUAL_HOST=mycoolwiki.joshfabean.com
      - VIRTUAL_PORT=3000
      - LETSENCRYPT_HOST=mycoolwiki.joshfabean.com
    ports:
      - "3000"
    restart: always

So all together your file should look like this:

version: '2'
services:
  nginx-proxy:
    container_name: nginx-proxy
    image: jwilder/nginx-proxy:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./letsencrypt/certs:/etc/nginx/certs
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt
    volumes_from:
      - nginx-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./letsencrypt/certs:/etc/nginx/certs:rw
  wiki:
    container_name: wiki
    image: ericbarch/dockuwiki
    environment:
      - SSH_PORT=22
      - SSH_DOMAIN=git.joshfabean.com
      - REMOTE_URL=git@git.joshfabean.com:fabean/Wiki.git
      - VIRTUAL_HOST=mycoolwiki.joshfabean.com
      - VIRTUAL_PORT=3000
      - LETSENCRYPT_HOST=mycoolwiki.joshfabean.com
    ports:
      - "3000"
    expose:
      - "3000"
    restart: always

Alright, you have your final docker-compose.yaml file almost done! Now from the directory /opt/docker-compose we need to tell docker to start all the containers. To do that run docker-compose up -d that tells docker-compose to read the docker-compose.yaml and up all those containers, the -d means to do it detached so if you close your terminal it keeps running.

Generally right here you'd be done, but because the DockuWiki server we're running needs full right access to a git repo you need to get it's SSH key and add it to your github/gitlab/bitbucker/gitea account. To do that we need to view the servers logs, as that's were it's telling you what's wrong. To view the logs you type docker logs wiki that works because wiki is the container name, you will see something like this:

From there copy the SSH key printed add it to your account, then you should see the logs change saying it connected and it's setting up your wiki. After that go to your website and things should be good!

Conclusion

You have now, spun up a Ubuntu Server, installed Docker, configured your docker server, and got a Wiki website up and running! With docker the possibilities of what services and sites you can start hosting yourself are endless, you really need to look no further that Awesome Selfhosted Repo I posted earlier to see what types of things you might be interested in hosting. Next steps might be compiling your own Docker containers, spinning up a private Chat server for you and your friends, or getting a Plex or Jellyfin server setup to more easily watch your TV Shows and Movies you have.

I hope this helped you get your feet wet with servers, if this inspired you or you run into issues or have questions feel free to reach out to me on Twitter @joshfabean.