it from external hosts. You can expose port 80 instead if you do not have
a web server running on port 80 of the host machine.
- Connects to the `mysql_private` network so it can communicate with the
`mysql` container, and also publishes port 80 to port 30000 on all swarm
nodes.
- Has access to the `mysql_password` secret, but specifies a different
target file name within the container. The WordPress container uses
the mount point `/run/secrets/wp_db_password`.
- Sets the environment variable `WORDPRESS_DB_PASSWORD_FILE` to the file
path where the secret is mounted. The WordPress service reads the
MySQL password string from that file and add it to the `wp-config.php`
configuration file.
- Connects to the MySQL container using the username `wordpress` and the
password in `/run/secrets/wp_db_password` and creates the `wordpress`
database if it does not yet exist.
- Stores its data, such as themes and plugins, in a volume called `wpdata`
so these files persist when the service restarts.
```console
$ docker service create \
--name wordpress \
--replicas 1 \
--network mysql_private \
--publish published=30000,target=80 \
--mount type=volume,source=wpdata,destination=/var/www/html \
--secret source=mysql_password,target=wp_db_password \
-e WORDPRESS_DB_USER="wordpress" \
-e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \
-e WORDPRESS_DB_HOST="mysql:3306" \
-e WORDPRESS_DB_NAME="wordpress" \
wordpress:latest
```
6. Verify the service is running using `docker service ls` and
`docker service ps` commands.
```console
$ docker service ls
ID NAME MODE REPLICAS IMAGE
wvnh0siktqr3 mysql replicated 1/1 mysql:latest
nzt5xzae4n62 wordpress replicated 1/1 wordpress:latest
```
```console
$ docker service ps wordpress
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
aukx6hgs9gwc wordpress.1 wordpress:latest moby Running Running 52 seconds ago
```
At this point, you could actually revoke the WordPress service's access to
the `mysql_password` secret, because WordPress has copied the secret to its
configuration file `wp-config.php`. Don't do that for now, because we
use it later to facilitate rotating the MySQL password.
7. Access `http://localhost:30000/` from any swarm node and set up WordPress
using the web-based wizard. All of these settings are stored in the MySQL
`wordpress` database. WordPress automatically generates a password for your
WordPress user, which is completely different from the password WordPress
uses to access MySQL. Store this password securely, such as in a password
manager. You need it to log into WordPress after
[rotating the secret](#example-rotate-a-secret).
Go ahead and write a blog post or two and install a WordPress plugin or
theme to verify that WordPress is fully operational and its state is saved
across service restarts.
8. Do not clean up any services or secrets if you intend to proceed to the next
example, which demonstrates how to rotate the MySQL root password.
### Example: Rotate a secret
This example builds upon the previous one. In this scenario, you create a new
secret with a new MySQL password, update the `mysql` and `wordpress` services to
use it, then remove the old secret.
> [!NOTE]
>
> Changing the password on a MySQL database involves running extra
> queries or commands, as opposed to just changing a single environment variable
> or a file, since the image only sets the MySQL password if the database doesn’t
> already exist, and MySQL stores the password within a MySQL database by default.
> Rotating passwords or other secrets may involve additional steps outside of