# 30分钟建成一个博客

By [子文](https://paragraph.com/@0x72548c18717a3cd17ff7d31d32c21f40049e2aeb) · 2024-01-05

---

> wordpress是广为人知的内容管理系统，而docker可以打包应用以及依赖包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，两者的结合让建站只需要简单的几步配置。

购买实例（服务器）
---------

阿里云、腾讯云、华为云、亚马逊云、谷歌云等等地方都可以购买云服务器，其中谷歌和亚马逊都有试用一年的套餐，而阿里、腾讯、华为的新用户和校园用户也有许多折扣，小伙伴们可以自行挑选合适的套餐购买。

安装docker和docker-compose
-----------------------

这里可以直接在购买服务器的时候选择含有docker的镜像，如果没有也可以在控制台中找到更换操作系统（或更换镜像）来换一个带有docker的镜像，如果还是没有可以通过以下方法安装：

    # 安装docker
    sudo curl -sSL https://get.daocloud.io/docker | sh
    
    # 安装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
    

创建持久化目录
-------

docker容器一旦销毁后，容器内的数据就会丢失，为了避免这种事情的发生，我们一般会通过挂载卷的方式来持久化这些数据：

    # 切换到安装目录
    cd ~
    
    # 创建挂载所需的目录
    ## 创建mysql配置目录
    mkdir db
    ## 创建mysql数据目录
    mkdir db_data
    ## 创建wordpress文件目录
    mkdir wordpress_data
    ## 创建nginx文件目录
    mkdir nginx
    
    # 创建必备配置文件
    ## 创建mysql配置文件
    cat > ./db/mysql.cnf << EOF
    [mysqld]
    explicit_defaults_for_timestamp=true
    wait_timeout=86400
    interactive_timeout=7200
    EOF
    ## 创建nginx配置文件
    
    ### 先启动一个ngninx的镜像
    sudo docker run -it -d --name nginx nginx:latest
    ### 将容器内的/etc/nginx目录拷贝到本地
    sudo docker cp nginx:/etc/nginx ./nginx/conf
    ### 将容器内的/usr/share/nginx/html目录拷贝到本地
    sudo docker cp nginx:/usr/share/nginx/html ./nginx/html
    ### 创建ngnix的日志目录
    mkdir ./nginx/log
    ### 文件拷贝完毕移除ngnix镜像
    sudo docker stop nginx
    sudo docker rm nginx
    

配置docker-compose.yml
--------------------

    vi docker-compose.yml
    

文件内容如下

    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 # 数据库管理员密码，推荐改为强密码
          MYSQL_DATABASE: wordpress # wordpress数据库
          MYSQL_USER: wordpress # wordpress用户
          MYSQL_PASSWORD: wordpress # wordpress用户的密码，推荐改为强密码
    
      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用户
          WORDPRESS_DB_PASSWORD: wordpress # 上面配置的mysql用户的密码
    

启动容器
----

    sudo docker-compose up -d
    

修改ngnix配置文件
-----------

经过上面的配置，我们可以通过`sudo docker ps`看到容器已经启动了，但是nginx还没配置好代理，所以还无法直接访问到wordpress的页面，我们只需要创建一个配置文件即可：

    # 创建nginx配置文件
    vi ./nginx/conf/conf.d/wordpress.conf
    

按`i`键进入编辑模式，将以下内容更改后粘贴：

    server {
      listen 80;
      server_name x.x.x.x; # 此处修改为你的主机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;
        # 转发host信息
        proxy_set_header Host $host;
      }
    }
    

按`:`后输入`wq!`保存文件即可

重启nginx容器并访问网站
--------------

    sudo docker-compose restart nginx
    

此时直接访问服务器IP地址即可访问worepress，如果出现了错误，可以使用`tail -f ./nginx/log/error.log`查看错误日志

进阶配置
----

### 建站一条龙服务

上述的方法只能在服务器上简单部署一个wordpress应用，别人可以用公网IP去访问你的页面，但这不合规也不安全，一个完整的建站流程还包括域名注册、网站备案、公安备案、DNS解析、SSL证书签发等等，以上步骤都可以在云服务厂商获取一条龙服务，其中域名注册是收费的，其他环节都有免费方案，需要注意的是网站备案需要近20天左右的审批时间。

### SSL证书配置

在云服务厂商那获取免费的ssl证书后上传到服务器，并将.crt和.key文件拷贝到./nginx/conf目录中，并生成将mozilla的pem文件：

    # 拷贝ssl证书文件
    cp /path/to/xxx.crt ./nginx/conf
    cp /path/to/xxx.key ./nginx/conf
    
    # 生成mozilla的pem文件
    curl https://ssl-config.mozilla.org/ffdhe2048.txt > ./nginx/conf/dhparam.pem
    

按标记的注释对./nginx/conf/conf.d/wrodpress.conf进行文件修改：

    # 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; # 这里改为自己的域名
    
        location / {
            return 301 https://yangziwen.cn$request_uri; # 这里改为自己的域名
        }
    }
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name yangziwen.cn www.yangziwen.cn; # 这里改为自己的域名
    
        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; # 这里改为自己的ssl证书
        ssl_certificate_key xxx.key; # 这里改为自己的ssl证书密钥
        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; # 这里改为自己的ssl证书
    
        # 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;
        }
    
    }
    

以上的配置模板是由[https://ssl-config.mozilla.org/](https://ssl-config.mozilla.org/)生成的，并进行了一些简单的安全加固，接下来重启ngnix即可直接通过https访问自己的站点了

    sudo docker-compose restart nginx
    

此时可以在[https://myssl.com/](https://myssl.com/)中对自己的站点进行HTTPS评级，以上配置的分数为A+，如果不是可能是因为之前主页上通过http引用了图片等资源，改为https引用即可

### nginx安全加固

在ssl配置中我们已经对nginx做了部分加固，还有一些配置需要在./nginx/conf/nginx.conf中进行配置，将文件进行如下修改，主要是禁止了http和直接使用ip访问

    
    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;
        #隐藏 Nginx 的版本号，提高安全性。
        server_tokens off;
        #隐藏 PHP 版本
        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; #防止通过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;
        }
    }                                                   
    

重启nginx：

    sudo docker-compose restart nginx
    

### wordpress安全加固

强烈建议站点建好后立马安装Wordfence插件，并开启双因子鉴权（Two-Factor Authentication），我在建好站等备案期间已经通过Wordfence插件拦截了许多尝试登录admin账号和访问敏感接口的行为

### 服务器安全加固

一般购买云服务器后厂商会赠送最基本的安全扫描，新建的实例需要及时按照扫描结果将一些敏感软件（如openssh）更新到最新版本，以免存在漏洞

ssh是我们登录服务器最常用的方式，也是黑客最爱的入口之一，新建实例后我们应该尽快进行以下两点配置：

1.  新建密钥，并将服务器实例与密钥关联，具体方式可以参考云服务厂商的说明。新建密钥后我们登录实例就不需要再输密码了，只要在ssh客户端配置好自己的私钥即可连接实例，唯一需要注意的是要避免私钥的泄露，私钥一旦泄露或丢失需要及时到云服务的用户管理中心去删除原始密钥并创建新的密钥
    
2.  修改服务器防火墙。进入云服务器的管理页面，修改防火墙，只要保留80，443，ICMP端口的访问即可，对于22端口如果不嫌麻烦的最好只留需要ssh登录的源端ip地址即可，不过像使用电信，移动宽带的用户，ip在一段时间或者重启路由器后会变，此时如果ssh连接不上大概率是ip地址更新导致的。对于ip在一个固定网段的用户，可以通过子网掩码来划定ip范围，就是ip后面的/24，/16，/8这些
    

### SEO配置

我们搭建好自己心爱的网站后，肯定希望尽快被志同道合的基友看到，这时SEO（搜索引擎优化）就起到了很大的帮助。在wordpress中我们可以通过一些插件即可方便地配置SEO，我用的是Yoast SEO这款插件，安装好后可以根据插件提示做一些简单配置。

sitemap（站点地图）是SEO相当重要的一部分，Yoast的站点地图是收费功能，我们可以安装WP Sitemap Page插件来生成一个简单的站点地图，通过`域名/sitemap_index.xml`即可访问，这是一个索引文件，点开后会有各种类型的索引，每个索引里面具有对应的url链接，这些链接基本涵盖了我们网站所有对外显示的内容。通过将这些xml索引推给百度、谷歌、必应的站长工具，就可以让搜索引擎快速收录我们的站点，以下是这些站长工具的地址

*   谷歌：[https://www.google.com/intl/zh-CN/webmasters/](https://www.google.com/intl/zh-CN/webmasters/)
    
*   百度：[https://ziyuan.baidu.com/site/index](https://ziyuan.baidu.com/site/index)
    
*   必应：[https://www.bing.com/webmasters/about?setlang=zh-cn](https://www.bing.com/webmasters/about?setlang=zh-cn)
    

配置方法也很简单，首先是站点关联，有各种关联方式，按照说明选一个配置就行。其次每个站长工具中都有站点地图的上传，谷歌和必应在菜单栏中就能看到，百度的在普通收录里面有个sitemap上传，只要将sitemap\_index.xml中所有xml的链接提交即可。

提交完站点地图之后，只要等各大搜索引擎去爬取站点地图中的url即可，这里不得不夸赞一下谷歌的速度，录完第二天就能在pc端搜到自己网站的内容了，而百度，着实让人有点着急。 robots.txt是一种爬虫协议，他们告诉搜索引擎的爬虫哪些能爬哪些不能爬，一份良好的robots.txt能够让爬虫快速发现你想要展示的页面，wordpress默认有一个robots.txt配置了简单的屏蔽wp-admin的策略，我们可以为其加上sitemap的地址，让爬虫更快地发现sitemap。首先进入`./wordpress_data`创建`robots.txt`文件，添加`Sitemap: https://域名/站点地图名.xml`,然后访问`https://域名/robots.txt`生效即可。

参考链接
----

*   [https://www.cnblogs.com/data-magnifier/p/15362218.html](https://www.cnblogs.com/data-magnifier/p/15362218.html)
    
*   [https://www.cnblogs.com/data-magnifier/p/15362218.html](https://www.cnblogs.com/data-magnifier/p/15362218.html)
    
*   [https://www.zengxi.net/2020/11/nginx\_security/](https://www.zengxi.net/2020/11/nginx_security/)
    
*   [https://chegva.com/3953.html](https://chegva.com/3953.html)
    
*   [https://www.wpdaxue.com/nginx-rules-to-enhance-wordpress-security.html](https://www.wpdaxue.com/nginx-rules-to-enhance-wordpress-security.html)

---

*Originally published on [子文](https://paragraph.com/@0x72548c18717a3cd17ff7d31d32c21f40049e2aeb/30)*
