Become a sponsor to see this post

Configuring wordpress securely with docker + nginx cache

Dec 24 2017

Note: I’m using this approach in this blog.

The problem

I have been using jekyll for a while. Jekyll is great: integrates with github, allows to statically generate blogs and sites so you just serve static files lightning-fast and you don’t have to be worried about being hacked by bad written php scripts.

The main problem with jekyll is that you have to write markdown manually, and you have to do a lot of things manually. Like copying images, linking to them, choosing the date. And you cannot schedule some posts to be published in the future. So you are kinda limited.

With wordpress you can schedule posts, and it has a wysiwyg editor. Also it has tons of plugins and themes already created for it.

I have tried blogger too, but it is too limited and they do not handle well things like inserting code, which is a thing a do a lot.

So can we have best of both worlds easily in our own server? Yes, but it is not trivial.

The solution

I’m going to explain how to configure everything to have a wordpress working in a password-protected subdomain, and then configure the main domain to cache and serve requests from the uncached domain and to limit access to wordpress admin stuff for security. Everything automatically sandboxed and secured by docker containers and letsencrypt powered SSL.

  • https://github.com/jwilder/nginx-proxy
  • https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion

With this script you are configuring a docker container + a nginx-letsencrypt companion that will renew automatically all the required certificates:

DIR=`dirname $0`
docker network create --driver bridge reverse-proxy
docker rm -f nginx
docker run -d -p 80:80 -p 443:443 \
  --name=nginx \
  --restart=always \
  --network=reverse-proxy \
  -v $DIR/certs:/etc/nginx/certs:ro \
  -v $DIR/conf.d:/etc/nginx/conf.d \
  -v $DIR/vhost.d:/etc/nginx/vhost.d \
  -v $DIR/html:/usr/share/nginx/html \
  -v /var/run/docker.sock:/tmp/docker.sock:ro \
  -e NGINX_PROXY_CONTAINER=nginx \
  --label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true \
  jwilder/nginx-proxy
docker rm -f nginx-letsencrypt
docker run -d \
    --name nginx-letsencrypt \
    --restart=always \
    --network=reverse-proxy \
    --volumes-from nginx \
    -v $DIR/certs:/etc/nginx/certs:rw \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    jrcs/letsencrypt-nginx-proxy-companion

Then you have to create a folder for your wordpress instance. And place these files there:

Dockerfile (custom wordpress increasing file limits):

Dockerfile

FROM wordpress
RUN echo "file_uploads = On\n" \
         "memory_limit = 64M\n" \
         "upload_max_filesize = 64M\n" \
         "post_max_size = 64M\n" \
         "max_execution_time = 60\n" \
         > /usr/local/etc/php/conf.d/uploads.ini
         >

docker-compose.yml (you have to replace myblog.com and myemail@myblog.com):

version: '2'
services:
  db-wordpress:
    restart: always
    image: mariadb
    volumes:
      - $PWD/db-wordpress:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=wordpress
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wordpress
      - MYSQL_PASSWORD=wordpress
    networks:
      - backend
  wordpress:
    depends_on:
      - db-wordpress
    #image: wordpress
    build:
      context: ""
      dockerfile: Dockerfile
    volumes:
      - $PWD/www:/var/www/html
      - $PWD/pass:/var/www/pass
      #- uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    expose:
      - 80
    environment:
      - WORDPRESS_DB_HOST=db-wordpress:3306
      - WORDPRESS_DB_PASSWORD=wordpress
      - VIRTUAL_HOST=admin.blog.myblog.com
      - LETSENCRYPT_HOST=admin.blog.myblog.com
      - LETSENCRYPT_EMAIL=myemail@myblog.com
    networks:
      - reverse-proxy
      - backend
    restart: always
  cache:
    image: nginx
    networks:
      - reverse-proxy
    restart: always
    volumes:
      - $PWD/cache:/usr/share/nginx/cache
      - $PWD/conf.d:/etc/nginx/conf.d:ro
    expose:
      - 80
    environment:
      VIRTUAL_HOST: blog.myblog.com
      LETSENCRYPT_HOST: blog.myblog.com
      LETSENCRYPT_EMAIL: myemail@myblog.com
      VIRTUAL_PORT: 80
networks:
  backend:
  reverse-proxy:
    external:
      name: reverse-proxy

conf.d/default.conf (you have to replace myblog and REPLACE_WITH_BASE64_ENCODED_USER:PASSWORD):