I’ve switched from using Traefik and WordPress for my website. Now, I use an internal Nginx proxy within Docker and my site is built with Hugo. To learn more about this change, you can read my post: Migrating from WordPress to Hugo
This first post will guide you on how to establish your own self-hosted Wordpress website using Docker, mirroring the setup of this very site. For this example, I’m using a physical Ubuntu machine connected to a Unifi Dream Machine Pro. You have the flexibility to employ a VPS or any bare-metal operating system that supports Docker. While this tutorial focuses on Ubuntu-specific tools, adjustments can be made for other environments if you’re comfortable with Docker.
Disclosure: As an Amazon Associate, I earn from qualifying purchases. Your support through these links helps maintain this blog, but rest assured, the pricing remains the same for you whether you use my links or not. Thanks for your support!
This guide presumes you have Ubuntu installed, access to a user account with root privileges, Docker and Docker-Compose set up, a domain name under your ownership (consider Google Domains or Hover if you need one), the ability to manage your domain’s DNS records (CloudFlare is recommended), and the capability to forward ports on your network (unless using a VPS or externally hosted OS).
Ubuntu’s environment file system is particularly useful for securely storing sensitive variables. This simplifies sharing docker-compose files without exposing confidential information on platforms like GitHub. While there might be other methods for managing secrets within Docker, they won’t be covered in this tutorial. Lastly, prioritize security when hosting a website on your network. Additionally, if you’re running multiple externally accessible web servers, you might find this post on reverse proxies helpful: https://nexus-security.github.io/running-a-reverse-proxy-using-docker-made-simple/.
Prepare Your Domain
For your domain (e.g., whitematter.tech), add DNS records that direct it to your server’s public IP address. For home networks, this is the public IP provided by your ISP, which can be found at whatismyip.com. Personally, I prefer dynamic DNS solutions like duckdns.org, allowing automatic updates to my public IP in the absence of a static IP from my ISP. For a better understanding of how to integrate duckdns, refer to this video. The following image illustrates how CloudFlare is configured for my domain, pointing to my duckdns address (without duckdns, “Content” would be your public IP, such as 177.99.88.10).
Set Environment Variables
In Ubuntu, access the Environment file with the command:
|
|
Below the PATH variable, paste the following, replacing the generic values in red with your specific information. Do not modify the PATH variable’s content.
For your time zone (TZ), refer to this list.
Replace “username” in the USERDIR with your Ubuntu username. It’s strongly recommended to use a password manager like 1Password to generate and securely store passwords for MySQL and your WordPress databases.
|
|
Save the file (“Ctrl” + “o” followed by “Enter”) and exit (“Ctrl” + “x”).
A logout/login or a system reboot is needed for the changes to take effect:
|
|
Preparing Directories and Permissions
Execute the following commands. You can run them all at once or individually. ${USERDIR}
will be populated from the environment file.
|
|
Create Traefik static configuration file.
Use the following command to create the Traefik static configuration file (${USERDIR}
will be taken from your environment file):
|
|
Paste the following content into the file, ensuring you replace the placeholder email address in red with your own.
Two caServer addresses are provided at the end of the file. The one containing “staging” is intended for testing purposes. While using the staging server certificates is beneficial during setup, be aware that browsers may display security warnings. The LetsEncrypt server has limitations on the number of certificates issued within a specific timeframe. To disable an address, simply add “#” at the beginning of the line – Ubuntu will ignore lines prefixed with “#.”
|
|
Save the file (“Ctrl” + “o” and “Enter”) and exit (“Ctrl” + “x”).
Prepare Traefik and Create Traefik Dynamic Config
For security, your Traefik password needs to be hashed using MD5, SHA1, or BCrypt. BCrypt is recommended for its stronger encryption.
Online Htpassword generators can be used for this purpose. For instance, if your username is “admin” and password is “password1234,” the BCrypt hash would resemble this: “admin:$2y$10$d0yk7WE.XqhF5bT1DdJhduRFOM5JSabTiSFCTnbC2.JgMolypHgS2.” Utilize a password manager (1Password is recommended) to generate a strong password for this step.
Once your username, password, and its hashed version are ready, proceed with the following:
Create the Traefik dynamic configuration file:
|
|
Paste the content below into the dynamic.yml file, replacing the placeholder username and password (in red) with your generated hashed credentials.
This configuration utilizes the page-ratelimit middleware. The provided values permit an average of 50 requests per second with a burst limit of 50. Feel free to adjust these values as needed.
|
|
Save (“Ctrl” + “o” and “Enter”) and exit (“Ctrl” + “x”).
Create the Traefik Docker-Compose File
Create the Traefik docker-compose file:
|
|
Copy the content below into the file, noting that fields enclosed in ${ }
will be filled in from the environment file.
This configuration uses the latest version of Traefik (currently v2.2.6). If you prefer to stick to the latest release within the 2.2.X series, specify the image tag as “traefik:chevrotin.” Be mindful that using the “latest” tag might lead to compatibility issues if future Traefik versions (v3, etc.) introduce breaking changes. Check dockerhub for available release tags.
This setup routes ports 80 (http) and 443 (https) to the Traefik container.
You can find a copy of this docker-compose.yml file on GitHub.
|
|
Save (“Ctrl” + “o” and “Enter”) and exit (“Ctrl” + “x”).
Create the WordPress Docker-Compose File
Create the WordPress docker-compose file:
|
|
Copy the content below, noting that fields enclosed in ${ }
will be populated from the environment file.
docker-compose.yml
|
|
Create the Proxy Network and Start Traefik
With all files in place, create the proxy network and start Traefik.
Create the proxy network:
|
|
Start the Traefik container:
|
|
Allow a few minutes for startup, then try to access the Traefik web admin page at https://traefik.yourdomain.com (replace “yourdomain.com” with your domain, matching the one in the environment file). If successful, log in using the non-hashed username and password. You should see the following:
If you can’t access the page, you might need to forward ports 80 and 443 to your Ubuntu server (see the example screenshot for forwarding to Ubuntu at 10.100.0.15). This step is not required for VPS or externally hosted options. This post provides recommendations for securing your network. Once ports are forwarded, you can proceed.
Start the Remaining Containers
Important: Remember to log in to WordPress and Portainer immediately after starting them to set passwords and secure access.
Start the remaining containers:
|
|
Give the containers a few minutes to start, and then try to access WordPress and Portainer through your browser.
WordPress:
Access WordPress at “https://yourdomain.com" (replace “yourdomain.com” with your domain).
You should land on the initial WordPress setup screen. Create a strong password for your WordPress user account. A password manager like 1Password can help with this.
A success message will indicate a successful WordPress installation.
Portainer:
Access Portainer at “https://portainer.yourdomain.com" (replace “yourdomain.com” with the domain from Section 1).
You’ll be directed to the Portainer setup screen. Create a strong password for your Portainer user account. Again, using a password manager like 1Password is recommended.
After setting your Portainer password, log in. In the left-hand menu, click “containers.” This view lists all running containers. From here, you can stop, start, restart, remove, and otherwise manage installed containers.
Getting Started with WordPress
It’s a good practice to increase the PHP memory limit and maximum file upload size for new WordPress installations. One approach is to modify the .htaccess file. Access this file in the terminal (${USERDIR}
will be taken from the environment file; the file path below assumes you’ve kept the WordPress volume as defined in the docker-compose file).
|
|
Add the following lines to the file:
|
|
Save (“Ctrl” + “o” and “Enter”) and exit (“Ctrl” + “x”).
Restart the WordPress container for the changes to take effect. You can either do this through Portainer or restart all containers:
|
|
WordPress Admin Page:
You can access your WordPress admin area at “https://yourdomain.com/wp-admin" (replace “yourdomain.com” with your domain). Use the credentials you set up in Section 14 to log in.
Change the WordPress Theme:
You can easily change your blog or website’s theme.
Click “Add New Theme,” search for your desired theme, hover over it, and click “Install.” After installation, click “Activate.”
Create a Blog Post:
To add a new blog post, click “Posts,” then “Add New.” This will generate a blank post. The default WordPress block editor is a user-friendly option for creating content. If you prefer, you can install page builder plugins. Here’s what the default block editor looks like:
After crafting your post, click “Publish,” and then click it again to make it live. You can view your post by navigating to the address displayed under “Post address.” Your blog post will resemble this. Customization can be achieved through settings and plugins.