Securing WordPress with Docker and AWS Lightsail
Summary
In this chapter, we will improve the security of our WordPress stack by moving the database passwords out of the main docker-compose.yml file.
Instead of storing passwords directly inside the Compose file, we will use Docker Secrets in conjunction with Docker Swarm. This allows the mysql, wordpress, and wpcli services to read password values from files mounted inside the running containers.
Sample folder for this chapter:
cd wordpressawslightsailsamples/Securing_WordPress_with_Docker_and_AWS_Lightsail
This folder contains the docker-compose.yml file used throughout this chapter:
Understanding WordPress Security with Docker Compose
What Are Docker Secrets?
We will use Docker Secrets to improve the security of our WordPress stack.
Docker Secrets provide a secure and reliable way to manage sensitive information required by containers at runtime. This includes database passwords, usernames, and other credentials that should not be stored directly inside a docker-compose.yml file.
services:
mysql:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
ports:
- "3306:3306"
secrets:
- mysql_password
- mysql_root_password
volumes:
- mysql_data:/var/lib/mysql
networks:
- wp-network
deploy:
replicas: 1
restart_policy:
condition: on-failure
wordpress:
depends_on:
- mysql
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: mysql:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
WORDPRESS_DEBUG: 1
secrets:
- mysql_password
ports:
- "80:80"
volumes:
- wp_html:/var/www/html
networks:
- wp-network
deploy:
replicas: 1
restart_policy:
condition: on-failure
wpcli:
image: wordpress:cli
entrypoint: wp
working_dir: /var/www/html
volumes:
- wp_html:/var/www/html
environment:
WORDPRESS_DB_HOST: mysql:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
secrets:
- mysql_password
networks:
- wp-network
deploy:
replicas: 0
volumes:
wp_html:
external: true
mysql_data:
external: true
networks:
wp-network:
driver: overlay
secrets:
mysql_root_password:
external: true
mysql_password:
external: true
Docker Secrets require Docker Swarm when deploying services with docker stack deploy. Before we can use secrets in our WordPress stack, we need to make sure Swarm mode is enabled on our Docker server, whether it is running on Lightsail or Docker Desktop.
Docker Swarm is Docker’s built-in tool for managing and running containers as services, making it suitable for deploying and managing our WordPress stack.
1. Check Whether Docker Swarm Is Already Enabled
To determine whether the Docker host MyUbuntuInstance is already part of a Docker Swarm, run:
docker -H ssh://MyUbuntuInstance node ls
If Swarm mode has not yet been initialised, you may encounter an error similar to the following:
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
This indicates that Docker is running, but the server has not yet been configured as a Swarm manager.
2. Initialise Docker Swarm
To initialise Docker Swarm on the remote Docker host MyUbuntuInstance, run:
docker -H ssh://MyUbuntuInstance swarm init
Docker should return output similar to the following:
Swarm initialized: current node (nyj0pha0ecxkwqd7eld75tv0v) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-60tdhafh6cak85ol8n5lx4okr9fhfoc3kloncihy4hmdlyf2gw-0nxhnq8gpdau3su0g36ybasu8 172.26.2.42:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
This indicates that Swarm mode has been successfully enabled and that the current server is now functioning as the Swarm manager.
3. Check the Swarm Node List Again
Run the following command again to confirm that the node is now part of the Swarm:
docker -H ssh://MyUbuntuInstance node ls
You should see output similar to the following:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
nyj0pha0ecxkwqd7eld75tv0v * ip-172-26-2-42 Ready Active Leader 28.4.0
4. Why Use Docker Secrets?
In the previous chapter, Docker Compose and WordPress, we stored the passwords directly inside the sample docker-compose.yml file:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_PASSWORD: wordpress
WORDPRESS_DB_PASSWORD: wordpress
While this approach is suitable for a simple example, storing passwords directly in the Compose file is not considered a best practice for secure configurations.
In this chapter, we will move these password values to Docker Secrets. Instead of including the passwords directly in docker-compose.yml, the services will retrieve them from secret files at runtime:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
5. Set Up the Docker Secrets
Before deploying the WordPress stack, we need to create the Docker Secrets that will be used by the MySQL and WordPress services.
We will use the docker secret create command to create each secret.
Create the Secrets in Docker
1. Create the mysql_password and mysql_root_password Secrets
When creating a password file for a MySQL Docker Secret, make sure the file does not contain a trailing carriage return or line-feed character. An extra newline becomes part of the password and can cause MySQL authentication errors when the secret is read.
Reference: Docker MySQL newline issue
mysql_password
Windows
Set-Content -Path .\mysql_password.txt -Value "wordpress" -NoNewline:$true
docker -H ssh://MyUbuntuInstance secret create mysql_password .\mysql_password.txt
macOS / Linux
printf '%s' 'wordpress' > mysql_password.txt
docker -H ssh://MyUbuntuInstance secret create mysql_password ./mysql_password.txt
mysql_root_password
Windows
Set-Content -Path .\mysql_root_password.txt -Value "wordpress" -NoNewline:$true
docker -H ssh://MyUbuntuInstance secret create mysql_root_password .\mysql_root_password.txt
macOS / Linux
printf '%s' 'wordpress' > mysql_root_password.txt
docker -H ssh://MyUbuntuInstance secret create mysql_root_password ./mysql_root_password.txt
2. List the Secrets
docker -H ssh://MyUbuntuInstance secret ls
ID NAME DRIVER CREATED UPDATED
z7w3jg9l8mascak2h46i073g0 mysql_password 4 weeks ago 4 weeks ago
ucu7gnnsaw41wdrt8n2dcdpgd mysql_root_password 4 weeks ago 4 weeks ago
3. Stop the Docker Compose Stack from Docker Compose and WordPress
Before deploying the updated WordPress stack that uses Docker Secrets, stop the Docker Compose stack created in the previous chapter, Docker Compose and WordPress.
Change to the sample directory containing the previous docker-compose.yml file:
cd wordpressawslightsailsamples/Docker_Compose_and_Wordpress
Shut down and remove the containers and networks created by that Compose project:
docker -H ssh://MyUbuntuInstance compose down
The named volumes remain in place, so your WordPress files and MySQL database data can be used again when you deploy the updated stack.
4. Deploy the New WordPress Stack
Change to the sample directory that contains the new docker-compose.yml file:
cd wordpressawslightsailsamples/Securing_WordPress_with_Docker_and_Lightsail
Deploy the stack:
docker -H ssh://MyUbuntuInstance stack deploy -c docker-compose.yml wordpress-stack
Options Explained
dockerruns the Docker command-line interface.-H ssh://MyUbuntuInstanceconnects Docker to the remote Lightsail instance over SSH.stack deploycreates a new Docker Swarm stack or updates an existing stack.-c docker-compose.ymlspecifies the Docker Compose file that defines the WordPress services, networks, volumes, and secrets.wordpress-stackspecifies the Docker stack name used as a prefix for services, networks, and other deployment resources.
5. Verify the WordPress Stack Services
List the services deployed as part of wordpress-stack:
docker -H ssh://MyUbuntuInstance stack services wordpress-stack
Options Explained
dockerruns the Docker command-line interface.-H ssh://MyUbuntuInstanceconnects Docker to the remote Lightsail instance over SSH.stack serviceslists the services deployed within the specified stack.wordpress-stackspecifies the name of the stack.
The command shows details for each service, including its name, replica status, container image, and published ports.
ID NAME MODE REPLICAS IMAGE PORTS
17zb0ywotjss wordpress-stack_mysql replicated 1/1 mysql:latest *:3306->3306/tcp
v0v2ameyqd2x wordpress-stack_wordpress replicated 1/1 wordpress:latest *:80->80/tcp
f0jxrzcv873r wordpress-stack_wpcli replicated 0/0 wordpress:cli
6. Retrieve the Lightsail Static IP Address
Using the AWS CLI, you can retrieve the current static IP address assigned to the Lightsail instance MyUbuntuInstance:
aws lightsail get-static-ip --static-ip-name MyUbuntuInstanceStaticIP --region ap-southeast-2 --profile MyUbuntuProfile
Access WordPress Remotely
Once the containers are running, open a web browser and go to:
http://ipAddress
Replace ipAddress with the static IP address returned by the AWS CLI command.
7. Stopping the WordPress Stack with Docker Stack
To gracefully remove the WordPress stack from the remote Lightsail instance, including its associated services and containers, run:
docker -H ssh://MyUbuntuInstance stack rm wordpress-stack
Further Reading
- Manage secrets securely in Docker Compose
- Manage sensitive data with Docker secrets
- Docker stack services

Leave a Reply
You must be logged in to post a comment.