Setup of this website

For this setup we will use an ubuntu server running docker containers on a home server. We will use docker-compose to set up both a wordpress and a reverse proxy which also grants SSL certificates. It also includes settings for your router.

Note this tutorial will presume you have a domain at your disposal, you can get one for free if you don't like to commit to any costs.

Set up your server

Get an image from ubuntu.com, in this case get the ubuntu-server version, this will include docker but no GUI. Use some tool to get this on a USB stick to install on your server, I recommend UUI (Universal USB installer) . After installing i recommend you connect using ssh to this server, for this you will need its internal ip, you can obtain this using:

ifconfig -a

Connect using:

 ssh username@internalip

From here you can start your setup, let's first do a testrun of setting up wordpress, we make a docker-compose file, compose it and try to access it on your local network, later on the internet (without a domain).

First make a folder with a short descriptive name for what you are making, place in the folder docker-compose.yml the following text using for instance nano (i.e. nano docker-compose.yml)

version: '3.3'
services:
db:
image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpresswordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpressvolumes:db_data: {}

As this is a test these passwords don't really matter yet. What matters here is that a wordpress container is made with a database on the same virtual network and this is approachable from the outside on port 8000.

Once this is saved, make sure you are in the the folder containing this file and the following to build the containers in the background (hence the -d)

docker-compose up -d

you can inspect its progress and logs using the following two commands:

docker ps -a

docker logs (-f) 

Testing your initial test setup

If you have done so correctly you should be able to access the test-wordpress website using http://localip:8000 you can go configure your testwebsite, but we will throw this away at some point. So as long as you are greeted with the wordpress-setup you are good.

Setup of router

To access your server on the world wide web you will need to allow access to it on your router. For this go to the settings of your router, then port forwarding and set the forward for ports 80 (http), 443 (https) and 8000 (testsetup) to forward to that localip.

Once this is properly set you should be able to acces the same testwebsite on your external ip. This Ip can be obtained by executing curl ifconfig.me . Then you can get to the same website using http://externalip:8000. Be sure to remove the port 8000 again from your router settings after you have tested this.

Setting up DNS

If you have control over a domain you can set up its dns, which is the settings of the Domain Name Server i.e. how other computers recognize that your websitename corresponds to your external ip.

Your dns settings might come at some preconfigured settings, the only things we are concerned about now are the A records. configure the www and/or @ A record to your external ip and you should be good for now (please read the other settings and see what you like/need that would be a whole topic in itself). Your A record should look something like this: Type:A, Name:@, Priority:0, content:externalIp, TTL 300. TTL means time-to-live which means you can fix this within 5 minutes if you mess up. After saving wait five minutes and clear your dns. On windows execute in CMD: ipconfig /flushdns after that use ping yourwebsite.com and it should show your external ip (ctrl + c to cancel)

Finishing up

Accessing your website in a browser by default is done using on port 80 (http) or on port 443 (https). To quickly get http working you cooould simply change "8000:80" to "80:80" in your initial docker-compose.yml, docker-compose up -d again and be 'done'. However Then we wouldn't really be able to set up multiple websites, and don't have a secure connection for anyone visiting our website.

Hence we will set up a reverse-proxy with a certification-supplier. A proxy is an application that will allow connections to be made from multiple clients to the same target. A reverse-proxy is of course the inverse given the same entry you can access multiple places (i.e. multiple websites/containers on the same server). The certification supplier is there to supply the certificates to the connections such that they properly are https.

For this to work we need the following:

Our nginx-proxy + certificate supplier is set up on external ports 80 and 443.

The website we have has internal ports 80 and 443 open on the same network as the nginx-proxy and some env-variables.

Lets first setup up the proxy and certificate supplier as it will adjust itself automagically if containers are updated and each time they are started.

make a folder nginx-proxy, place the following docker-compose.yml there and execute docker-compose up -d

version: '2'services:  nginx-proxy:    image: nginxproxy/nginx-proxy    container_name: nginx-proxy    ports:      - "80:80"      - "443:443"    volumes:      - conf:/etc/nginx/conf.d      - vhost:/etc/nginx/vhost.d      - html:/usr/share/nginx/html      - dhparam:/etc/nginx/dhparam      - certs:/etc/nginx/certs:ro      - /var/run/docker.sock:/tmp/docker.sock:ro    network_mode: bridge  acme-companion:    image: nginxproxy/acme-companion    container_name: nginx-proxy-acme    volumes_from:      - nginx-proxy    volumes:      - certs:/etc/nginx/certs:rw      - acme:/etc/acme.sh      - /var/run/docker.sock:/var/run/docker.sock:ro    network_mode: bridgevolumes:  conf:  vhost:  html:  dhparam:  certs:  acme:

Next we will need to remove or update our wordpress setup, I would recommend removing our current one first, then making a new one.

First stop the running containers, get the relevant ones using docker ps -a then stop the container using docker stop then remove using docker rm. Now we do need to worry about those passwords, I recommend generating one and storing it safely using for instance pwgen. Make sure that the passwords align in the docker-compose.yml of wordpress otherwise it will simply not work properly. In this example below i didn't update the password for obvious reasons.

version: '3.3'services:db: image: mysql:5.7 volumes:   - db_data:/var/lib/mysql restart: always environment:   MYSQL_ROOT_PASSWORD: somewordpress   MYSQL_DATABASE: wordpress   MYSQL_USER: wordpress   MYSQL_PASSWORD: wordpresswordpress: depends_on:   - db image: wordpress:latest expose:   - "443"   - "80" restart: always environment:   WORDPRESS_DB_HOST: db:3306   WORDPRESS_DB_USER: wordpress   WORDPRESS_DB_PASSWORD: wordpress   WORDPRESS_DB_NAME: wordpress   VIRTUAL_PORT: 80   VIRTUAL_HOST: yourwebsite.com   LETSENCRYPT_HOST: yourwebsite.comvolumes:db_data: {}

The differences here are that instead of an external port 8000 we open up internal ports 443 and 80, we have a virtual port 80 (don't know if this is required) a virtual_host (which is the name of your website) and the same for lets encrypt host. All of this is such that your proxy + certificate supplier set-up knows what to set through this container and give it ability to do so. Once this is up using docker-compose up -d we are not yet done as the two sets of containers are on 'different' networks. This was a bit tricky to set up properly and this is probably not the best way to do this, but: you can simply add your wordpress container to the network of nginx-proxy. Do so by using docker network connect bridge.

If you are lucky this should work in one go, which means you can access the website using your browser. Troubleshooting steps: you can restart the nginx-proxy container and or its cert-supplier (twice). You can check the configuration of nginx, you can do this by viewing the config file within that container, i.e. docker exec -ti cat /etc/nginx/conf.d/default.conf. Here you should see something like 'upstream yourwebsite {' and there the wordpress container name and 'server someip:80;' This ip should correspond to the ip you see in the network-settings of your wordpress container in the bridge network which you can inspect by using docker inspect (at the very end Networks, bridge then "IPAddress".

Possible improvements to this setup:

  1. Putting passwords in a file is insecure + this way they are also shown in the docker inspect output.
  2. Using a different cert supplier on nginx-proxy-acme, by default it uses lets-encrypt, which is fine, but if you really want control over your certificates it is possible to have a different supplier and get a nice webinterface overview
  3. Putting the containers after creation on the same network is ugly as far as i'm concerned. At this moment I didn't have the patience yet to make this part more convenient/reliable.

If you have any feedback, let me know.