Link Search Menu Expand Document

Self-hosting Assignment

Install Docker

Docker is a containerization software that makes it very easy to set up and run a reproducable image (a container) of a certain application. It lets users package all of the required software to run a certain application (dependencies) together so that it can be easily run on any computer with very little setup. You can think of it as a lighter version of a virtual machine with all of the dependencies to run your app already installed. If you’re more interested in what docker is or does, we recommend watching this video

If you’re on MacOS/Windows, install Docker Desktop. On Linux, install Docker Engine and Docker Compose.

To ensure Docker was installed correctly, open a terminal (Terminal on MacOS and PowerShell on Windows) and ensure you get output when you run docker ps

$ docker ps

Config file

It’s very easy to get something running locally with Docker. All you’ll need to do is create a configuration file and run a single command. Depending on what you’d like to self-host, choose the config file and save it as docker-compose.yml in an empty folder somewhere on your computer. We’ve provided most of the config files for you, but you’ll need to fill out some parts yourself.

YAML: YAML Ain’t Markup Language™

YAML is essentially just a text file that follows a specific format, making it useful as a configuration file. The following examples should be mostly self-explanatory, but here’s some things to remember:

  1. Indentation matters
  2. # starts a comment. You can use these to write information that will be ignored by Docker

Action Items

  1. Create a new folder on your computer
  2. Save the config file of the application you’d like to run as docker-compose.yml in that folder
  3. Change the FIXME’s in the config file to the relevant information (for passwords, create your own).
  4. In your terminal, navigate to the folder you created using cd, ls, and pwd: Navigating your filesystem in the Linux terminal (applies to any terminal you’re using).
  5. Run docker-compose up -d
  6. Each section explains how you can verify it’s running correctly. You can also view logs with docker-compose logs -f
  7. Submit a screenshot of your web app running!
  8. To stop the containers, run docker-compose down

If something goes wrong, run docker-compose down, delete the data folder that was created in the folder, edit docker-compose.yml, and run docker-compose up -d again


Nextcloud is a self-hosted alternative to Google Drive/Contacts/Calendar. Using this config file, you’ll spin up two containers: the one you see (nextcloud) and the backend MySQL database (nextcloud_db).

version: "2"
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
      - 80:80
      - 443:443
      - nextcloud_db
      - ./data/html:/var/www/html
      - MYSQL_HOST=nextcloud_db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=root
    image: mariadb:latest
    container_name: nextcloud_db
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --skip-innodb-read-only-compressed
      - MYSQL_DATABASE=nextcloud
      - ./data/mysql:/var/lib/mysql

Then, open your browser to and follow the instructions to create an admin account


Pi-hole is a network-wide ad blocker that also blocks plenty of tracking scripts with minimal website breakage. Any device you connect to your network (phone, smart TV, etc.) will now be able to block ads just by connecting to your network. In this guide, we’ll just show how to get it running locally, but the advanced guide will show how to enable it for your entire network.

How it works

When you visit a website, your computer must first translate a domain name ( into an IP address ( by asking a DNS server specified by the network. Pi-hole works by acting as the DNS server and translating analytics/ad domains ( into a bogus/nonexistent IP address (, so applications won’t be able to connect to any known ad/analytics domains. Otherwise, it just forwards requests to a normal DNS server.

version: '2'
    image: pihole/pihole:latest
    container_name: pihole
    restart: unless-stopped
      - TZ="America/Los_Angeles"
#    volumes:
#      - ./data/etc-pihole/:/etc/pihole/
#      - ./data/etc-dnsmasq.d/:/etc/dnsmasq.d/
      - 53:53/tcp # You may need to change port 53 to another port if something else is using port 53
      - 53:53/udp # same here. For example, you could do `553:53/tcp` and `553:53/udp`
      - 80:80/tcp
      - 443:443

Then, visit in your browser. When you making the following DNS queries to Pi-hole, you should see the admin interface update!

To make a DNS query, you can use dig on MacOS/Linux and nslookup on Windows. Then, do the same DNS query, but use Pi-hole as your DNS server ( If Pi-hole is working correctly, you should get as the result for

Note: $ is not part of the command, it’s just used to differentiate from the output of a command from the command itself


$ dig +short # If you're using a port other than 53, run with `-p <port_number>`
$ dig +short @ # Use pi-hole


$ nslookup
$ nslookup


LanguageTool is an open-source alternative to Grammarly. Both work by sending any text you type (Google Docs, emails, text boxes, etc.) to a server which analyzes it and sends back the results. As you’d expect, this is not that great in terms of privacy. While LanguageTool has a much better privacy policy than Grammarly, you can actually self-host the server part of LanguageTool to make everything private.

version: '2'
    image: silviof/docker-languagetool:latest
    container_name: languagetool
    restart: unless-stopped
      - 8081:8010

How to test the server

To use it with your browser extension, open the settings for the browser extension and under Experimental settings (only for advanced users) -> LanguageTool API server URL, change it to Local server (localhost). Then, you can try it out on any website with a text box (e.g.,

n-gram data

To detect errors with words that are often confused like their and there, you’ll need to download and set up your server with n-gram data. It’s not enabled by default because it’s a pretty large file (8 GB). Follow LanguageTool’s guide to download it, then add this to your config file:

      - /path/to/ngrams:/ngrams # FIXME: change this path

Minecraft server

No need to be on the same LAN to play Minecraft with your friends, you can self-host your own server! We’ll be using Spigot (basically it’s better than Vanilla/Bukkit Minecraft server) for this guide.

version: '2'
    container_name: mc
    image: itzg/minecraft-server:latest
    restart: unless-stopped
      - EULA=TRUE
      - DIFFICULTY=normal
      - OPS=FIXME # Put your Minecraft username here
      - TZ=America/Los_Angeles
      - ENABLE_RCON=true
      - GUI=false
      - INIT_MEMORY=2G # Needs AT LEAST 2 GB
      - MAX_MEMORY=3G
      - ./data:/data
      - 25565:25565

Note that it takes quite a while for the server to start up. Use docker-compose logs -f to see when the container is ready for you to connect to it. It’ll be ready when the logs say [Server thread/INFO]: RCON running on

When it’s ready, add a new Multiplayer server in your Minecraft app (Multiplayer Server -> Add Server). Set Server Name to anything you’d like and Server Address to Then, you should be able to connect.

Note: For some reason, you won’t be OP right away, so after you’ve connected to the server at least once, restart the container with docker-compose restart mc then you’ll be OP once it restarts

Static website

Create a file index.html in an empty folder with the following contents:

<!DOCTYPE html>
  <h1>Hello World!</h1>

Create another file default.conf in the same folder with the following contents:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    location / {
        root   /var/www/html;
        index  index.html index.htm;

In the same folder, add this Docker config file:

version: '2'
    container_name: nginx
    image: nginx:latest
    restart: unless-stopped
      - 80:80
      - ./index.html:/var/www/html/index.html:ro
      - ./default.conf:/etc/nginx/conf.d/default.conf:ro

Then, open in your browser


Below, we will explain some of the technical aspects of what these config files do. You don’t need to understand these to complete the assignment, but we recommend reading them if you’re interested.


Images are prepackaged versions of an application that contain all files and dependencies needed to run a program. We can specify the image we want to run in our config file and Docker will automatically fetch and run the image from Docker Hub.


Ports are essentialy doors into a computer or network. In order for you to access your web app, you’ll need to expose/open a port on your computer. Most lower numbered ports are generally reserved for certain tasks/protocols (e.g. port 80 for http traffic, 443 for https), while most higher numbered ports are unmapped.

As such, programs like Nextcloud that listen on ports 80 and 443 (or similarly with other ports) might interfere with other programs that listen on the same ports. Docker solves this issue by mapping the container’s ports to arbitrary ports on your computer. For example, these lines from the Nextcloud config map ports 80 and 443 in the Nextcloud container to the normally unused ports 4536 and 4637 on the host computer:

  - 4536:80
  - 4637:443

This allows you to not have to worry about changing the default ports within Nextcloud and just change the port numbers in Docker instead. The config files we’ve provided should already remap ports for you, but feel free to play around with these if you wish.

You can read more about ports here. The config files we’ve provided should already handle these for you


For applications that require persistent storage (i.e. the files the application creates should be retained even if you quit/restart the container) like Nextcloud, we use volumes to map folders/directories on our host machines to directories within the container. As an example, in the config for Nextcloud’s database (nextcloud_db), we map the folder ./nextcloud/db/mysql on the host computer to /var/lib/mysql in the database container, so even if you quit the database container, all of your files will be safe and sound. This has already been implemented for you in our provided config files, but feel free to change the folders if you wish.


The restart policy tells docker when it should try to restart your container. All of our dockerfiles are set as restart: unless-stopped. This tells docker that if your container crashes, it will keep trying to restart it automatically unless you explicitly stop it.

Making your application public (optional)

Disclaimer: This is not required for the assignment, so this section of the guide will be much more technically involved and more of a summary than a step by step guide. If you get stuck or otherwise want help, feel free to message us on Mattermost! This will also NOT work if you live in the dorms (and you’re not using a VPS) or otherwise cannot access your router settings.

If you are using Pi-Hole, follow this guide instead of what we have written below.

If you want to be able to access your applications from anywhere on the internet, you’ll need:

  • A server or VPS (Virtual Private Server)
  • A domain name (e.g., which can be as little as $12/year

For a server, you can use any computer that you can keep running (nearly) 24/7. It doesn’t need to be particularly powerful; an old computer or a laptop would work just fine. If you don’t have any old hardware lying around or don’t want to go through the effort of setting up a computer, you can also rent a VPS from a cloud hosting provider online (e.g., OVH, Vultr, Scaleway, DigitalOcean). A VPS is essentially a virtual server that you can access and manage over the internet, while the actual hardware behind it is managed by the hosting company.

If you are setting up your own server, we recommend installing a Linux distribution on it. The vast majority of servers run Linux, and there are many server tools available for it already. Our personal recommendation is Ubuntu Server (Option 2), but you can use whatever you like. Here is a video explaining how to install Ubuntu Server:

To get a domain name, you have to purchase one from a domain name registrar. The price of this varies depending on the registrar and the specific domain name, but on average it is around $12/year. Some examples of where you can get a domain name are Njalla, Namecheap, and Google Domains. If your registrar provides it, we recommend enabling the WHOIS protection to prevent others from looking up who bought the domain.

Once you have both a server and a domain, SSH into your server and follow the steps outlined above in the first part of the assignment to get your application up and running on your server. At this point, you should be able to access your application from within your home network (or over the network if a VPS) at SERVER_IP_ADDRESS:DOCKER_PORT (e.g., You can get your server’s IP address by running ip addr on your server.

The next step is to make your server publicly accessible over the internet. For this, you will have to do 2 things. First, (if you are NOT using a VPS) go into your router settings and port forward ports 80 and 443 to your server/ your server’s IP address. This will tell any requests that are incoming to your home network to be redirected towards your server so they can be handled by your application. The exact instructions for this vary based on your specific router, so you should look up instructions for the router you have. Second, you will set up your domain address to point towards your home network or VPS. If you are on your home network, get your IP address at whatismyip. If you are using a VPS, follow the instructions to get your IP address from your VPS provider. Then, go into the settings of your domain name registrar and add a new A record under your domain name with the data field being your/the VPS’s IP address. The specific steps will again depend on your specific domain registrar, so you should look this up and follow the instructions given by your registrar.

If all goes well, at this point you should be able to access your application from your domain name! If you go to, your application should pop up. We know this section of the guide was much less hand hold-y than the first, and we don’t necessarily expect you to be able to this on your own. Therefore, if your application doesn’t work at this point or you just want some help, we reiterate that you should please feel free to message us on Mattermost, and we’ll be happy to help :)