How I run this blog with docker
Lets talk about this blog and how it is running.
My blog is powered by:
- docker
- apache
- php 7
- wordpress
- mysql
- nginx reverse proxy (this maps the domain milmike.com with a specific docker container)
- https with letsencrypt (free ssl certificates)
- http2 protocoll
I will show you how I managed to run this blog using these technologies but before that, you might ask yourself: why? why so “complicated”?
Thats not really complicated. I think it is even much simpler than installing everything from scratch. You don’t have to install apache, php, configure your apache, mysql etc.. the only thing you need is docker and a docker-compose.yml file. And you can quickly migrate to another server or work easily locally with the exact same installation as in production. Thats actually how I work most of the time. Since I discovered docker, I use it for dev and prod.
This is not a tutorial how to install docker, you should already know some basics about docker.
So, let’s go!
At first, you also need the tool docker-compose, install first because you will work with a docker-compose.yml file.
You will need 2 docker-compose.yml files: One which will be the reverse-proxy and ssl provider and the other file which can be any project. Lets see how the docker-files look like:
docker-compose.yml for the reverse proxy and letsencrypt ssl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
version: "3" services: nginx-proxy: image: jwilder/nginx-proxy container_name: nginx-proxy ports: - "80:80" - "443:443" expose: - 80 - 443 volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - /home/michael/nginx-proxy/nginx/certs:/etc/nginx/certs - /home/michael/nginx-proxy/nginx/vhost.d:/etc/nginx/vhost.d - /home/michael/nginx-proxy/nginx/html:/usr/share/nginx/html - /home/michael/nginx-proxy/nginx/dhparam:/etc/nginx/dhparam environment: DEFAULT_HOST: default.vhost letsencrypt: image: jrcs/letsencrypt-nginx-proxy-companion container_name: nginx-proxy-le environment: NGINX_PROXY_CONTAINER: nginx-proxy depends_on: - nginx-proxy volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - /home/michael/nginx-proxy/nginx/certs:/etc/nginx/certs - /home/michael/nginx-proxy/nginx/vhost.d:/etc/nginx/vhost.d - /home/michael/nginx-proxy/nginx/html:/usr/share/nginx/html - /home/michael/nginx-proxy/nginx/dhparam:/etc/nginx/dhparam networks: default: external: name: nginx-proxy |
The above docker-compose.yml file will start 2 things:
- a reverse proxy
- letsenrypt tool for the reverse proxy
the tool will automatically create a letsencrypt ssl certificate one you start a container with new a domain. It will also update the certificate after 3 months.
But how does the reverse proxy work?
Simply said: it is the web server, if you open the site on this server (port 80 or ssl 443) this proxy will see the request and route the http request to the target docker project.
But how does the proxy server know which domain is mapped to which docker container??
Thats simple: environment variables. In your target docker project you specify environment values telling “I am the container for the domain milmike.com”. If you start the project, the reverse proxy will know that you started the container and will automatically map every http request to the new container.
OK cool, but how does the SSL certificate thing work?
If you start your container with the wordpress/apache the reverse proxy will know about it. It will also let the letsencrypt container know about it, which will then automatically create a SSL certificate for you. Sounds complicated but it really isn’t almost everything is done automatically.
docker-compose file with my blog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
version: "3.0" services: milmikeweb: image: webdevops/php-apache:7.3 container_name: milmike_wordpress volumes: - ./:/app/ expose: - 80 - 443 restart: always environment: VIRTUAL_PROTO: https VIRTUAL_PORT: 443 VIRTUAL_HOST: milmike.com, www.milmike.com LETSENCRYPT_HOST: milmike.com, www.milmike.com PHP_OPCACHE_MEMORY_CONSUMPTION: 192 PHP_OPCACHE_MAX_ACCELERATED_FILES: 10000 PHP_OPCACHE_VALIDATE_TIMESTAMPS: 1 PHP_OPCACHE_REVALIDATE_FREQ: 0 PHP_OPCACHE_INTERNED_STRINGS_BUFFER: 16 PHP_DISMOD: sodium,exif,pgsql,ioncube,amqp,bcmath,ldap,pcntl,redis,mongodb,xsl,sysvshm,sysvmsg,sysvsem stdin_open: true tty: true networks: default: external: name: nginx-proxy |
Above you see a docker-compose file which will start apache with php7 from webdevops (btw, I use their containsers for webdev all the time)
The most important part is “VIRTUAL_HOST: milmike.com, www.milmike.com” This tells the proxy “hello proxy, if you have http requests for milmike.com or www.milmike.com, send the requests to me”
If you plan to use SSL, you will also have to use VIRTUAL_PROTO, VIRTUAL_PORT and LETSENCRYPT_HOST. The latter is simply the same as VIRTUAL_HOST. For these domains / subdomains a letsencrypt certificate will be created.
If you start these 2 containers, you are ready to go, you have a working webserver with ssl. But I will also show how I use it with MySQL and WordPress.
MySQL
I have an external MySQL server. I could put the server in one of the docker-files above but I prefer to use own docker-compose file for the database. Here how it looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
version: '3.3' services: db: user: "1000" image: mysql:5.7 restart: always environment: MYSQL_DATABASE: 'db' MYSQL_USER: 'someuser' MYSQL_PASSWORD: 'password' MYSQL_ROOT_PASSWORD: 'password' ports: - '3306:3306' expose: - '3306' volumes: - /home/server/mysql-database/data:/var/lib/mysql:rw networks: default: external: name: nginx-proxy |
The above yaml file will start the mysql server and expose the port to the public. You don’t really have to do this, but I also use the server with tools where a tunnel is not possible.
You can also see the volume. It is mounted to a path on this server. Why? because the data will be there even if I restart / remove the mysql docker. And I also can move the data quickly to another server without creating database dumps and importing these. This is the fastest way to backup / restore your data.
WordPress
Ok, the last thing. WordPress. This is the only thing that is not dockerized. I simply downlaoded the wordpress.zip file and installed it here on my server. I then added the docker-compose.yml file to the root of wordpress installation and started it by executing docker-compose up -d.
TLDR / Steps
- create a folder “nginx-proxy” (on your server)
- put there the docker-compose.yml file from above (and edit the file to your needs, especially the paths)
- create following folders in your nginx-proxy folder: certs, vhost.d, html, dhparam and make these folder writable
- chmod 777 /var/run/docker.sock
- now start it: docker-compose up -d
- create somewhere a new folder for the wordpress, eg /home/www/myblog
- download there wordpress or whatever you want
- in that folder, put there the second docker-compose.yml file from above and update the file to your needs.
- start it: docker-compose up -d
One more thing
after you reboot your server, you might also chmod 777 /var/run/docker.sock file.