banner
子文

子文

世界,你好鸭~
x
github

Build a personal blog in 30 minutes

WordPress is a well-known content management system, while Docker can package applications and their dependencies into a lightweight, portable container, which can then be deployed on any popular Linux machine. The combination of the two allows for website creation with just a few simple configuration steps.

Purchase Instances (Servers)#

Cloud servers can be purchased from places like Alibaba Cloud, Tencent Cloud, Huawei Cloud, Amazon Cloud, Google Cloud, etc. Among them, Google and Amazon offer one-year trial packages, while new users and campus users of Alibaba, Tencent, and Huawei also have many discounts. Friends can choose suitable packages to purchase.

Install Docker and Docker Compose#

You can directly choose an image with Docker when purchasing the server. If not, you can find the option to change the operating system (or change the image) in the console to switch to an image that includes Docker. If it’s still not available, you can install it using the following method:

# Install Docker
sudo curl -sSL https://get.daocloud.io/docker | sh

# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Create Persistent Directories#

Once a Docker container is destroyed, the data inside the container will be lost. To avoid this, we generally persist this data by mounting volumes:

# Switch to the installation directory
cd ~

# Create the necessary directories for mounting
## Create MySQL configuration directory
mkdir db
## Create MySQL data directory
mkdir db_data
## Create WordPress file directory
mkdir wordpress_data
## Create Nginx file directory
mkdir nginx

# Create essential configuration files
## Create MySQL configuration file
cat > ./db/mysql.cnf << EOF
[mysqld]
explicit_defaults_for_timestamp=true
wait_timeout=86400
interactive_timeout=7200
EOF
## Create Nginx configuration file

### First, start an Nginx image
sudo docker run -it -d --name nginx nginx:latest
### Copy the /etc/nginx directory from the container to local
sudo docker cp nginx:/etc/nginx ./nginx/conf
### Copy the /usr/share/nginx/html directory from the container to local
sudo docker cp nginx:/usr/share/nginx/html ./nginx/html
### Create Nginx log directory
mkdir ./nginx/log
### After copying files, remove the Nginx image
sudo docker stop nginx
sudo docker rm nginx

Configure docker-compose.yml#

vi docker-compose.yml

The file content is as follows:

version: '3'
services:
  nginx:
    image: nginx:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf:/etc/nginx:ro
      - ./nginx/html:/usr/share/nginx/html:rw
      - ./nginx/log:/var/log/nginx:rw
      - ./nginx/ssl:/etc/ssl:ro

  wpdatabase:
    image: mysql:latest
    volumes:
      - ./db_data:/var/lib/mysql
      - ./db/mysql.cnf:/etc/my.cnf
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root # Database administrator password, recommended to change to a strong password
      MYSQL_DATABASE: wordpress # WordPress database
      MYSQL_USER: wordpress # WordPress user
      MYSQL_PASSWORD: wordpress # Password for the WordPress user, recommended to change to a strong password

  wordpress:
    depends_on:
      - wpdatabase
    image: wordpress:latest
    volumes:
      - ./wordpress_data:/var/www/html
    restart: always
    environment:
      WORDPRESS_DB_HOST: wpdatabase:3306
      WORDPRESS_DB_USER: wordpress # MySQL user configured above
      WORDPRESS_DB_PASSWORD: wordpress # Password for the MySQL user configured above

Start the Container#

sudo docker-compose up -d

Modify Nginx Configuration File#

After the above configuration, we can see that the container has started by using sudo docker ps, but Nginx is not configured properly for proxying, so we cannot directly access the WordPress page yet. We just need to create a configuration file:

# Create Nginx configuration file
vi ./nginx/conf/conf.d/wordpress.conf

Press the i key to enter edit mode, change the following content, and paste it:

server {
  listen 80;
  server_name x.x.x.x; # Change this to your host IP

  location / {
    proxy_pass http://wordpress;
    proxy_redirect off;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    # Forward host information
    proxy_set_header Host $host;
  }
}

Press : then type wq! to save the file.

Restart Nginx Container and Access the Website#

sudo docker-compose restart nginx

At this point, you can directly access the server IP address to visit WordPress. If an error occurs, you can use tail -f ./nginx/log/error.log to check the error log.

Advanced Configuration#

One-stop Website Building Service#

The above method can only deploy a WordPress application simply on the server. Others can access your page using the public IP, but this is not compliant and not secure. A complete website building process also includes domain registration, website filing, public security filing, DNS resolution, SSL certificate issuance, etc. All of these steps can be obtained as a one-stop service from cloud service providers. Domain registration is paid, while other steps have free options. It should be noted that website filing requires about 20 days for approval.

SSL Certificate Configuration#

After obtaining a free SSL certificate from the cloud service provider, upload it to the server and copy the .crt and .key files to the ./nginx/conf directory, and generate Mozilla's pem file:

# Copy SSL certificate files
cp /path/to/xxx.crt ./nginx/conf
cp /path/to/xxx.key ./nginx/conf

# Generate Mozilla's pem file
curl https://ssl-config.mozilla.org/ffdhe2048.txt > ./nginx/conf/dhparam.pem

Modify the ./nginx/conf/conf.d/wordpress.conf file according to the marked comments:

# generated 2022-03-24, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6

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

    server_name _;
    server_name yangziwen.cn www.yangziwen.cn; # Change this to your own domain

    location / {
        return 301 https://yangziwen.cn$request_uri; # Change this to your own domain
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yangziwen.cn www.yangziwen.cn; # Change this to your own domain

    location / {
      proxy_pass http://wordpress;

          proxy_http_version    1.1;
          proxy_cache_bypass    $http_upgrade;

          proxy_set_header Upgrade            $http_upgrade;
          proxy_set_header Connection         "upgrade";
          proxy_set_header Host                $host;
          proxy_set_header X-Real-IP            $remote_addr;
          proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto    $scheme;
          proxy_set_header X-Forwarded-Host    $host;
          proxy_set_header X-Forwarded-Port    $server_port;
    }

    ssl_certificate xxx.crt; # Change this to your own SSL certificate
    ssl_certificate_key xxx.key; # Change this to your own SSL certificate key
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;
    
    # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
    ssl_dhparam dhparam.pem;

    # intermediate configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate xxx.crt; # Change this to your own SSL certificate

    # replace with the IP address of your resolver
    resolver 8.8.8.8;
    
    location ~* /xmlrpc.php {
        deny all;
    }

    if ( $fastcgi_script_name ~ \..*\/.*php ) {
        return 403;
    }

    if ($request_method !~ ^(GET|PUT|HEAD|POST|OPTIONS)$ ) {
        return 444;
    }

}

The above configuration template is generated by https://ssl-config.mozilla.org/ and has undergone some simple security hardening. Next, restart Nginx to directly access your site via HTTPS.

sudo docker-compose restart nginx

At this point, you can check your site's HTTPS rating at https://myssl.com/. The score for the above configuration is A+. If it is not, it may be because images or other resources were referenced via HTTP on the homepage; change them to HTTPS references.

Nginx Security Hardening#

In the SSL configuration, we have already made some hardening to Nginx. There are still some configurations that need to be made in ./nginx/conf/nginx.conf. Modify the file as follows, mainly to prohibit HTTP and direct IP access.


user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    # Hide Nginx version number to improve security.
    server_tokens off;
    # Hide PHP version
    fastcgi_hide_header X-Powered-By;
    proxy_hide_header X-Powered-By;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
    server {
        listen 80 default;
        server_name _;
        return 444; # Prevent access to the website via IP
        location ~* \.(rar|zip|gz|tar|tgz|tar.gz|7z|z|bz2|tar.bz2|sql|log|rar|ini|bak|conf|DS_Store|idea|swp|svn|entries|git|config)$ {
            deny all;
        }
        autoindex off;
        include vhost/*.conf;
    }
}                                                   

Restart Nginx:

sudo docker-compose restart nginx

WordPress Security Hardening#

It is strongly recommended to install the Wordfence plugin immediately after setting up the site and enable Two-Factor Authentication. During the period of setting up the site and filing, I have already intercepted many attempts to log in to the admin account and access sensitive interfaces through the Wordfence plugin.

Server Security Hardening#

Generally, after purchasing a cloud server, the provider will offer basic security scanning. Newly created instances need to be updated promptly according to the scanning results to ensure that some sensitive software (like OpenSSH) is up to date to avoid vulnerabilities.

SSH is the most commonly used way to log into servers and is also one of the favorite entry points for hackers. After creating a new instance, we should quickly configure the following two points:

  1. Create a new key and associate the server instance with the key. The specific method can refer to the cloud service provider's instructions. After creating a new key, we no longer need to enter a password to log into the instance; we just need to configure our private key in the SSH client to connect to the instance. The only thing to note is to avoid the leakage of the private key. If the private key is leaked or lost, you need to promptly delete the original key in the cloud service's user management center and create a new key.
  2. Modify the server firewall. Enter the management page of the cloud server and modify the firewall to only allow access to ports 80, 443, and ICMP. For port 22, if it’s not too much trouble, it’s best to only leave the source IP address that needs SSH login. However, for users using China Telecom or China Mobile broadband, the IP may change after a period or after restarting the router. If SSH cannot connect, it is likely due to the IP address update. For users with a fixed IP range, you can define the IP range using a subnet mask, which is the /24, /16, /8 that follows the IP.

SEO Configuration#

After building our beloved website, we certainly hope to be seen by like-minded friends as soon as possible. At this time, SEO (Search Engine Optimization) plays a significant role. In WordPress, we can easily configure SEO through some plugins. I use the Yoast SEO plugin, and after installing it, you can follow the plugin's prompts to make some simple configurations.

Sitemap is a very important part of SEO. The sitemap feature of Yoast is a paid function, but we can install the WP Sitemap Page plugin to generate a simple sitemap, which can be accessed via domain/sitemap_index.xml. This is an index file, and when opened, it will have various types of indexes, each containing corresponding URL links, covering basically all the content displayed externally on our website. By submitting these XML indexes to the webmaster tools of Baidu, Google, and Bing, we can allow search engines to quickly index our site. Here are the addresses for these webmaster tools:

The configuration method is also very simple. First is site association, with various association methods; just choose one according to the instructions. Secondly, each webmaster tool has a sitemap upload feature. Google and Bing can be seen in the menu bar, while Baidu has a sitemap upload option under ordinary indexing. Just submit all the XML links in sitemap_index.xml.

After submitting the sitemap, just wait for the major search engines to crawl the URLs in the sitemap. I must praise Google's speed; the next day, I could find my website's content on the PC side, while Baidu took a bit longer.

robots.txt is a crawling protocol that tells search engine crawlers which pages can be crawled and which cannot. A good robots.txt can help crawlers quickly discover the pages you want to display. WordPress has a default robots.txt that includes a simple strategy to block wp-admin. We can add the sitemap address to help crawlers discover the sitemap faster. First, enter ./wordpress_data to create a robots.txt file, adding Sitemap: https://domain/sitemap_name.xml, then access https://domain/robots.txt to make it effective.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.