其他分享
首页 > 其他分享> > 2021-06-17

2021-06-17

作者:互联网

Introduction

WordPress is a free and open-source Content Management System (CMS) built on a MySQL database with PHP processing. Thanks to its extensible plugin architecture and templating system, and the fact that most of its administration can be done through the web interface, WordPress is a popular choice when creating different types of websites, from blogs to product pages to eCommerce sites.

Running WordPress typically involves installing a LAMP (Linux, Apache, MySQL, and PHP) or LEMP (Linux, Nginx, MySQL, and PHP) stack, which can be time-consuming. However, by using tools like Docker and Docker Compose, you can simplify the process of setting up your preferred stack and installing WordPress. Instead of installing individual components by hand, you can use images, which standardize things like libraries, configuration files, and environment variables, and run these images in containers, isolated processes that run on a shared operating system. Additionally, by using Compose, you can coordinate multiple containers — for example, an application and database — to communicate with one another.

In this tutorial, you will build a multi-container WordPress installation. Your containers will include a MySQL database, an Nginx web server, and WordPress itself. You will also secure your installation by obtaining TLS/SSL certificates with Let’s Encrypt for the domain you want associated with your site. Finally, you will set up a cron job to renew your certificates so that your domain remains secure.

Prerequisites

To follow this tutorial, you will need:

Step 1 — Defining the Web Server Configuration

Before running any containers, our first step will be to define the configuration for our Nginx web server. Our configuration file will include some WordPress-specific location blocks, along with a location block to direct Let’s Encrypt verification requests to the Certbot client for automated certificate renewals.

First, create a project directory for your WordPress setup called wordpress and navigate to it:


   
  • mkdir wordpress && cd wordpress
  Copy

Next, make a directory for the configuration file:


   
  • mkdir nginx-conf
  Copy

Open the file with nano or your favorite editor:


   
  • nano nginx-conf/nginx.conf
  Copy

In this file, we will add a server block with directives for our server name and document root, and location blocks to direct the Certbot client’s request for certificates, PHP processing, and static asset requests.

Paste the following code into the file. Be sure to replace example.com with your own domain name:

~/wordpress/nginx-conf/nginx.conf
server {
        listen 80;
        listen [::]:80;
    server_name <span class="highlight">example.com</span> www.<span class="highlight">example.com</span><span class="token punctuation">;</span>

    index <span class="highlight">index.php</span> index.html index.htm<span class="token punctuation">;</span>

    root /var/www/html<span class="token punctuation">;</span>

    location ~ /.well-known/acme-challenge <span class="token punctuation">{</span>
            allow all<span class="token punctuation">;</span>
            root /var/www/html<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location / <span class="token punctuation">{</span>
            try_files <span class="token variable">$uri</span> <span class="token variable">$uri</span>/ /index.php<span class="token variable">$is_args</span><span class="token variable">$args</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location ~ <span class="token punctuation">\</span>.php$ <span class="token punctuation">{</span>
            try_files <span class="token variable">$uri</span> <span class="token operator">=</span><span class="token number">404</span><span class="token punctuation">;</span>
            fastcgi_split_path_info ^<span class="token punctuation">(</span>.+<span class="token punctuation">\</span>.php<span class="token punctuation">)</span><span class="token punctuation">(</span>/.+<span class="token punctuation">)</span>$<span class="token punctuation">;</span>
            fastcgi_pass <span class="highlight">wordpress</span>:9000<span class="token punctuation">;</span>
            fastcgi_index index.php<span class="token punctuation">;</span>
            include fastcgi_params<span class="token punctuation">;</span>
            fastcgi_param SCRIPT_FILENAME <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span><span class="token punctuation">;</span>
            fastcgi_param PATH_INFO <span class="token variable">$fastcgi_path_info</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location ~ /<span class="token punctuation">\</span>.ht <span class="token punctuation">{</span>
            deny all<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location <span class="token operator">=</span> /favicon.ico <span class="token punctuation">{</span>
            log_not_found off<span class="token punctuation">;</span> access_log off<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    location <span class="token operator">=</span> /robots.txt <span class="token punctuation">{</span>
            log_not_found off<span class="token punctuation">;</span> access_log off<span class="token punctuation">;</span> allow all<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    location ~* <span class="token punctuation">\</span>.<span class="token punctuation">(</span>css<span class="token operator">|</span>gif<span class="token operator">|</span>ico<span class="token operator">|</span>jpeg<span class="token operator">|</span>jpg<span class="token operator">|</span>js<span class="token operator">|</span>png<span class="token punctuation">)</span>$ <span class="token punctuation">{</span>
            expires max<span class="token punctuation">;</span>
            log_not_found off<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

Copy

Our server block includes the following information:

Directives:

Location Blocks:

For more information about FastCGI proxying, see Understanding and Implementing FastCGI Proxying in Nginx. For information about server and location blocks, see Understanding Nginx Server and Location Block Selection Algorithms.

Save and close the file when you are finished editing. If you used nano, do so by pressing CTRL+X, Y, then ENTER.

With your Nginx configuration in place, you can move on to creating environment variables to pass to your application and database containers at runtime.

Step 2 — Defining Environment Variables

Your database and WordPress application containers will need access to certain environment variables at runtime in order for your application data to persist and be accessible to your application. These variables include both sensitive and non-sensitive information: sensitive values for your MySQL root password and application database user and password, and non-sensitive information for your application database name and host.

Rather than setting all of these values in our Docker Compose file — the main file that contains information about how our containers will run — we can set the sensitive values in an .env file and restrict its circulation. This will prevent these values from copying over to our project repositories and being exposed publicly.

In your main project directory, ~/wordpress, open a file called .env:


   
  • nano .env
  Copy

The confidential values that we will set in this file include a password for our MySQL root user, and a username and password that WordPress will use to access the database.

Add the following variable names and values to the file. Remember to supply your own values here for each variable:

~/wordpress/.env
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
  Copy

We have included a password for the root administrative account, as well as our preferred username and password for our application database.

Save and close the file when you are finished editing.

Because your .env file contains sensitive information, you will want to ensure that it is included in your project’s .gitignore and .dockerignore files, which tell Git and Docker what files not to copy to your Git repositories and Docker images, respectively.

If you plan to work with Git for version control, initialize your current working directory as a repository with git init:


   
  • git init
  Copy

Then open a .gitignore file:


   
  • nano .gitignore
  Copy

Add .env to the file:

~/wordpress/.gitignore
.env
  Copy

Save and close the file when you are finished editing.

Likewise, it’s a good precaution to add .env to a .dockerignore file, so that it doesn’t end up on your containers when you are using this directory as your build context.

Open the file:


   
  • nano .dockerignore
  Copy

Add .env to the file:

~/wordpress/.dockerignore
.env
  Copy

Below this, you can optionally add files and directories associated with your application’s development:

~/wordpress/.dockerignore
.env
.git
docker-compose.yml
.dockerignore
  Copy

Save and close the file when you are finished.

With your sensitive information in place, you can now move on to defining your services in a docker-compose.yml file.

Step 3 — Defining Services with Docker Compose

Your docker-compose.yml file will contain the service definitions for your setup. A service in Compose is a running container, and service definitions specify information about how each container will run.

Using Compose, you can define different services in order to run multi-container applications, since Compose allows you to link these services together with shared networks and volumes. This will be helpful for our current setup since we will create different containers for our database, WordPress application, and web server. We will also create a container to run the Certbot client in order to obtain certificates for our webserver.

To begin, open the docker-compose.yml file:


   
  • nano docker-compose.yml
  Copy

Add the following code to define your Compose file version and db database service:

~/wordpress/docker-compose.yml
version: '3'

services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: ‘–default-authentication-plugin=mysql_native_password’
networks:
- app-network 

Copy

The db service definition contains the following options:

Next, below your db service definition, add the definition for your wordpress application service:

~/wordpress/docker-compose.yml
...
  wordpress:
    depends_on:
      - db
    image: wordpress:5.1.1-fpm-alpine
    container_name: wordpress
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wordpress:/var/www/html
    networks:
      - app-network
  Copy

In this service definition, we are naming our container and defining a restart policy, as we did with the db service. We’re also adding some options specific to this container:

Next, below the wordpress application service definition, add the following definition for your webserver Nginx service:

~/wordpress/docker-compose.yml
...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network
  Copy

Again, we’re naming our container and making it dependent on the wordpress container in order of starting. We’re also using an alpine image — the 1.15.12-alpine Nginx image.

This service definition also includes the following options:

And again, we’ve added this container to the app-network network.

Finally, below your webserver definition, add your last service definition for the certbot service. Be sure to replace the email address and domain names listed here with your own information:

~/wordpress/docker-compose.yml
certbot:
  depends_on:
    - webserver
  image: certbot/certbot
  container_name: certbot
  volumes:
    - certbot-etc:/etc/letsencrypt
    - wordpress:/var/www/html
  command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com
  Copy

This definition tells Compose to pull the certbot/certbot image from Docker Hub. It also uses named volumes to share resources with the Nginx container, including the domain certificates and key in certbot-etc and the application code in wordpress.

Again, we’ve used depends_on to specify that the certbot container should be started once the webserver service is running.

We’ve also included a command option that specifies a subcommand to run with the container’s default certbot command. The certonly subcommand will obtain a certificate with the following options:

Below the certbot service definition, add your network and volume definitions:

~/wordpress/docker-compose.yml
...
volumes:
  certbot-etc:
  wordpress:
  dbdata:

networks:
app-network:
driver: bridge 

Copy

Our top-level volumes key defines the volumes certbot-etc, wordpress, and dbdata. When Docker creates volumes, the contents of the volume are stored in a directory on the host filesystem, /var/lib/docker/volumes/, that’s managed by Docker. The contents of each volume then get mounted from this directory to any container that uses the volume. In this way, it’s possible to share code and data between containers.

The user-defined bridge network app-network enables communication between our containers since they are on the same Docker daemon host. This streamlines traffic and communication within the application, as it opens all ports between containers on the same bridge network without exposing any ports to the outside world. Thus, our db, wordpress, and webserver containers can communicate with each other, and we only need to expose port 80 for front-end access to the application.

The finished docker-compose.yml file will look like this:

~/wordpress/docker-compose.yml
version: '3'

services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: ‘–default-authentication-plugin=mysql_native_password’
networks:
- app-network

wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER= M Y S Q L U S E R < / s p a n > − < s p a n c l a s s = " t o k e n a s s i g n − l e f t v a r i a b l e " > W O R D P R E S S D B P A S S W O R D < / s p a n > < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n v a r i a b l e " > MYSQL_USER</span> - <span class="token assign-left variable">WORDPRESS_DB_PASSWORD</span><span class="token operator">=</span><span class="token variable"> MYSQLU​SER</span>−<spanclass="tokenassign−leftvariable">WORDPRESSD​BP​ASSWORD</span><spanclass="tokenoperator">=</span><spanclass="tokenvariable">MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network

webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- “80:80”
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network

certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com

volumes:
certbot-etc:
wordpress:
dbdata:

networks:
app-network:
driver: bridge 

Copy

Save and close the file when you are finished editing.

With your service definitions in place, you are ready to start the containers and test your certificate requests.

Step 4 — Obtaining SSL Certificates and Credentials

We can start our containers with the docker-compose up command, which will create and run our containers in the order we have specified. If our domain requests are successful, we will see the correct exit status in our output and the right certificates mounted in the /etc/letsencrypt/live folder on the webserver container.

Create the containers with docker-compose up and the -d flag, which will run the db, wordpress, and webserver containers in the background:


   
  • docker-compose up -d
  Copy

You will see output confirming that your services have been created:


 
  Output
 Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot   ... done

Using docker-compose ps, check the status of your services:


   
  • docker-compose ps
  Copy

If everything was successful, your db, wordpress, and webserver services will be Up and the certbot container will have exited with a 0 status message:


 
  Output
   Name                 Command               State           Ports       
-------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0                      
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp
webserver   nginx -g daemon off;             Up       0.0.0.0:80->80/tcp 
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp           

If you see anything other than Up in the State column for the db, wordpress, or webserver services, or an exit status other than 0 for the certbot container, be sure to check the service logs with the docker-compose logs command:


   
  • docker-compose logs service_name
  Copy

You can now check that your certificates have been mounted to the webserver container with docker-compose exec:


   
  • docker-compose exec webserver ls -la /etc/letsencrypt/live
  Copy

If your certificate requests were successful, you will see output like this:


 
  Output
 total 16
drwx------    3 root     root          4096 May 10 15:45 .
drwxr-xr-x    9 root     root          4096 May 10 15:45 ..
-rw-r--r--    1 root     root           740 May 10 15:45 README
drwxr-xr-x    2 root     root          4096 May 10 15:45 example.com

Now that you know your request will be successful, you can edit the certbot service definition to remove the --staging flag.

Open docker-compose.yml:


   
  • nano docker-compose.yml
  Copy

Find the section of the file with the certbot service definition, and replace the --staging flag in the command option with the --force-renewal flag, which will tell Certbot that you want to request a new certificate with the same domains as an existing certificate. The certbot service definition will now look like this:

~/wordpress/docker-compose.yml
...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - certbot-var:/var/lib/letsencrypt
      - wordpress:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
  Copy

You can now run docker-compose up to recreate the certbot container. We will also include the --no-deps option to tell Compose that it can skip starting the webserver service, since it is already running:


   
  • docker-compose up --force-recreate --no-deps certbot
  Copy

You will see output indicating that your certificate request was successful:


 
  Output
 Recreating certbot ... done
Attaching to certbot
certbot      | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot      | Plugins selected: Authenticator webroot, Installer None
certbot      | Renewing an existing certificate
certbot      | Performing the following challenges:
certbot      | http-01 challenge for example.com
certbot      | http-01 challenge for www.example.com
certbot      | Using the webroot path /var/www/html for all unmatched domains.
certbot      | Waiting for verification...
certbot      | Cleaning up challenges
certbot      | IMPORTANT NOTES:
certbot      |  - Congratulations! Your certificate and chain have been saved at:
certbot      |    /etc/letsencrypt/live/example.com/fullchain.pem
certbot      |    Your key file has been saved at:
certbot      |    /etc/letsencrypt/live/example.com/privkey.pem
certbot      |    Your cert will expire on 2019-08-08. To obtain a new or tweaked
certbot      |    version of this certificate in the future, simply run certbot
certbot      |    again. To non-interactively renew *all* of your certificates, run
certbot      |    "certbot renew"
certbot      |  - Your account credentials have been saved in your Certbot
certbot      |    configuration directory at /etc/letsencrypt. You should make a
certbot      |    secure backup of this folder now. This configuration directory will
certbot      |    also contain certificates and private keys obtained by Certbot so
certbot      |    making regular backups of this folder is ideal.
certbot      |  - If you like Certbot, please consider supporting our work by:
certbot      | 
certbot      |    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
certbot      |    Donating to EFF:                    https://eff.org/donate-le
certbot      | 
certbot exited with code 0

With your certificates in place, you can move on to modifying your Nginx configuration to include SSL.

Step 5 — Modifying the Web Server Configuration and Service Definition

Enabling SSL in our Nginx configuration will involve adding an HTTP redirect to HTTPS, specifying our SSL certificate and key locations, and adding security parameters and headers.

Since you are going to recreate the webserver service to include these additions, you can stop it now:


   
  • docker-compose stop webserver
  Copy

Before we modify the configuration file itself, let’s first get the recommended Nginx security parameters from Certbot using curl:


   
  • curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
  Copy

This command will save these parameters in a file called options-ssl-nginx.conf, located in the nginx-conf directory.

Next, remove the Nginx configuration file you created earlier:


   
  • rm nginx-conf/nginx.conf
  Copy

Open another version of the file:


   
  • nano nginx-conf/nginx.conf
  Copy

Add the following code to the file to redirect HTTP to HTTPS and to add SSL credentials, protocols, and security headers. Remember to replace example.com with your own domain:

~/wordpress/nginx-conf/nginx.conf
server {
        listen 80;
        listen [::]:80;
    server_name <span class="highlight">example.com</span> www.<span class="highlight">example.com</span><span class="token punctuation">;</span>

    location ~ /.well-known/acme-challenge <span class="token punctuation">{</span>
            allow all<span class="token punctuation">;</span>
            root /var/www/html<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location / <span class="token punctuation">{</span>
            rewrite ^ https://<span class="token variable">$host</span><span class="token variable">$request_uri</span>? permanent<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;

    index index.php index.html index.htm<span class="token punctuation">;</span>

    root /var/www/html<span class="token punctuation">;</span>

    server_tokens off<span class="token punctuation">;</span>

    ssl_certificate /etc/letsencrypt/live/<span class="highlight">example.com</span>/fullchain.pem<span class="token punctuation">;</span>
    ssl_certificate_key /etc/letsencrypt/live/<span class="highlight">example.com</span>/privkey.pem<span class="token punctuation">;</span>

    include /etc/nginx/conf.d/options-ssl-nginx.conf<span class="token punctuation">;</span>

    add_header X-Frame-Options <span class="token string">"SAMEORIGIN"</span> always<span class="token punctuation">;</span>
    add_header X-XSS-Protection <span class="token string">"1; mode=block"</span> always<span class="token punctuation">;</span>
    add_header X-Content-Type-Options <span class="token string">"nosniff"</span> always<span class="token punctuation">;</span>
    add_header Referrer-Policy <span class="token string">"no-referrer-when-downgrade"</span> always<span class="token punctuation">;</span>
    add_header Content-Security-Policy <span class="token string">"default-src * data: 'unsafe-eval' 'unsafe-inline'"</span> always<span class="token punctuation">;</span>
    <span class="token comment"># add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;</span>
    <span class="token comment"># enable strict transport security only if you understand the implications</span>

    location / <span class="token punctuation">{</span>
            try_files <span class="token variable">$uri</span> <span class="token variable">$uri</span>/ /index.php<span class="token variable">$is_args</span><span class="token variable">$args</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location ~ <span class="token punctuation">\</span>.php$ <span class="token punctuation">{</span>
            try_files <span class="token variable">$uri</span> <span class="token operator">=</span><span class="token number">404</span><span class="token punctuation">;</span>
            fastcgi_split_path_info ^<span class="token punctuation">(</span>.+<span class="token punctuation">\</span>.php<span class="token punctuation">)</span><span class="token punctuation">(</span>/.+<span class="token punctuation">)</span>$<span class="token punctuation">;</span>
            fastcgi_pass <span class="highlight">wordpress</span>:9000<span class="token punctuation">;</span>
            fastcgi_index index.php<span class="token punctuation">;</span>
            include fastcgi_params<span class="token punctuation">;</span>
            fastcgi_param SCRIPT_FILENAME <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span><span class="token punctuation">;</span>
            fastcgi_param PATH_INFO <span class="token variable">$fastcgi_path_info</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location ~ /<span class="token punctuation">\</span>.ht <span class="token punctuation">{</span>
            deny all<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    location <span class="token operator">=</span> /favicon.ico <span class="token punctuation">{</span>
            log_not_found off<span class="token punctuation">;</span> access_log off<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    location <span class="token operator">=</span> /robots.txt <span class="token punctuation">{</span>
            log_not_found off<span class="token punctuation">;</span> access_log off<span class="token punctuation">;</span> allow all<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    location ~* <span class="token punctuation">\</span>.<span class="token punctuation">(</span>css<span class="token operator">|</span>gif<span class="token operator">|</span>ico<span class="token operator">|</span>jpeg<span class="token operator">|</span>jpg<span class="token operator">|</span>js<span class="token operator">|</span>png<span class="token punctuation">)</span>$ <span class="token punctuation">{</span>
            expires max<span class="token punctuation">;</span>
            log_not_found off<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

Copy

The HTTP server block specifies the webroot for Certbot renewal requests to the .well-known/acme-challenge directory. It also includes a rewrite directive that directs HTTP requests to the root directory to HTTPS.

The HTTPS server block enables ssl and http2. To read more about how HTTP/2 iterates on HTTP protocols and the benefits it can have for website performance, please see the introduction to How To Set Up Nginx with HTTP/2 Support on Ubuntu 18.04.

This block also includes our SSL certificate and key locations, along with the recommended Certbot security parameters that we saved to nginx-conf/options-ssl-nginx.conf.

Additionally, we’ve included some security headers that will enable us to get A ratings on things like the SSL Labs and Security Headers server test sites. These headers include X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy, and X-XSS-Protection. The HTTP Strict Transport Security (HSTS) header is commented out — enable this only if you understand the implications and have assessed its “preload” functionality.

Our root and index directives are also located in this block, as are the rest of the WordPress-specific location blocks discussed in Step 1.

Once you have finished editing, save and close the file.

Before recreating the webserver service, you will need to add a 443 port mapping to your webserver service definition.

Open your docker-compose.yml file:


   
  • nano docker-compose.yml
  Copy

In the webserver service definition, add the following port mapping:

~/wordpress/docker-compose.yml
...
  webserver:
    depends_on:
      - wordpress
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network
  Copy

The docker-compose.yml file will look like this when finished:

~/wordpress/docker-compose.yml
version: '3'

services:
db:
image: mysql:8.0
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: ‘–default-authentication-plugin=mysql_native_password’
networks:
- app-network

wordpress:
depends_on:
- db
image: wordpress:5.1.1-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER= M Y S Q L U S E R < / s p a n > − < s p a n c l a s s = " t o k e n a s s i g n − l e f t v a r i a b l e " > W O R D P R E S S D B P A S S W O R D < / s p a n > < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n v a r i a b l e " > MYSQL_USER</span> - <span class="token assign-left variable">WORDPRESS_DB_PASSWORD</span><span class="token operator">=</span><span class="token variable"> MYSQLU​SER</span>−<spanclass="tokenassign−leftvariable">WORDPRESSD​BP​ASSWORD</span><spanclass="tokenoperator">=</span><spanclass="tokenvariable">MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network

webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- “80:80”
- “443:443”
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network

certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com

volumes:
certbot-etc:
wordpress:
dbdata:

networks:
app-network:
driver: bridge 

Copy

Save and close the file when you are finished editing.

Recreate the webserver service:


   
  • docker-compose up -d --force-recreate --no-deps webserver
  Copy

Check your services with docker-compose ps:


   
  • docker-compose ps
  Copy

You should see output indicating that your db, wordpress, and webserver services are running:


 
  Output
   Name                 Command               State                     Ports                  
----------------------------------------------------------------------------------------------
certbot     certbot certonly --webroot ...   Exit 0                                           
db          docker-entrypoint.sh --def ...   Up       3306/tcp, 33060/tcp                     
webserver   nginx -g daemon off;             Up       0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp    

With your containers running, you can now complete your WordPress installation through the web interface.

Step 6 — Completing the Installation Through the Web Interface

With our containers running, we can finish the installation through the WordPress web interface.

In your web browser, navigate to your server’s domain. Remember to substitute example.com here with your own domain name:

https://example.com

Select the language you would like to use:

WordPress Language Selector

After clicking Continue, you will land on the main setup page, where you will need to pick a name for your site and a username. It’s a good idea to choose a memorable username here (rather than “admin”) and a strong password. You can use the password that WordPress generates automatically or create your own.

Finally, you will need to enter your email address and decide whether or not you want to discourage search engines from indexing your site:

WordPress Main Setup Page

Clicking on Install WordPress at the bottom of the page will take you to a login prompt:

WordPress Login Screen

Once logged in, you will have access to the WordPress administration dashboard:

WordPress Main Admin Dashboard

With your WordPress installation complete, you can now take steps to ensure that your SSL certificates will renew automatically.

Step 7 — Renewing Certificates

Let’s Encrypt certificates are valid for 90 days, so you will want to set up an automated renewal process to ensure that they do not lapse. One way to do this is to create a job with the cron scheduling utility. In this case, we will create a cron job to periodically run a script that will renew our certificates and reload our Nginx configuration.

First, open a script called ssl_renew.sh:


   
  • nano ssl_renew.sh
  Copy

Add the following code to the script to renew your certificates and reload your web server configuration. Remember to replace the example username here with your own non-root username:

~/wordpress/ssl_renew.sh
#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
KaTeX parse error: Expected 'EOF', got '&' at position 73: …oken operator">&̲amp;&amp;</span…COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af 

Copy

This script first assigns the docker-compose binary to a variable called COMPOSE, and specifies the --no-ansi option, which will run docker-compose commands without ANSI control characters. It then does the same with the docker binary. Finally, it changes to the ~/wordpress project directory and runs the following docker-compose commands:

It then runs docker system prune to remove all unused containers and images.

Close the file when you are finished editing. Make it executable:


   
  • chmod +x ssl_renew.sh
  Copy

Next, open your root crontab file to run the renewal script at a specified interval:


   
  • sudo crontab -e
  Copy

If this is your first time editing this file, you will be asked to choose an editor:


 
  Output
 no crontab for root - using an empty one

Select an editor. To change later, run ‘select-editor’.

  1. /bin/nano <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]:

At the bottom of the file, add the following line:

crontab
...
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
  Copy

This will set the job interval to every five minutes, so you can test whether or not your renewal request has worked as intended. We have also created a log file, cron.log, to record relevant output from the job.

After five minutes, check cron.log to see whether or not the renewal request has succeeded:


   
  • tail -f /var/log/cron.log
  Copy

You should see output confirming a successful renewal:


 
  Output
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating ‘certbot renew’ close to cert expiry
** (The test certificates above have not been saved.)


You can now modify the crontab file to set a daily interval. To run the script every day at noon, for example, you would modify the last line of the file to look like this:

crontab
...
0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
  Copy

You will also want to remove the --dry-run option from your ssl_renew.sh script:

~/wordpress/ssl_renew.sh
#!/bin/bash

COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"

cd /home/sammy/wordpress/
KaTeX parse error: Expected 'EOF', got '&' at position 63: …oken operator">&̲amp;&amp;</span…COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af 

Copy

Your cron job will ensure that your Let’s Encrypt certificates don’t lapse by renewing them when they are eligible. You can also set up log rotation with the Logrotate utility to rotate and compress your log files.

Conclusion

In this tutorial, you used Docker Compose to create a WordPress installation with an Nginx web server. As part of this workflow, you obtained TLS/SSL certificates for the domain you want associated with your WordPress site. Additionally, you created a cron job to renew these certificates when necessary.

As additional steps to improve site performance and redundancy, you can consult the following articles on delivering and backing up WordPress assets:

If you are interested in exploring a containerized workflow with Kubernetes, you can also check out:

标签:06,17,will,wordpress,2021,file,our,your,certbot
来源: https://blog.csdn.net/wosiy/article/details/117984015