Linux

Install WordPress with Docker Compose, Nginx, Apache with SSL

Disclosure: This post may contain affiliate links, which means we may receive a commission if you click a link and purchase something that we recommended.

Install WordPress with Docker, Nginx, Apache with SSL . In this guide you are going to learn how to make a best performance setup with Docker, Docker Compose, Nginx, Apache, PHP 8.1, MariaDB and Let’s Encrypt to run WordPress on Ubuntu 22.04.

We will also create volumes so the changes or updates will be preserved while container restarting.

This setup is tested on Google cloud with an instance running Ubuntu 22.04 OS. You can also make this setup in any cloud services like AWS or Azure or DigitalOcean or any dedicated or VPS servers.

Prerequisites

  1. Install Docker on Ubuntu 22.04
  2. Install Docker Compose on Ubuntu 22.04.

Please make sure you have completed all the above mentioned steps

  • Domain pointed to your server IP address.
  • Docker installed and configured.
  • Docker Compose installed and configured.

Once you have all the prerequisites done you can proceed to make the setup and configure WordPress.

Step 1: Create a project directory

SSH to your server and start by creating a new project directory named wp-project. You can also name it whatever you need.

mkdir wp-project

Step 2: Create Docker Compose YML File

Now navigate inside the project directory and create a new docker-compose.yml file with the following configuration.

cd wp-project

Create a new docker-compose.yml file.

nano docker-compose.yml

Copy the entire contents below and paste it in the file.

Make sure to replace the below mentioned environment variables.

version: "3.9"
services:
    wordpress:
        container_name: wordpress
        image: wordpress:php8.1-apache
        restart: always
        stdin_open: true
        tty: true
        environment:
            WORDPRESS_DB_HOST: mariadb
            WORDPRESS_DB_USER: db_user
            WORDPRESS_DB_PASSWORD: db_user_pass
            WORDPRESS_DB_NAME: db_name
        volumes:
            - wordpress_data:/var/www/html
            - ./wordpress:/var/www/html
    mariadb:
        container_name: mariadb
        image: mariadb
        restart: always
        environment:
            MYSQL_DATABASE: db_name
            MYSQL_USER: db_user
            MYSQL_PASSWORD: db_user_pass
            MYSQL_RANDOM_ROOT_PASSWORD: 'root_pass'
        volumes:
            - db_data:/var/lib/mysql
    nginx:
        container_name: nginx
        image: nginx:latest
        restart: unless-stopped
        ports:
            - 80:80
            - 443:443
        volumes:
            - ./nginx/conf:/etc/nginx/conf.d
            - ./certbot/conf:/etc/nginx/ssl
            - ./certbot/data:/var/www/html
    certbot:
        container_name: certbot
        image: certbot/certbot:latest
        command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email -d domain.com -d www.domain.com
        volumes:
            - ./certbot/conf:/etc/letsencrypt
            - ./certbot/logs:/var/log/letsencrypt
            - ./certbot/data:/var/www/html
volumes:
    db_data:
    wordpress_data:

Hit CTRL-X followed by Y and ENTER to save and exit the file.

Here are the configuration details.

  • version: Compose file version which is compatible with the Docker Engine. You can check compatibility here.
  • services: here we have 4 services named wordpress, mariadb, nginx and certbot.
  • image: We use latest WordPress with PHP 8.1, Apache, Mariadb, Nginx and Certbot images available in Docker hub.
  • volumes:
    • wordpress: we have configured this directory to be synced with the directory we wish to use as the web root inside the container.
    • conf: here we will place the Nginx configuration file to be synced with the default Nginx conf.d folder inside the container.
    • cedtbot/conf: this is where we will receive the SSL certificate and this will be synced with the folder we wish to inside the container.
    • ports: configure the container to listen upon the listed ports.
    • command: the command used to receive the SSL certificate.
  • environment: here we list all the environment variables that are available for the WordPress image.
    • WORDPRESS_DB_HOST: Here we are using the service name of MariaDB container.
    • WORDPRESS_DB_USER: Same as the one we have configured in mariadb service.
    • WORDPRESS_DB_PASSWORD: Same as the one we have configured in mariadb service.
    • WORDPRESS_DB_NAME: Same as the one we have configured in mariadb service.

Step 3: Configure Nginx

As per the docker-compose.yml configuration we need to create the default.conf file inside the nginx/conf directory.

Create the directory besides your docker-compose.yml file to hold the configuration file.

mkdir -p nginx/conf

Create a file named default.conf.

nano nginx/conf/default.conf

Place the following configurations, here we use reverse proxy configuration to wordpress container running Apache.

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

    server_name domain.com www.domain.com;

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

    location ~ /.well-known/acme-challenge {
        allow all; 
        root /var/www/html;
    }

    location / {
        try_files $uri @apache;
    }

    location ~ ^/.user.ini {
        deny all;
    }

    location ~*  .(svg|svgz)$ {
        types {}
        default_type image/svg+xml;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location @apache {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~[^?]*/$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~ .php$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~/. {
        deny all;
        access_log off;
        log_not_found off;
    }
} 

Hit CTRL-X followed by Y and ENTER to save and exit the file.

Now you have your docker compose configuration and your Nginx configuration.

Step 4: Deploy WordPress with Docker Compose

Start the containers using the following command, you will receive the SSL certificates once the containers are started.

docker-compose up -d

Once all containers are started you will see two additional directories certbot and wordpress created alongside your docker-compose.yml file.

The directory wordpress holds all your WordPress website source code.

The directory certbot holds all the files related to your SSL certificates.

To view the containers you can execute the following command.

docker-compose ps

Step 5: Configure Let’s Encrypt SSL with Nginx

As you have received the Let’s Encrypt SSL certificate you can configure HTTPS and setup redirection to HTTPS.

Edit the default.conf and make the following changes.

nano nginx/conf/default.conf
server {
    listen [::]:80;
    listen 80;

    server_name domain.com www.domain;

    return 301 https://www.domain.com$request_uri;
}

 server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;

    server_name domain.com;

    ssl_certificate /etc/nginx/ssl/live/domain.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/domain.com/privkey.pem;

    return 301 https://www.domain.com$request_uri; 
}

server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;

    server_name www.domain.com;

    ssl_certificate /etc/nginx/ssl/live/domain.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/domain.com/privkey.pem;

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

    location ~ /.well-known/acme-challenge {
         allow all; 
         root /var/www/html;
    }

    location / {
        try_files $uri @apache;
    }

    location ~ ^/.user.ini {
        deny all;
    }

    location ~*  .(svg|svgz)$ {
        types {}
        default_type image/svg+xml;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location @apache {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~[^?]*/$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~ .php$ {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_pass http://wordpress:80;
    }

    location ~/. {
        deny all;
        access_log off;
        log_not_found off;
    }
} 

Hit CTRL-X followed by Y and ENTER to save and exit the file.

Now restart the Nginx service to load the new configurations.

docker-compose restart nginx

Now you can check your domain name from your browser. You will get a redirection to HTTPS and you will see the WordPress installation page to complete the installation.

Learn the most Advanced Techniques of WordPress with this easy to learn course now.

Conclusion

Now you have learned how to install and setup WordPress with Nginx, Apache, PHP 8.1, MariaDB and Let’s Encrypt with Docker and Docker Compose on Ubuntu 22.04.

Thanks for your time. If you face any problem or any feedback, please leave a comment below.

12 Comments

  1. Wonderful publication.
    But, I am getting an nginx error “403 Forbidden. nginx/1.21.6”

    • Same here…. This tutorial is very nice and explains the various steps but unfortunatly, it is buggy!

  2. This is some random copy/paste from the internet. The config is buggy and I guarantee you the guy has never run it in his life.

    image: wordpress:php8.1-apache

    and then he suggests to configure nginx

    lol what a looser

    • Sorry for your misunderstanding, you can’t find this config elsewhere. This setup works. I think you don’r understand the configuration. Please try and it will work. It is a reverse proxy setup with Apache and Nginx so you can get the speed of Nginx and power of Apache also you can get the benefits of using .htaccess.

  3. One can’t assign two different mount points to the same location, yet in your code you do.

    volumes:
    – wordpress_data:/var/www/html
    – ./wordpress:/var/www/html

      • Real Deal is correct. this config will not work with the duplicated wordpress_data mount point. I’m presently stuck trying to get traffic from the underlying apache to load data – its blocking the certbot startup….

    • I am getting the following error which I think is related to this:

      ERROR: Duplicate mount points: [wordpress_data:/var/www/html:rw, /root/wp-project/ :rw]

  4. I have a problem to load .css and .js files.. this config seems to block css

Write A Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.