Dockerize and Secure WordPress behind a Proxy

When you hear the words WordPress, Secure and Proxy you might start having nightmares. But there is no reason for that. Just by following the instructions hereunder, and setting up the proxy carefully, you should be able to carry out this tiresome task easily.

Why a Proxy?

Well, basically because it is easier to implement and faster to scale when you want to serve multiple applications in the same host.

dockerizepost

Let’s start

In the following section you will find several scripts to run Docker containers, each one detailing both, its purpose and its configurations.

So, first you should start setting up the file structure that will be used all over the post:

├─ init-db/
│ └─ wordpress-init-db.sql
├─ proxy-nginx/
│ └─ default.conf
├─ wordpress/
│ └─ 000-default.conf
├─ create_proxy_nginx.sh
├─ create_wordpress_mysql.sh
└─ create_wordpress.sh

MySQL

Before running the MySQL container you need to mount a pre-loaded WordPress database named as wordpress that has already defined the SITE_URL and HOME variables with the url for your site, like http://wordpress.example.com. Next you will find the create script for the container:

WordPress

Once the MySQL container is created and running properly, you should create the WordPress container, and override the default Apache configuration with a custom defined settings like the ServerName that will be used in the next step. Hereafter you will find the creation script for the container and a summary of the Apache configuration:

Proxy

Now let’s create the Nginx container that will act as a proxy for your WordPress site. It’s important to link it with the WordPress container and setup the default.conf configuration file for the Nginx container. Next you will find the creation script for the container and a summary of the Nginx configuration. Be aware of the proxy_set_header defined there:

Running everything!

First we need to setup execution grants to all the *.sh files with:

Be sure to run all these scripts in the root folder

  1. Run the create_wordpress_mysql.sh script and wait until it is ready and the database is created.
  2. Run the create_wordpress.sh script and wait until it is ready.
  3. Run the create_proxy_nginx.sh script.
  4. Add in your /etc/hosts an alias wordpress.example.com that points to `127.0.1.1`.

Now, you should be able to browse http://wordpress.example.com and see the WordPress site properly

Fixing Mixed Content Error easily

Fixing protocol errors

You may face “Mixed Content Error” thrown by WordPress when there are some assets being loaded by http instead of https.

To solve it, you need to install a plugin SSL Insecure Content Fixer.

  1. Open a browser
  2. Navigate to http://wordpress.example.com/wp-admin
  3. Log in with the credentials used before when running the wordpress container
  4. Install and activate the SSL Insecure Content Fixer
  5. Navigate to Settings -> SSL Insecure Content
  6. Set HTTPS detection to HTTP_X_FORWARDED_PROTO (e.g. load balancer, reverse proxy, NginX)

The following extra steps are just in case you are still seeing the error.

  1. Navigate to Settings -> General
  2. Set the WordPress Address (URL) and Site Address (URL) to your new HTTPS address, in our case https://wordpress.example.com

That’s it! You should now enjoy your secure WordPress application running properly.

Nice, but where is the trick?

The first trick is that all the --link containers have an alias defined in the /etc/hosts in the host containers. This is why in the location / closure inside of the Nginx configuration file the line proxy_pass http://wordpress; appears.

And the other trick is just a couple of headers that you need to define in order to allow the WordPress plugin (SSL Insecure Content Fixer) to be aware that it’s receiving a proxy redirection request.

What’s next?

In our next post you will learn how to test your SSL certificates locally in your Chrome browser to be sure that is it working fine and that your site will be ready when you decide to go live.

  • Asterix

    Hmm, do you have an idea why my redirect for
    http://www.myotherdomain.com
    doesn’t work?

    server {
    server_name http://www.myotherdomain.com;
    return 301 $scheme://test.domain.com$request_uri;
    }
    server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;

    root /var/www/html;
    index index.php index.html index.htm;

    #Password protects the test subdomain
    auth_basic “Restricted Content”;
    auth_basic_user_file /etc/nginx/.htpasswd;
    # Make site accessible from https://test.domain.com/
    server_name test.domain.com;
    include snippets/ssl-test.domain.com.conf;
    include snippets/ssl-params.conf;
    location ~ /.well-known {
    allow all;
    }
    location / {
    try_files $uri $uri/ /index.php$is_args$query_string;
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root /usr/share/nginx/html;
    }
    location ~ [^/].php(/|$) {
    fastcgi_split_path_info ^(.+?.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
    return 404;
    }
    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY “”;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    include fastcgi_params;
    }
    location ~ .php$ {
    #match actual filename with extension or file not found
    #try_files $uri $uri =404;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }
    }

    • Germán Nicolas Ollé

      Hi Asterix,

      I saw that there are diffrents ways to define a redirection using Nginx, also a few that looks really simple.
      Please take a look here https://gist.github.com/EmranAhmed/946a74c0331832040844#efficient-301-redirects

      Please let me know if anything in that link help you.
      Take care!

      • Asterix

        Thanks! I will try those out! Can you recommend any Docker-file for WordPress locally in Windows 10 with NGINX? I have tried these on my Windows 10 laptop, installed with Kitematic, but error on both… https://hub.docker.com/r/iamdb/nginx-bedrock-wordpress/ and https://hub.docker.com/r/rija/docker-nginx-fpm-caches-wordpress/

        • Germán Nicolas Ollé

          I am not a Windows developer and I am not familiar with Kitematic, but it looks like it is like a virtual box to use docker easily.

          About images, I used in the post the official versions of wordpress and nginx.
          I recommend you to use always official images except in the case that you really are looking for something specific.

          WordPress: https://hub.docker.com/_/wordpress/
          NGINX: https://hub.docker.com/_/nginx/

          And just place your wordpress app behind the NGINX without opening any ports in your WordPress app. Just open your NGINX’s ports and in the settings create a redirection to your wordpress app. You can use the hosts alias directly.

          • Asterix

            Hmm, I see. I was interested in Docker just to have the same setup locally as on the live server I have built at Digitalocean. So I thought I could find one single Docker file with everything I needed like: Ubuntu16-nginx-mariadb-fast-cgi-php7 But i might have missed the whole point with Docker. It seems to me now that I am better off just installing Ubuntu on my laptop and then manually install nginx, mariadb, fast-cgi php7 and copy configs from my live server. Docker seems more complicated and makes me lose time.

          • Germán Nicolas Ollé

            All of that is realizable with Docker, also if you already know how make the setup manually (install mariadb, fast-cgi, etc..). One thing that you can do, is create your own Dockerfile ubuntu16.04 or ubuntu16.10 and just add all the extra steps to install everything that you need. Then your Dockerfile will look like this:

            FROM ubuntu:16.04
            RUN apt-get update &&
            apt-get install -yq –no-install-recommends mariadb-serve php ….

            After that you can build your own image with all the thing that you need, here is the real magic of Docker.

            Here you can see a little more about Dockerfile: https://docs.docker.com/engine/reference/builder/

            Good luck! 😉

          • Asterix

            This seemed to be a fantastic idea but now I have spent several hours googling around just to figure out how to make just any apt-get command work in Docker CLI with Powershell… 🙂 This should work shouldn’t it?? PS C:Program FilesDockerDocker> docker run apt-get install mariadb-server
            “docker.exe: Error: image library/apt-get:latest not found”
            I tried this with both official NGINX and official UBUNTU

          • Germán Nicolas Ollé

            The command “docker run ..” is to create container from your compiled docker images.

            You need to create a Dockerfile with all the steps tot build your own image (read the link that I sent you), and when you have all the steps correctly. You can “build” your image with. Run this command in the same folder where you have your Dockerfile: “docker build –tag my-own-image-name .”.

            When you image is ready, then you can run your containers with that image,
            “docker run –name my-container-name -d my-own-image-name”

            The Dockerfile should contain all the steps that you need to install and configure your environment, here are a lot of Dockerfile examples, uses them as a reference to build your own image based of ubuntu:16.04

            https://github.com/kstaken/dockerfile-examples

            Take care!