概要
本文講述了從一台空白入門級VPS完成Wordpress安裝與優化的過程,在一篇文章中包含了通常要在別的地方看數十篇文章的內容。為了提高文章的熵值,文中略去了一些簡單的一看界面就知道怎麼去做的操作過程。在精力允許的情況下,本文可能長期更新。本人水平有限,文中一些東西不是特別嚴謹,也可能會有一些錯誤的地方,若各位發現有不對的地方歡迎指教。
另外這裡所說的入門級VPS是指單核處理器1G內存這樣的VPS。
本站使用了WordPress的子域名多站功能,主站yyr.im是博客,子站k.yyr.im是個人知識庫。
基礎架構
這裡採用Debian+Openresty+PHP+MariaDB
Debian
曾在Debian與CentOS之間猶豫過,兩者都以穩定保守著稱,CentOS有大廠依托對硬件的兼容性更好,相對Debian來說更保守些,在性能與節約資源上略遜於Debian。但想著網站是搭建在VPS上的,CentOS對硬件的兼容性在虛擬機上沒有優勢,所以選擇了Debian。
Nginx
準備
一台運行Debian的VPS並將需要的域名綁定到這個VPS上。
搭建基本的Wordpress
安裝MariaDB及Wordpress所必要的php擴展
1 2 |
sudo apt update && sudo apt upgrade sudo apt install nginx mariadb-server php-fpm php-mysql php-curl php-xml php-gd php-mbstring php-zip php-imagick php-bcmath |
使用mysql_secure_installation
命令為MariaDB進行安全設置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
sudo mysql_secure_installation NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MariaDB to secure it, we'll need the current password for the root user. If you've just installed MariaDB, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): <- 輸入當前root密碼,初次運行直接按回車 OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] y <- 是否設置root密碼,按回車進行root密碼設置 New password: <- 輸入root密碼 Re-enter new password: <- 再次輸入root密碼 Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] <- 是否刪除匿名用戶,按按回車刪除 ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] n <- 是否禁止root遠程登錄,按回車禁止 ... skipping. By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y <- 是否刪除test數據庫,按回車刪除 - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y <- 是否重新加載權限表,按回車重新加載 ... Success! Cleaning up... All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB! |
安裝Nginx
準備編譯環境
1 2 3 4 5 6 7 8 |
#进入超级用户 sudo su #安装git apt install git #安装编译工具 apt install build-essential #安装依赖,libjemalloc-dev 用於多處理器優化,根據主機情況安裝 apt install libpcre3-dev zlib1g-dev libssl-dev uuid-dev libjemalloc-dev |
編譯安裝Nginx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#進入源碼目錄 cd #下載brotli源碼 git clone https://github.com/google/ngx_brotli.git #更新brotli cd ngx_brotli git submodule update --init --recursive cd .. #下載ngx_pagespeed源碼 #參考 https://www.modpagespeed.com/doc/build_ngx_pagespeed_from_source #設置版本變量,在這裡檢查最新版本號 https://www.modpagespeed.com/doc/release_notes NPS_VERSION=1.13.35.2-stable #設置操作系統數位 SYSBIT=X64 #下載 wget https://github.com/apache/incubator-pagespeed-ngx/archive/v${NPS_VERSION}.zip #解壓 unzip v${NPS_VERSION}.zip nps_dir=$(find . -name "*pagespeed-ngx-${NPS_VERSION}" -type d) cd "$nps_dir" NPS_RELEASE_NUMBER=${NPS_VERSION/beta/} NPS_RELEASE_NUMBER=${NPS_VERSION/stable/} psol_url=https://dl.google.com/dl/page-speed/psol/${NPS_RELEASE_NUMBER}-${SYSBIT}.tar.gz [ -e scripts/format_binary_url.sh ] && psol_url=$(scripts/format_binary_url.sh PSOL_BINARY_URL) wget ${psol_url} tar -xzvf $(basename ${psol_url}) # extracts to psol/ cd .. #下載OpenResty源碼 #設置OpenResty版本變量,在這裡檢查最新版本號 https://openresty.org/cn/download.html ORT_VERSION=1.15.8.1 下载Openresty wget https://openresty.org/download/openresty-${ORT_VERSION}.tar.gz 解压 tar -xzvf openresty-${ORT_VERSION}.tar.gz cd openresty-${ORT_VERSION}/ #配置編譯選項 ./configure \ --add-module=/usr/src/$nps_dir ${PS_NGX_EXTRA_FLAGS} \ --add-module=/usr/src/ngx_brotli \ --with-http_v2_module \ --with-http_ssl_module \ --with-http_gzip_static_module \ --with-ld-opt='-ljemalloc' #jemalloc用於多處理器內存分配優化優化,根據情況配置 #編譯並安裝 make && make install |
設置開機自動啟動Nginx
參考https://www.nginx.com/resources/wiki/start/topics/examples/systemd/
創建文件/lib/systemd/system/nginx.service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target |
避免Failed to parse PID from file /run/nginx.pid: Invalid argument
參考:https://www.v2ex.com/t/300986
1 2 |
mkdir -p /etc/systemd/system/nginx.service.d printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" >/etc/systemd/system/nginx.service.d/override.conf |
設置開機自動啟動Openresty
1 2 3 |
systemctl enable nginx.service #立即启动OpenResty systemctl start nginx.service |
配置基本網頁服務器
創建站點目錄
我的網站文件放在/var/www/yyr.im/
中的,網站根目錄設置在/var/www/yyr.im/public/wordpress
中,先使用下面命令創建目錄
1 |
sudo mkdir -p /var/www/yyr.im/public/ |
使用Nginx Config生成基本網站配置文件
OpenResty是基於Nginx的,配置文件也與Nginx兼容,所以可用Nginx Config,前面的鏈接點開就是我生成的配置文件,這樣生成的配置文件並不到把所有需求兼顧到位,還需要根據自身情況做進一步改動。我們先把生成的文件放置到自己的主機上對應的文件夾中,然後建立/usr/local/openresty/nginx/conf/sites-enabled/yyr.im.conf
軟鏈接到/usr/local/openre sty/nginx/conf/sites-available/yyr.im.conf
以啟用站點。
1 |
ln -s /usr/local/openresty/nginx/conf/sites-available/yyr.im.conf /usr/local/openresty/nginx/conf/sites-enabled/yyr.im.conf |
為站點部署Let’s Encrypt通配符ECC/RSA雙證書
Let’s Encrypt是目前應用最廣泛的免費數字證書頒發機構,由英特網安全研究小組(ISRG)、電子前哨基金會、Mozilla基金會、Akamai以及思科提供支持,支持泛域名證書,證書有效期為90天,可以免費續期,配合第三方工具可以實現自動續期。
ECC是指橢圓曲線密碼學(Elliptic Curve Cryptography),ECC證書是指使用ECDSA(Elliptic Curve Digital Signature Algorithm 椭圆曲线数字签名算法)公鑰的證書;RSA證書是指使用RSA加密算法公鑰的證書。ECC證書比RSA證書安全效能更好,因此目前應優先使用ECC證書。RSA證書歷史悠久,兼容性好。
為了提高網站安全性如果只使用TLS 1.2及以上版本協議,那麼RSA證書只對 Chrome 49 / XP SP3有用,因為支持TLS 1.2的瀏覽器除了Chrome 49 / XP SP3外都支持ECC證書,如果你不打算支持Chrome 49 / XP SP3,可以不申请RSA證書。
申請證書
這裡使用的工具是acme.sh,最流行的certbot在申請ECC證書的時候只能填寫一個域名,通配符證書需要填寫兩個域名yyr.im
和*.yyr.im
,因为*.yyr.im
不包含yyr.im
,而acme.sh則支持在申請ECC證書時填寫多個域名。
首先安裝acme.sh
1 |
curl https://get.acme.sh | sh |
根據官方說明,安裝過程中進行了以下幾步
1. 把 acme.sh 安装到你的 home 目录下
2. 自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书.
申請證書需要驗證域名所有權,有http驗證(在網站根目錄建立指定名稱的文件夾),有DNS驗證。申請通配符證書必須使用DNS驗證域名所有權,DNS驗證是通過向域名的txt記錄添加Let’s Encrypt所返回的字符串,手動向域名DNS添加txt記錄的會無法做到對證書自動續期,因為Let’s Encrypt每次返回字符串都不一樣,因此需要用到DNS API,可以向域名自動添加txt記錄以自動驗證域名所有權,從而實現證書自動續期。
我的域名yyr.im是在name.com註冊的,根據官網的DNS API說明可以到 https://www.name.com/account/settings/api 申請API並取得API的令牌(token)。再通過下面兩條命令設置變量(將user
換成你在域名註冊商的用戶名,將token換成你剛剛獲取的API令牌)。
1 2 |
export Namecom_Username="user" export Namecom_Token="token" |
之後便可使用下面兩條命令分別申請ECC證書和RSA證書。
1 2 3 4 |
#申請ECC證書 acme.sh --issue --dns dns_namecom -d yyr.im -d *.yyr.im --keylength ec-384 --accountkeylength ec-384 --ocsp-must-staple #申請RSA證書 acme.sh --issue --dns dns_namecom -d yyr.im -d *.yyr.im --keylength 4096 --accountkeylength 4096 --ocsp-must-staple |
部署證書
為Nginx指定證書位置
已經申請好的證書會放在~/.acme.sh/
中,根據acme.sh官方這裡的證書僅供內部使用而且以後目錄結構可能會發生變化,不應讓Nginx/Apache直接使用這裡的證書。應該使用acme.sh --installcert
將證書複製到其他位置,這樣acme.sh會記住你複製證書的位置,下次續期證書時會自動更新這裡的文件。
為方便管理,我將證書放在/var/www/yyr.im/certificate/
,首先創建文件夾,並將該文件夾擁有者改為之前安裝acme.sh的用戶,以便acme.sh在複製證書和自動續期證書的時候不會遇到權限障礙。
1 2 3 4 |
#創建證書文件夾 sudo mkdir /var/www/yyr.im/certificate/ #更改文件夾所有者,user需改為你操作acme.sh的賬戶,否則部署和更新證書可能會出現權限問題 sudo chown user. /var/www/yyr.im/certificate/ |
然後編輯/usr/local/openresty/nginx/conf/sites-available/yyr.im.conf
將# SSL
下面的內容改為這樣
1 2 3 4 5 6 7 |
#SSL #ECC ssl_certificate /var/www/yyr.im/certificate/yyr.im_ecc_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_ecc.key; #RSA ssl_certificate /var/www/yyr.im/certificate/yyr.im_rsa_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_rsa.key; |
複製證書
使用acme.sh --installcert
命令分別將所申請的ECC證書和RSA證書複製到 /var/www/yyr.im/certificate/
中。
1 2 3 4 |
#ECC acme.sh --installcert -d yyr.im -d *.yyr.im --ecc --cert-file /var/www/yyr.im/certificate/yyr.im_ecc.cer --key-file /var/www/yyr.im/certificate/yyr.im_ecc.key --ca-file /var/www/yyr.im/certificate/yyr.im_ecc_ca.cer --fullchain-file /var/www/yyr.im/certificate/yyr.im_ecc_fullchain.cer --reloadcmd "sudo service openresty force-reload" #RSA acme.sh --installcert -d yyr.im -d *.yyr.im --cert-file /var/www/yyr.im/certificate/yyr.im_rsa.cer --key-file /var/www/yyr.im/certificate/yyr.im_rsa.key --ca-file /var/www/yyr.im/certificate/yyr.im_rsa_ca.cer --fullchain-file /var/www/yyr.im/certificate/yyr.im_rsa_fullchain.cer --reloadcmd "sudo service openresty force-reload" |
為Wordpress創建數據庫
1 2 3 4 5 6 7 8 9 10 |
#打開MariaDB sudo mariadb #創建名為wordpress的數據庫 CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; #為wordpress數據庫創建名為wordpress_user的數據庫用戶 GRANT ALL ON wordpress.* TO 'wordpress_user'@'localhost' IDENTIFIED BY 'password'; #刷新權限 FLUSH PRIVILEGES; #退出 exit |
下載安裝Wordpress
1 2 3 4 5 6 7 8 |
#進入網站目錄 cd /var/www/yyr.im/public/ #下載最新的wordpress sudo curl -LO https://wordpress.org/latest.tar.gz #解壓縮 sudo tar xzvf latest.tar.gz 刪除壓縮包 sudo rm lastest.tar.gz #變更wordpress文件夾所有者和用戶組為www-data以便Wordpress可以自行更新 sudo chown -R www-data:www-data /var/www/yyr.im/public/wordpress/ |
做完上述操作後從瀏覽器訪問你的域名,根據提示完成安裝。
啟用子域名多站支持
也就是在安裝一個Wordpress的前提下,使用子域名同時運行多個網站。此處參考https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/
OpenResty配置
首先打開網站配置文件/usr/local/openresty/nginx/conf/sites-available/yyr.im.conf
下面代碼中被標記出來的關鍵行是針對WordPress子域名多站的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#WP多站配置 map $http_host $blogid { default -999; } server { listen 443 ssl http2 fastopen=3 reuseport; listen [::]:443 ssl http2 fastopen=3 reuseport; server_name .yyr.im; set $base /var/www/yyr.im; root $base/public/wordpress; # SSL #ECC ssl_certificate /var/www/yyr.im/certificate/yyr.im_ecc_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_ecc.key; #ssl_trusted_certificate /var/www/yyr.im/certificate/yyr.im_ecc_ca.cer; #RSA ssl_certificate /var/www/yyr.im/certificate/yyr.im_rsa_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_rsa.key; #ssl_trusted_certificate /var/www/yyr.im/certificate/yyr.im_rsa_ca.cer; # security include nginxconfig.io/security.conf; # index index index.php; #Skip Cache include nginxconfig.io/skipcache.conf; #redis include nginxconfig.io/redis.conf; #fastcgi cache purge #include nginxconfig.io/purge.conf; location ~ [^/]\.php(/|$) { include nginxconfig.io/php_fastcgi.conf; #include nginxconfig.io/fastcgi_cache.conf; include nginxconfig.io/srcache.conf; } #僅開啟GET POST請求,避免其他請求被惡意利用 if ($request_method !~ ^(HEAD|GET|POST)$) { return 403; } #快速響應HEAD請求 if ($request_method ~ ^(HEAD)$ ) { return 200 "All OK"; } #WP多站配置 # wordpress固定链接设置 # This is cool because no php is touched for static content. # include the "?$args" part so non-default permalinks doesn't break when using query string location / { try_files $uri $uri/ /index.php?$args; } #WPMU Files location ~ ^/files/(.*)$ { try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ; access_log off; log_not_found off; expires max; } #WPMU x-sendfile to avoid php readfile() location ^~ /blogs.dir { internal; alias /var/www/yyr.im/public/wordpress/wp-content/blogs.dir; access_log off; log_not_found off; expires max; } #add some rules for static content expiry-headers here 此处可以继续添加伪静态规则 # additional config include nginxconfig.io/general.conf; include nginxconfig.io/wordpress.conf; include pagespeed/pagespeed.conf; } # HTTP redirect server { listen 80 fastopen=3 reuseport; listen [::]:80 fastopen=3 reuseport; server_name .yyr.im; location / { return 301 https://yyr.im$request_uri; } |
修改完後執行sudo service openresty force-reload
重新加載OpenResty配置。
WordPress配置
編輯Wordpress安裝目錄中的wp-config.php
在 /* That’s all, stop editing! Happy blogging. */
上面加入define('WP_ALLOW_MULTISITE', true);
然後重新進入Wordpress後台-工具-網址網路安裝,根據提示操作即可。之後你就可以加入你想要的子域名站點了。
訪問無效子域名自動跳轉到主域名
默認情況下檔訪問一個不存在的子域名時比如test.yyr.im
,會提示註冊該子域建立新的子站,如果你不是Blog服務商的話,這對你是毫無意義的。如果想要在訪問無效子域名時自動跳轉到主域名,可以編輯 wp-config.php
在 /* That’s all, stop editing! Happy blogging. */
上面加入 define( 'NOBLOGREDIRECT', '%siteurl%' );
之後訪問無效子域名便會跳轉到主域名,但是訪問不存在的頁面時也會跳轉到主域名,也就是說不能顯示404頁面,要解決這個問題,可以在wp-content
目錄下創建mu-plugins
文件夾,在 mu-plugins
文件夾裡創建custom.php
,內容如下。
1 2 |
<?php remove_action( 'template_redirect', 'maybe_redirect_404' ); |
設置網站圖標
關於網站圖標的相關知識參考:https://www.zhangxinxu.com/wordpress/2019/06/html-favicon-size-ico-generator/
如果可以,建議製作矢量的網站圖標,存儲為favicon.svg,再上傳到 https://realfavicongenerator.net/ 根據提示生成圖標文件和XHTML配置代碼,將圖標文件下載解壓縮到網站根目錄中,然後將剛才製作的 favicon.svg 也放到網站根目錄中。
接下來需要在佈景主題中的header.php中插入剛才生成的配置代碼,手動加入的話每次更換主題都要修改header.php,使用Insert Headers and Footers插件的話可以一勞永逸,安裝並啟用該插件後在設定中就能看到Insert Headers and Footers進入之後在“填入首頁指令碼”的位置粘帖上剛才生成的代碼,再在第二行插入<link rel="icon" type="image/svg+xml" sizes="any" href="/favicon.svg"/>
,以啟用文件尺寸更小的SVG格式圖標,完整內容如下:
1 2 3 4 5 6 7 8 |
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"/> <link rel="icon" type="image/svg+xml" sizes="any" href="/favicon.svg"/> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/> <link rel="manifest" href="/site.webmanifest"/> <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"/> <meta name="msapplication-TileColor" content="#2b5797"/> <meta name="theme-color" content="#ffffff"/> |
安全性優化
配置加密套件
加密套件的作用是保障服務器與客戶端之間數據傳輸的保密性和準確性。一套加密套件包括了密鑰交換算法、認證算法、批量加密算法、完整性檢驗算法。例如ECDHE-ECDSA-AES256-GCM-SHA384表示使用了ECDHE密鑰交換算法、ECDSA認證算法、AES256-GCM批量加密算法、SHA384完整性檢驗算法的加密套件。
目前主流的密鑰交換算法有ECDHE(Elliptic Curve Diffie–Hellman key Exchange 橢圓曲線迪菲-赫爾曼密鑰交換)和DHE(Diffie–Hellman key exchange 迪菲-赫爾曼密鑰交換)兩種,ECDHE比DHE安全效能更好,支持TLS 1.2的瀏覽器都支持ECDHD,因此只使用ECDHE作為密鑰交換算法。
加密套件是在 /usr/local/openresty/nginx/conf/nginx.conf
中配置的,因為只使用 ECDHE沒使用DHE,所以不需要 dhparam.pem,應在/etc/nginx/nginx.conf
删除ssl_dhparam /etc/nginx/dhparam.pem;
,具體加密套件配置如下:
1 2 3 4 5 |
# Mozilla Intermediate configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305; ssl_ecdh_curve secp384r1; ssl_prefer_server_ciphers on; |
修改完執行sudo service openresty force-reload
重新加載配置後,SSLLabs評分應該能達到A+
唯一的Cipher Strength沒有滿分是因為TLS 1.3協議中綁定了TLS_AES_128_GCM_SHA256加密套件,使用低於AES256的加密套件會被扣分,若一定要追求全部滿分,可以取消TLS 1.3支持。
HTTP response headers安全配置
詳細介紹可以看這裡 https://segmentfault.com/a/1190000018463035
配置文件放在/usr/local/openresty/nginx/conf/nginxconfig.io/security.conf
針對WordPress我的配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# security headers #參考 https://segmentfault.com/a/1190000018463035 add_header X-Frame-Options "sameorigin" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "block-all-mixed-content; upgrade-insecure-requests; default-src 'none'; base-uri 'self'; connect-src 'self'; font-src 'self' data: fonts.gstatic.com cdn.jsdelivr.net; form-action 'self'; frame-ancestors 'self'; frame-src 'self' akismet.com wp-themes.com; img-src 'self' data: secure.gravatar.com ts.w.org ps.w.org wpdotorg.files.wordpress.com wp-themes.com cdn.jsdelivr.net; manifest-src 'self' cdn.jsdelivr.net; media-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' wp-themes.com akismet.com cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' wp-themes.com fonts.googleapis.com akismet.com cdn.jsdelivr.net; worker-src 'self'" always; #參考 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy add_header Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'self'; usb 'none'; vibrate 'none'; vr 'none'; wake-lock 'none'" always; #參考 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Feature-Policy add_header Strict-Transport-Security "max-age=315360000; includeSubDomains; preload" always; add_header Expect-CT "enforce; max-age=315360000" always; add_header Cache-Control "no-cache; max-age=0" always; add_header Accept-Ranges "bytes" always; # . files location ~ /\.(?!well-known) { deny all; } |
主要需要注意的是Content-Security-Policy的配置,如果你的網站需要引用外站的東西,就得同時更新Content-Security-Policy配置,在Chrome可以按F12檢查哪些內容被CSP阻止加載。
上面配置中包含了HSTS(HTTP Strict Transport Security HTTP嚴格傳輸安全)要使其生效的話,還需要在 https://hstspreload.org/ 提交你的域名。
按照上面的配置可以
websecurity.is評分96
Mozilla Observatory 評分80(B+)
上述三個網站安全性檢測網站的扣分原因都是Content-Security-Policy規則中的script-src和style-src使用了'unsafe-inline'
和'unsafe-eval'
這兩個參數,去掉這兩個參數就能得到滿分,但是WordPress的主題商店和插件商店就無法正常使用了。
限制HTTP請求類型
作為WordPress網站,通常只使用使用以下HTTP請求
GET
GET
方法請求展示指定資源。使用GET
的請求只應用於取得資料。HEAD
HEAD
方法請求與GET
方法相同的回應,但它沒有回應主體(response body)。POST
POST
方法用於提交指定資源的實體,通常會改變伺服器的狀態或副作用(side effect)。
開放其他請求會造成安全隱患,因此只開放這幾個請求就好,在網站配置文件中插入以下代碼
1 2 3 4 5 6 7 8 9 |
#僅開啟GET POST請求,避免其他請求被惡意利用 if ($request_method !~ ^(HEAD|GET|POST)$) { return 403; } #快速響應HEAD請求 if ($request_method ~ ^(HEAD)$ ) { return 200 "All OK"; } |
通過一些插件增加網站安全性
- Akismet Anti-Spam – 減少垃圾評論
- NoSpamNX – 減少垃圾評論
- WPS Hide Login – 修改默認登錄網址
- Limit Login Attempts Reloaded – 限制登錄密碼錯誤重試次數,防止網站登錄帳號被暴力破解
- Search Limiter & Blocker – 限制搜索使用頻率,防止濫用搜索功能造成網站崩潰
性能優化
使用jsDelivr公共CDN免費加速js和css文件
jsDelivr是全球性的公共CDN服務,罕見的在中國大陸也部署有節點。對於WordPress可以通過安裝並啟用commonWP這個插件,無需額外任何設置,就可以將所有頁面上可加速的js、css文件更換為jsDelivr的地址。注意如果設置了Content-Security-Policy需保證允許加載來自cdn.jsdelivr.net的文件。
優化function.php,取消加載不必要的功能
function.php是位於主題目錄下的一個功能函數文件,因此每次更換主題後,都要重新修改function.php,為了消除這種不便我們可以使用Code Snippets這個插件來修改function.php。
function.php的優化代碼參考了
https://www.mf8.biz/use-function-make-wp-fast/
https://yungke.me/speed-wordpress-optimization/
我主要加入了如下代碼:
强制jquery库文件底部载入
将 JS 放到最后加载,有利于提高网站加载效率
1 2 3 4 5 6 |
//强制jquery库文件底部载入 function ds_print_jquery_in_footer( &$scripts) { if ( ! is_admin() ) $scripts->add_data( 'jquery', 'group', 1 ); } add_action( 'wp_default_scripts', 'ds_print_jquery_in_footer' ); |
删除 wp_head 中无关紧要的代码
1 2 3 4 5 6 |
remove_action('wp_head', 'rsd_link'); remove_action('wp_head', 'wlwmanifest_link'); remove_action('wp_head', 'wp_generator'); remove_action('wp_head', 'start_post_rel_link'); remove_action('wp_head', 'index_rel_link'); remove_action('wp_head', 'adjacent_posts_rel_link'); |
禁用Emoji功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function disable_emojis() { remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ); remove_action( 'wp_print_styles', 'print_emoji_styles' ); remove_action( 'admin_print_styles', 'print_emoji_styles' ); remove_filter( 'the_content_feed', 'wp_staticize_emoji' ); remove_filter( 'comment_text_rss', 'wp_staticize_emoji' ); remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' ); add_filter( 'tiny_mce_plugins', 'disable_emojis_tinymce' ); } add_action( 'init', 'disable_emojis' ); /** * remove the tinymce emojis plugin. */ function disable_emojis_tinymce( $plugins ) { if ( is_array( $plugins ) ) { return array_diff( $plugins, array( 'wpemoji' ) ); } else { return array(); } } |
屏蔽文章 Embed 功能
1 2 3 4 |
function my_deregister_scripts(){ wp_dequeue_script( 'wp-embed' ); } add_action( 'wp_footer', 'my_deregister_scripts' ); |
移除頭部 wp-json 標籤和 HTTP header 中的 link
1 2 |
remove_action('wp_head', 'rest_output_link_wp_head', 10 ); remove_action('template_redirect', 'rest_output_link_header', 11 ); |
移除 wlwmanifest, RSD, Shortlink 的鏈接
是由 Windows Live Writer / RSD 所使用的。利用 XML-RPC 第三方應用程序請求使用,在大多數情況下,這都是不必要的代碼。
另外,WordPress 內附頁面的縮網址。如果你已經設置了固定鏈接,例如:domain.com/post,那麼沒有理由使用縮網址,這只是不必要的代碼。
1 2 3 4 5 6 |
function remheadlink() { remove_action( 'wp_head', 'wlwmanifest_link'); remove_action ('wp_head', 'rsd_link'); remove_action( 'wp_head', 'wp_shortlink_wp_head'); } add_action('init', 'remheadlink'); |
禁用 Self Pingbacks 鏈接
pingback 是一個自動鏈接,當另一個部落格鏈接到你的文章時就會創建一個 Pingback,基本上只是個垃圾郵件,浪費主機資源,建議將他禁用。
1 2 3 4 5 6 7 |
function no_self_ping( &$links ) { $home = get_option( 'home' ); foreach ( $links as $l => $link ) if ( 0 === strpos( $link, $home ) ) unset($links[$l]); } add_action( 'pre_ping', 'no_self_ping' ); |
禁用REST API
1 2 3 4 5 6 7 8 9 10 11 12 |
// Filters for WP-API version 1.x add_filter('json_enabled', '__return_false'); add_filter('json_jsonp_enabled', '__return_false'); // Filters for WP-API version 2.x add_filter('rest_enabled', '__return_false'); add_filter('rest_jsonp_enabled', '__return_false'); // Remove REST API info from head and headers remove_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' ); remove_action( 'wp_head', 'rest_output_link_wp_head', 10 ); remove_action( 'template_redirect', 'rest_output_link_header', 11 ); |
移除 jQuery Migrate
大多數的佈景主題的前端代碼和外掛都不需要 jquery-migrate.min.js 文件,只有一些較舊的網站會用到 jQuery 函數,這只會為您的網站增加不必要的加載。
1 2 3 4 5 6 7 |
function isa_remove_jquery_migrate( &$scripts) { if(!is_admin()) { $scripts->remove( 'jquery'); $scripts->add( 'jquery', false, array( 'jquery-core' ), '1.12.4' ); } } add_filter( 'wp_default_scripts', 'isa_remove_jquery_migrate' ); |
關閉XML-RPC功能
這個功能主要用於WordPress客戶端連接,同時一些攻擊者也會利用這個功能嘗試破解管理密碼,如果你不使用WordPress客戶端可以關閉它。
1 |
add_filter('xmlrpc_enabled', '__return_false'); |
緩存優化
眾所周知WordPress是個PHP動態建站程序,默認情況下所有操作包括頁面訪問都需要後台進行計算,再將所需結果呈現出來,緩存的作用就是將計算結果存儲起來,下次需要相同的內容時直接從緩存中調取,而不必重新計算耗費系統資源,緩存優化是WordPress最重要的優化手段。
在這裡,緩存優化包括了頁面緩存、對象緩存
頁面緩存優化
頁面緩存的實現方式可分為插件和後端工具,
插件是指利用諸如WP Super Cache、W3 Total Cache、WP-Rocket這樣的插件來實現頁面緩存功能。
緩存調用流程為:瀏覽器-網頁服務器-WordPress-插件-緩存
後端工具實現方式則是直接配合網頁服務器來實現頁面緩存。
緩存調用流程為:瀏覽器-網頁服務器-緩存
很顯然通過後端工具實現頁面緩存是更有效率的方式,目前WordPress的後端頁面緩存優化方案主要有:
- Memcached
- Redis
- FastCGI Cache
- Pika
其中Memcached和Redis是將緩存內容存儲在內存中,但考慮到入門級主機內存不大,只能放棄這樣的方案,如果為了性能一定要使用內存級頁面緩存,對於入門主機建議使用內存利用率更高的Mencached。FastCGI Cache和Pika都是將緩存數據存儲在硬盤中,FastCGI Cache是Nginx自帶的功能,Pika可以看作是Redis的硬盤版,兼容Redis相關工具,功能更為強大。Pika存取緩存需要走TCP/IP協議,這樣也可以存取其他的主機的緩存實現強大的集群功能,但單機性能上不如直接通過Unix socket存取緩存的FastCGI Cache快,實際測試下來也是Pika比FastCGI Cache載入相同的頁面略慢幾十毫秒。對於入門主機FastCGI Cache實現頁面緩存更為合適,但可能由於我使用的是OpenResty的原因,雖然可以成功的存取緩存,但是不能利用WordPress的Nginx Helper插件刷新和清除過時的緩存。考慮到實際Pika和FastCGI Cache性能差距並不算太大通常就,所以就暫時用Pika來實現頁面緩存,下次換主機的時候再試試Nginx+FastCGI Cache來實現WordPress頁面緩存。
安裝pika
參考:https://github.com/Qihoo360/pika/wiki/%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8
https://blog.csdn.net/weixin_34396103/article/details/92592243/
http://liyangliang.me/posts/2015/06/using-supervisor/
先去Pika的releases頁面查看最新版本
1 2 3 4 5 6 7 8 9 10 |
cd /opt #下載Pika wget https://github.com/Qihoo360/pika/releases/download/v3.3.1/pika-linux-x86_64-v3.3.1.tar.bz2 #解壓 tar -jxvf pika-linux-x86_64-v3.3.1.tar.bz2 #重命名 sudo mv output pika #建立相關目錄並設目錄所有者 mkdir -p /data/pika/log/ /data/pika/db /opt/pika/dump/ /data/pika/dbsyn chown -R www-data.www-data /data/pika/log/ /data/pika/db /opt/pika/dump/ /data/pika/dbsyn |
在Pika配置文件中配置相關路徑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# Pika port port : 9221 # Thread Number thread-num : 1 # Thread Pool Size thread-pool-size : 12 # Sync Thread Number sync-thread-num : 6 # Pika log path log-path :/data/pika/log/ # Pika db path db-path : /data/pika/db/ # Pika write-buffer-size write-buffer-size : 268435456 # Pika timeout timeout : 60 # Requirepass requirepass : # Masterauth masterauth : # Userpass userpass : # User Blacklist userblacklist : # if this option is set to 'classic', that means pika support multiple DB, in # this mode, option databases enable # if this option is set to 'sharding', that means pika support multiple Table, you # can specify slot num for each table, in this mode, option default-slot-num enable # Pika instance mode [classic | sharding] instance-mode : classic # Set the number of databases. The default database is DB 0, you can select # a different one on a per-connection basis using SELECT <dbid> where # dbid is a number between 0 and 'databases' - 1, limited in [1, 8] databases : 1 # default slot number each table in sharding mode default-slot-num : 1024 # replication num defines how many followers in a single raft group, only [0, 1, 2, 3, 4] is valid replication-num : 0 # consensus level defines how many confirms does leader get, before commit this log to client, # only [0, ...replicaiton-num] is valid consensus-level : 0 # Dump Prefix dump-prefix : # daemonize [yes | no] #daemonize : yes # Dump Path dump-path : /data/pika/dump/ # Expire-dump-days dump-expire : 0 # pidfile Path pidfile : ./pika.pid # Max Connection maxclients : 20000 # the per file size of sst to compact, default is 20M target-file-size-base : 20971520 # Expire-logs-days expire-logs-days : 7 # Expire-logs-nums expire-logs-nums : 10 # Root-connection-num root-connection-num : 2 # Slowlog-write-errorlog slowlog-write-errorlog : no # Slowlog-log-slower-than slowlog-log-slower-than : 10000 # Slowlog-max-len slowlog-max-len : 128 # Pika db sync path db-sync-path : /data/pika/dbsync/ # db sync speed(MB) max is set to 1024MB, min is set to 0, and if below 0 or above 1024, the value will be adjust to 1024 db-sync-speed : -1 # The slave priority slave-priority : 100 # network interface #network-interface : eth1 # replication #slaveof : master-ip:master-port # CronTask, format 1: start-end/ratio, like 02-04/60, pika will check to schedule compaction between 2 to 4 o'clock everyday # if the freesize/disksize > 60%. # format 2: week/start-end/ratio, like 3/02-04/60, pika will check to schedule compaction between 2 to 4 o'clock # every wednesday, if the freesize/disksize > 60%. # NOTICE: if compact-interval is set, compact-cron will be mask and disable. # #compact-cron : 3/02-04/60 # Compact-interval, format: interval/ratio, like 6/60, pika will check to schedule compaction every 6 hours, # if the freesize/disksize > 60%. NOTICE:compact-interval is prior than compact-cron; #compact-interval : # the size of flow control window while sync binlog between master and slave.Default is 9000 and the maximum is 90000. sync-window-size : 9000 # max value of connection read buffer size: configurable value 67108864(64MB) or 268435456(256MB) or 536870912(512MB) # default value is 268435456(256MB) # NOTICE: master and slave should share exactly the same value max-conn-rbuf-size : 268435456 ################### ## Critical Settings ################### # write_binlog [yes | no] write-binlog : yes # binlog file size: default is 100M, limited in [1K, 2G] binlog-file-size : 104857600 # Automatically triggers a small compaction according statistics # Use the cache to store up to 'max-cache-statistic-keys' keys # if 'max-cache-statistic-keys' set to '0', that means turn off the statistics function # it also doesn't automatically trigger a small compact feature max-cache-statistic-keys : 0 # When 'delete' or 'overwrite' a specific multi-data structure key 'small-compaction-threshold' times, # a small compact is triggered automatically, default is 5000, limited in [1, 100000] small-compaction-threshold : 5000 # If the total size of all live memtables of all the DBs exceeds # the limit, a flush will be triggered in the next DB to which the next write # is issued. max-write-buffer-size : 10737418240 # Limit some command response size, like Scan, Keys* max-client-response-size : 1073741824 # Compression type supported [snappy, zlib, lz4, zstd] compression : snappy # max-background-flushes: default is 1, limited in [1, 4] max-background-flushes : 1 # max-background-compactions: default is 2, limited in [1, 8] max-background-compactions : 2 # maximum value of Rocksdb cached open file descriptors max-cache-files : 5000 # max_bytes_for_level_multiplier: default is 10, you can change it to 5 max-bytes-for-level-multiplier : 10 # BlockBasedTable block_size, default 4k # block-size: 4096 # block LRU cache, default 8M, 0 to disable # block-cache: 8388608 # whether the block cache is shared among the RocksDB instances, default is per CF # share-block-cache: no # whether or not index and filter blocks is stored in block cache # cache-index-and-filter-blocks: no # when set to yes, bloomfilter of the last level will not be built # optimize-filters-for-hits: no # https://github.com/facebook/rocksdb/wiki/Leveled-Compaction#levels-target-size # level-compaction-dynamic-level-bytes: no |
設置Pika開機自動啟動
首先安裝supervisor
Superviosr是一个进程管理工具,可以保证你的程序在服务器开机时自动启动以及程序意外终止时重新启动。当你的项目有多个并且需要同时启动或关闭,使用Supervisor一行命令都可以同时重启,而不是一个一个命令地重启。
參考:
https://zhuanlan.zhihu.com/p/92154179
http://frankchen.xyz/2017/07/06/Use-supervisor-support-Python3-program/
http://liyangliang.me/posts/2015/06/using-supervisor/
1 |
sudo apt-get install supervisor |
建立Pika開機啟動配置文件/etc/supervisor/conf.d/pika.conf
內容如下
1 2 3 4 5 6 7 8 9 10 11 |
[program:pika] command=/opt/pika/bin/pika -c /opt/pika/conf/pika.conf ;process_name=%(process_num)02d numprocs=1 user=www-data autostart=true autorestart=true redirect_stderr=true stdout_logfile=/data/logs/pika/pika_sup.log stdout_logfile_maxbytes=50MB stdout_logfile_backups=5 |
根據最新配置文件啟動進程
1 |
supervisorctl update |
測試Pika是否正常工作
安裝Redis-tools
1 |
sudo apt-get install redis-tools |
連接到Pika
1 |
redis-cli -h 127.0.0.1 -p 9221 |
寫入並讀取數據
1 2 3 4 |
> SET user redistester OK > GET user "redistester" |
如果可以正常寫入讀取數據則說明Pika工作正常。
驗證完成後清空數據庫
1 2 |
> FLUSHALL OK |
配置OpenResty在Pika中存取頁面緩存
參考:https://www.mf8.biz/nginx-redis-cache-make-wordpress-fast/
创建連接Pika服務器的配置文件/usr/local/openresty/nginx/conf/nginxconfig.io/heaer_redis.conf
1 2 3 4 |
upstream redis { server 127.0.0.1:9221; keepalive 512; } |
創建頁面緩存存取規則配置文件/usr/local/openresty/nginx/conf/nginxconfig.io/redis.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 |
location /redis-fetch { internal ; set $redis_key $args; redis_pass redis; } location /redis-store { internal ; set_unescape_uri $key $arg_key ; redis2_query set $key $echo_request_body; redis2_query expire $key 14400; redis2_pass redis; } |
創建頁面緩存忽略規則配置文件/usr/local/openresty/nginx/conf/nginxconfig.io/skipcache.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 |
set $skip_cache 0; if ($request_method = POST) { set $skip_cache 1; } if ($query_string != "") { set $skip_cache 1; } if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") { set $skip_cache 1; } if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $skip_cache 1; } |
將上面三個新創建的文件嵌入到網站配置文件/usr/local/openresty/nginx/conf/sites-available/yyr.im.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#Redis include nginxconfig.io/header_redis.conf; #FastCGI Cache #include nginxconfig.io/header_fastcgi_cache.conf; #WP多站配置 map $http_host $blogid { default -999; } server { listen 443 ssl http2 fastopen=3; listen [::]:443 ssl http2 fastopen=3; server_name .yyr.im; set $base /var/www/yyr.im; root $base/public/wordpress; # SSL #ECC ssl_certificate /var/www/yyr.im/certificate/yyr.im_ecc_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_ecc.key; #ssl_trusted_certificate /var/www/yyr.im/certificate/yyr.im_ecc_ca.cer; #RSA ssl_certificate /var/www/yyr.im/certificate/yyr.im_rsa_fullchain.cer; ssl_certificate_key /var/www/yyr.im/certificate/yyr.im_rsa.key; #ssl_trusted_certificate /var/www/yyr.im/certificate/yyr.im_rsa_ca.cer; # security include nginxconfig.io/security.conf; # index index index.php; #Skip Cache include nginxconfig.io/skipcache.conf; #redis include nginxconfig.io/redis.conf; #fastcgi cache purge #include nginxconfig.io/purge.conf; location ~ [^/]\.php(/|$) { include nginxconfig.io/php_fastcgi.conf; #include nginxconfig.io/fastcgi_cache.conf; include nginxconfig.io/srcache.conf; } #僅開啟GET POST請求,避免其他請求被惡意利用 if ($request_method !~ ^(HEAD|GET|POST)$) { return 403; } #快速響應HEAD請求 if ($request_method ~ ^(HEAD)$ ) { return 200 "All OK"; } #WP多站配置 # wordpress固定链接设置 # This is cool because no php is touched for static content. # include the "?$args" part so non-default permalinks doesn't break when using query string location / { try_files $uri $uri/ /index.php?$args; } #WPMU Files location ~ ^/files/(.*)$ { try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ; access_log off; log_not_found off; expires max; } #WPMU x-sendfile to avoid php readfile() location ^~ /blogs.dir { internal; alias /var/www/yyr.im/public/wordpress/wp-content/blogs.dir; access_log off; log_not_found off; expires max; } #add some rules for static content expiry-headers here 此处可以继续添加伪静态规则 # additional config include nginxconfig.io/general.conf; include nginxconfig.io/wordpress.conf; include pagespeed/pagespeed.conf; } # HTTP redirect server { listen 80 fastopen=3; listen [::]:80 fastopen=3; server_name .yyr.im; location / { return 301 https://yyr.im$request_uri; } } |
完後在重新加載配置文件使其生效
1 |
sudo service openresty force-reload |
使用Chrome打開網站,退出登錄,按F12
打開如下視圖,按幾次F5刷新頁面,若看到x-cache: BYPASS則說明已經在使用緩存了。
使用Nginx Helper清除過時緩存
完成前面的步驟,網站已經可以從緩存中調取內容呈現給前台用戶,但頁面內容若有更新,應當清除過時緩存,再重新緩存新的內容,這就需要使用WordPress的Nginx Helper插件了。安裝該插件後進入設置頁面,如下圖所示,填入剛剛搭建的Pika服務的主機ip和端口。其他選項默認就好,或根據自己需求調整。設置完成後該插件在滿足條件的情況下將自動清除過時的緩存。
對象緩存優化
我的理解對象緩存是數據庫查詢結果緩存,前面已經在前端做了頁面緩存,那麼再做對象緩存優化理論上只對網站後台操作和搜索功能有效果,所以做了頁面緩存優化再做對象緩存優化通常不是很有必要。但作為一個追求極致的人,我還是把這步優化做了。前面已經安裝配置好Pika,PHP程序存取Pika中的對象數據需安裝php的redis擴展。
安裝php的redis擴展
建議使用pecl工具安裝php的redis擴展,使用apt安裝似乎需要一些額外的配置才能正常使用。首先安裝pecl工具。參考http://yzone.net/blog/153
1 |
sudo apt install php-pear php-dev --no-install-recommends |
如果你前面沒有裝過build-essential
那麼就需要獨立安裝g++
以確保pecl可以正確安裝php擴展。
接下來使用pecl安裝php的redis擴展。
1 |
sudo pecl install redis |
WordPress配置
安裝Redis Object Cache插件。並將如下代碼加入到wp-config.php文件中/* That's all, stop editing! Happy publishing. */
的上方,並根據實際情況修改。
1 2 3 4 5 6 |
define('WP_REDIS_CLIENT', 'pecl'); // 指定與Pika/Redis通信的客戶端, pecl 即 The PHP Extension Community Library define('WP_REDIS_SCHEME', 'tcp'); // 連接Pika/Redis的通信協議,目前Pika只支持tcp define('WP_REDIS_HOST', '127.0.0.1'); //Pika/Redis的服務器ip define('WP_REDIS_PORT', '9221'); // Pika/Redis的端口 define('WP_REDIS_DATABASE', '0'); // 指定所用數據庫 define('WP_CACHE_KEY_SALT', 'wp_');數據前綴 |
進入Redis Object Cache設定界面,檢查服務器信息是否正確,若正確,則點擊“啟用物件快取”當出現“已連接”則說明設置成功。
自動刷新緩存
在functions.php加入下面代碼實現自動刷新緩存。
1 2 3 4 5 6 7 8 |
//发布、更新文章刷新缓存 add_action('publish_post', 'redis_Refresh_By_Publish', 0); //文章单页删除 add_action('publish_page', 'redis_Refresh_By_page_Publish', 0); //提交评论刷新缓存 add_action('comment_post', 'redis_Refresh_By_Comments',0); //审核评论刷新缓存 add_action('comment_unapproved_to_approved', 'redis_Refresh_By_Approved',0); |
參考:https://www.phpsong.com/2917.html
配置PageSpeed
前面已經把PageSpeed Nginx Module編譯進OpenResty。下面直接開始它的配置。
參考:https://sufob.com/lnmp-nginx-add-google-pagespeed-module-combine-compress-js-css-convert-webp-async-loading/
配置PageSpeed優化選項
建立/usr/local/openresty/nginx/conf/pagespeed/main.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
#main.conf #PageSpeed 配置 pagespeed on; #1.12.34.1以上可设置all pagespeed ProcessScriptVariables all; #启用PageSpeed Gzip请求资源,此项要求ng启用gzip pagespeed FetchWithGzip on; #配置筛选项默认CoreFilters pagespeed RewriteLevel CoreFilters; # X-Header 值,用于判断是否生效 pagespeed XHeaderValue "Powered By yyr.im"; #是否尊重原始header pagespeed RespectVary off; #PageSpeed能够根据响应头中指定的任何内容安全策略调整其优化 pagespeed HonorCsp on; #防止重新壓縮 pagespeed NoTransformOptimizedImages on; #是否让PageSpeed优化缓存时间(接管缓存控制) pagespeed DisableRewriteOnNoTransform off; #重写HTML缓存头 pagespeed ModifyCachingHeaders on; #列出未解决的错误 pagespeed ListOutstandingUrlsOnError on; #限制资源最大值启用优化,默认大小16M pagespeed MaxCacheableContentLength 16777216; #配置共享内存元数据缓存 pagespeed CreateSharedMemoryMetadataCache "/var/cache/pagespeed/" 51200; #共享内存元数据缓存检查点,5分钟一次 pagespeed ShmMetadataCacheCheckpointIntervalSec 300; #配置文件高速缓存 pagespeed FileCachePath /var/cache/pagespeed; pagespeed FileCacheSizeKb 102400; pagespeed FileCacheCleanIntervalMs 3600000; pagespeed FileCacheInodeLimit 500000; pagespeed LRUCacheKbPerProcess 8192; pagespeed LRUCacheByteLimit 16384; # 禁止 pagespeed 处理/wp-admin/目录 pagespeed Disallow "*/wp-admin/*"; pagespeed Disallow "*/wp-login.php*"; # 禁止 pagespeed 处理/wp-default/目录 pagespeed Disallow "*/wp-default/*"; #开启使用Redis(和memcached只能先其一) pagespeed RedisServer "127.0.0.1:9221"; #缓存清除 pagespeed EnableCachePurge on; pagespeed PurgeMethod PURGE; #清空缓存临界值,优化率80% pagespeed DownstreamCacheRewrittenPercentageThreshold 80; #PageSpeed管理页面配置 #共享内存统计 pagespeed Statistics on; #开启虚拟主机统计信息 pagespeed UsePerVhostStatistics on; pagespeed StatisticsLogging on; pagespeed StatisticsLoggingIntervalMs 60000; pagespeed StatisticsLoggingMaxFileSizeKb 1024; #消息缓冲区大小,默认为0,不保留消息 pagespeed MessageBufferSize 100000; pagespeed LogDir /var/log/pagespeed; pagespeed StatisticsPath /ngx_pagespeed_statistics; pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics; pagespeed MessagesPath /ngx_pagespeed_message; pagespeed ConsolePath /pagespeed_console; pagespeed AdminPath /pagespeed_admin; pagespeed GlobalAdminPath /pagespeed_global_admin; |
建立/usr/local/openresty/nginx/conf/pagespeed/pagespeed.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#pagespeed.conf #PageSpeed优化设置 #直接获取HTTPS资源 pagespeed FetchHttps enable; #允许自签名证书资源 #pagespeed FetchHttps enable,allow_self_signed; #加载筛选文件 include pagespeed/filters.conf; #启用测量客户端加载和呈现页面所花费的时间 pagespeed EnableFilters add_instrumentation; #预处理DNS pagespeed EnableFilters insert_dns_prefetch; #资源预加载 pagespeed EnableFilters hint_preload_subresources; #异步加载Google广告 pagespeed EnableFilters make_show_ads_async; #异步加载Google统计 pagespeed EnableFilters make_google_analytics_async; #插入Google Analytics #pagespeed EnableFilters insert_ga; #pagespeed AnalyticsID <Analytics ID>; #提示资源预加载 在http响应头添加head 以便预加载 pagespeed EnableFilters hint_preload_subresources; #缓存 開啟此處會導致網頁錯亂 #相当于同时使用了extend_cache_images, extend_cache_scripts和 extend_cache_css pagespeed EnableFilters extend_cache; pagespeed EnableFilters extend_cache_pdfs; pagespeed EnableFilters local_storage_cache; #确保对pagespeed优化资源的请求进入pagespeed处理程序并且没有额外的头部信息 location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; } location ~ "^/pagespeed_static/" { } location ~ "^/ngx_pagespeed_beacon$ps_dollar" { } #PageSpeed Admin Dashboard include pagespeed/dashboard.conf; |
建立/usr/local/openresty/nginx/conf/pagespeed/filters.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#filters.conf ## Text / HTML pagespeed EnableFilters combine_heads; # 启用压缩空白过滤器 pagespeed EnableFilters collapse_whitespace; pagespeed EnableFilters convert_meta_tags; # 删除带默认属性的标签 pagespeed EnableFilters elide_attributes; pagespeed EnableFilters pedantic; pagespeed EnableFilters remove_comments; pagespeed EnableFilters remove_quotes; pagespeed EnableFilters trim_urls; ## JavaScript pagespeed EnableFilters canonicalize_javascript_libraries; pagespeed EnableFilters inline_javascript; pagespeed EnableFilters combine_javascript; pagespeed EnableFilters rewrite_javascript; #pagespeed EnableFilters outline_javascript; #高风险,延迟加载js #pagespeed EnableFilters defer_javascript; ## CSS #pagespeed EnableFilters outline_css; pagespeed EnableFilters inline_import_to_link; pagespeed EnableFilters inline_css; pagespeed EnableFilters inline_google_font_css; pagespeed EnableFilters combine_css; pagespeed EnableFilters move_css_above_scripts; pagespeed EnableFilters move_css_to_head; pagespeed EnableFilters prioritize_critical_css; pagespeed EnableFilters fallback_rewrite_css_urls; # 优化内嵌样式属性 pagespeed EnableFilters rewrite_style_attributes; # CSS 的 URL 重置 pagespeed EnableFilters rewrite_style_attributes_with_url; # 通过删除 CSS 文件中的@import,减少 HTTP 请求往返次数。 pagespeed EnableFilters flatten_css_imports; pagespeed CssFlattenMaxBytes 5120; pagespeed EnableFilters rewrite_css; ## Images # 使用 JavaScript 从第一次出现图像加载图像替换重复的内联图像 pagespeed EnableFilters dedup_inlined_images; pagespeed EnableFilters insert_image_dimensions; #pagespeed EnableFilters inline_preview_images; pagespeed EnableFilters resize_mobile_images; pagespeed EnableFilters lazyload_images; #pagespeed LazyloadImagesBlankUrl "//static.youfencun.com/1.gif"; # 不加载显示区域以外的图片 #pagespeed LazyloadImagesAfterOnload off; #pagespeed CriticalImagesBeaconEnabled false; #(优化图片,实际使用了inline_images,recompress_images,convert_to_webp_lossless,resize_images) #pagespeed EnableFilters rewrite_images; pagespeed EnableFilters inline_images; pagespeed EnableFilters convert_gif_to_png; pagespeed EnableFilters convert_jpeg_to_progressive; pagespeed EnableFilters recompress_jpeg; pagespeed EnableFilters recompress_png; #pagespeed EnableFilters recompress_webp; pagespeed EnableFilters strip_image_color_profile; pagespeed EnableFilters strip_image_meta_data; pagespeed EnableFilters jpeg_subsampling; #pagespeed EnableFilters convert_png_to_jpeg; pagespeed EnableFilters responsive_images; pagespeed EnableFilters resize_rendered_image_dimensions; #pagespeed EnableFilters convert_jpeg_to_webp; #pagespeed EnableFilters convert_to_webp_animated; pagespeed EnableFilters convert_to_webp_lossless; pagespeed EnableFilters sprite_images; pagespeed EnableFilters responsive_images; pagespeed EnableFilters resize_images; pagespeed EnableFilters responsive_images_zoom; #让JS里引用的图片也加入优化 pagespeed InPlaceResourceOptimization on; pagespeed EnableFilters in_place_optimize_for_browser; |
建立/usr/local/openresty/nginx/conf/pagespeed/dashboard.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
location /ngx_pagespeed_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } location /ngx_pagespeed_global_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } location /ngx_pagespeed_message { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } location /pagespeed_console { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } location ~ ^/pagespeed_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } location ~ ^/pagespeed_global_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file pagespeed/.htpasswd; } |
配置PageSpeed緩存文件夾
1 2 3 4 5 |
mkdir /var/cache/pagespeed chown -R www-data:root /var/cache/pagespeed chmod 700 /var/cache/pagespeed mkdir /var/log/pagespeed chown -R www-data. /var/log/pagespeed |
為OpenResty啟用PageSpeed
將下列代碼加入到/usr/local/openresty/nginx/conf/nginx 的 http { }
內
1 2 |
#PageSpeed include pagespeed/main.conf; |
完後重新加載OpenResty配置文件使配置生效。
1 |
sudo service openresty force-reload |
設置PageSpeed管理界面密碼
1 2 3 4 |
#安裝htpasswd命令工具 apt-get install apache2-utils #使用htpasswd命令創建PageSpeed管理界面用戶名密碼,admin是用戶名,password是密碼 htpasswd -d -b -c /usr/local/openresty/nginx/conf/pagespeed/.htpasswd admin password |
之後就可以在https://yyr.im/pagespeed_global_admin/ 輸入上面設置的用戶名密碼進入PageSpeed管理界面了
開啟BBR、TCP Fast Open
BBR(Bottleneck Bandwidth and RTT),是一種由Google推出的拥塞控制算法,可以起到降低網絡延遲,增加寬帶利用率的效果。
TFO(TCP Fast Open TCP快速打開)是TCP 連接的一種簡化握手手續的拓展,用於提高兩端點間連接的開啟速度。
BBR和TFO使用下面的命令開啟
1 2 3 4 5 |
sudo su echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf echo "net.ipv4.tcp_fastopen=3" >> /etc/sysctl.conf sysctl -p |
查看BBR是否開啟
1 |
lsmod | grep bbr |
出現tcp_bbr
字樣說明開啟成功。
查看TCP Fast Open是否開啟
1 |
sysctl net.ipv4.tcp_fastopen |
出現net.ipv4.tcp_fastopen = 3
說明開啟成功
使TCP Fast Open對網站生效
要使TCP Fast Open對網站生效還需編輯網站配置文件 /usr/local/openresty/nginx/conf/sites-available/yyr.im.conf
在listen
那行後面加入fastopen=3
1 2 3 4 5 |
listen 443 ssl http2 fastopen=3; listen [::]:443 ssl http2 fastopen=3; listen 80 fastopen=3; listen [::]:80 fastopen=3; |
查看性能優化效果
PageSpeed Insigsth
GTmetrix
Pingdom
其他優化
下面的優化在網站訪問量巨大的情況下可能才會看到效果,對於一般個人網站來講提升非常有限,所以這部分優化對個人網站來講不是特別必要,有興趣的可以試試調整。
設置ulimit参数
首先使用 ulimit -n 1048576
命令測試系統是否支持最大數值 1048576
,若支持則可以編輯 /etc/security/limits.conf
加入
1 2 3 4 5 6 |
* soft nofile 1048576 * hard nofile 1048576 * soft memlock -1 * hard memlock -1 * soft nproc -1 * hard nproc -1 |
nofile
為最大文件打開數,memlock
為最大內存使用數,nproc
為最大進程數-1
表示不做限制。
調整ip_vs參數
ip_vs參數用於決定服務器的最大連接數
1 2 3 4 |
sudo apt install ipvsadm <br />sudo ipvsadm #查看ip_vs參數 sudo echo 'options ip_vs conn_tab_bits=22' > /etc/modprobe.d/ip_vs.conf #22代表2的22次方 sudo reboot #重啟使配置生效 sudo ipvsadm #查看ip_vs參數是否生效 |
优化sysctl.conf
待補充……
總結
這些優化只能說達到極致優化的90%,比如因為技術原因沒有啟用性能更好的FastCGI Cache,以及Nginx/OpenResty、PageSpeed、sysctl.conf還有更深的優化空間。FastCGI Cache大概會在下次換主機的時候嘗試使用。雖然WordPress有時被稱為傻瓜建站程序,但對其進行優化並不是一件簡單的事情,這也是一些專業WordPress虛擬主機的存在價值所在,但對個人網站來講使用專業WordPress虛擬主機顯得有些奢侈了。