配置LEMP(linux+nginx+mysql/myariadb+php7-fpm)以及HTTPS

By | July 3, 2017

说明:

这篇日志以在Centos上部署Nginx + MySQL + PHP fpm (Wordpress,为例阐述了这项任务的必要步骤,假设是Wordpress的文件目录已经在服务器本地,并且曾经(在另一地方)部署过。

准备工作: 需要安装Nginx,此前已经发布一篇关于编译安装Nginx的文章,请参照该文—— CentOS7 编译安装Nginx

配置 PHP-FPM

yum install epel-release -y
rpm -Uvh https://centos7.iuscommunity.org/ius-release.rpm
yum install php71u-fpm

编辑/etc/php.ini 文件:

;; 取消以下项的注释,并设值为0
cgi.fix_pathinfo=0

编辑 /etc/php-fpm.d/www.conf 文件:
取消注释并修改以下项:

user = nginx
group = nginx
listen = /run/php-fpm/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 066

取消注释以下项的注释:

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

启动php-fpm并将其设为开机启动:

systemctl start php-fpm
systemctl enable php-fpm

查看FPM是否已经运行

netstat -pl | grep php-fpm

执行结果类似如下:

unix 2 [ ACC ] STREAM LISTENING 167832 8171/php-fpm: maste /run/php-fpm/www.sock

配置Nginx

编辑/etc/nginx/nginx.conf文件:
将http指令内server部分注释,然后添加以下部分:
(此处根据wordpress官方网站上的建议,详见Nginx « WordPress Codex

# WordPress single site rules.
# Designed to be included in any server {} block.
# Upstream to abstract backend connection(s) for php
upstream php {
server unix:/run/php-fpm/www.sock;
server 127.0.0.1:9000;
}
server {
## Your website name goes here.
server_name domain1.com domain2.com;
## Your only path reference.
root /var/www/wordpress;
## This should be in your http block and if it is, it's not needed here.
index index.php;
access_log /var/www/wordpress/logs/access.log combined;
error_log /var/www/wordpress/logs/error.log notice;location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location / {
# 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
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
}

將wordpress的目录属主和属组设为nginx,开启SELinux的系统需要设置允许Nginx访问目录以及80、443两个端口的安全规则。
启动Nginx

/usr/sbin/nginx -c /etc/nginx/nginx.conf

通过浏览器访问绑定的域名,得到有“No input file specified.”提示的页面,而且访问日志(access.log)中显示该请求的状态码是404。可通过修改虚拟目录下所有的文件属主为nginx解决此问题。重新访问,已经可正常访问。

配置HTTPS

这里使用Let's Encrypt提供的HTTPS证书,通过Certbot自动获取证书。
可以在以下网站查找到各种平台和服务器如何获取和自动部署HTTPS证书的教程:https://certbot.eff.org/

获取证书的步骤如下:

运行如下命令安装依赖:

yum -y install yum-utils
yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional

安装Certbot:

yum install certbot-nginx

运行Certbot,將自动部署HTTPS证书,:

certbot --nginx

如果出现“ImportError: 'pyOpenSSL' module missing required functionality. Try upgrading to v0.14 or newer.”错误,解决办法见站内文章:解决certbot安装证书时出现的“ImportError: 'p+yOpenSSL' module missing required functionality. Try upgrading to v0.14 or newer.”错误
如果出现:

IMPORTANT NOTES:
- The following errors were reported by the server:Domain: domain1.com
Type: connection
Detail: Error getting validation data

这样的错误,要检查443端口是否开放。当出现以下消息时表示部署成功:

Congratulations! You have successfully enabled https://domian1.com and https://domian2.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=domian1.com
https://www.ssllabs.com/ssltest/analyze.html?d=domian2.com
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/domian1.com/fullchain.pem. Your cert
will expire on 2017-09-30. To obtain a new or tweaked version of
this certificate in the future, simply run certbot again with the
"certonly" option. To non-interactively renew <em>all</em> of your
certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

检查HTTPS的安全性:

访问:
https://www.ssllabs.com/ssltest/analyze.html?d=domian1.com
https://www.ssllabs.com/ssltest/analyze.html?d=domian2.com
其中,可通过以下方法增加安全性从而获得更高的评分:
配置HSTS(HTTP严格传输安全,HTTP Strict Transport Security)
將下面的语句插入到SSL相关的server 指令中:

add_header Strict-Transport-Security "max-age=31536000;includeSubDomains";

使用前向安全性:
生成一个更强壮的DHE参数

openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

在/etc/nginx/nginx.conf http块添加:

ssl_dhparam /etc/ssl/certs/dhparam.pem;
启用OCSP装订:

生成证书链文件:

cd /etc/letsencrypt/live/domain1.com
cat fullchain.pem privkey.pem >domain.chain.stapling.pem
mv domain.chain.stapling.pem /etc/ssl/certs/

编辑Nginx配置文件,在http块中添加:

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
ssl_trusted_certificate /etc/ssl/certs/domain.chain.stapling.pem;

启用HTTP公钥固定扩展(HPKP),具体步骤请移步HTTPS配置HPKP
配置加密套件:

ssl_ciphers 'AES128+EECDH:AES128+EDH';

可能Nginx会提示重复的ssl_ciphers,这时注释掉这行。

重启Nginx

设定计划任务

每天11:59和23:59执行证书的更新操作
编辑/etc/crontab文件,加上下面一行:

echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null

LEMP的部署到此完成。

部署过程中出现的一些问题及解决方案

如果重启nginx或者重启电脑后启动之时出现如下的错误日志:

systemd[1]: PID file /run/nginx.pid not readable (yet?) after start.
7月 03 00:12:54 devvps systemd[1]: nginx.service start operation timed out. Terminating.

通过取消注释并修改Nginx配置文件方式来解决该问题:

# 搜索/etc/nginx/nginx.conf文件的nginx.pid一行
# 將注释取消,并修改为:
pid /run/nginx.pid

启动Nginx即可解决问题!
参考资料:
How to Install Laravel 5.x with Nginx and PHP-FPM 7.1 on CentOS 7
Certbot
微信公众号:codelast的文章《为nginx服务器网站添加HTTPS/配置SSL证书》
解决NGINX PHP "No input file specified
PID file /run/nginx.pid not readable (yet?) after start | SvennD
增强 nginx 的 SSL 安全性-系统运维|Linux.中国-开源社区

Created on 2017.07.02

鉴于本人的相关知识储备以及能力有限,本博客的观点和描述如有错漏或是有考虑不周到的地方还请多多包涵,也欢迎指正,一起学习,共同进步。如果本文对您有帮助,而且让您觉得值得为内容付费,那么就请赞助(打赏)一下本人,这不强制。打赏支持微信支付,方法是使劲地戳一下下方的“打赏”按钮,然后得到微信收款的二维码,再用微信支付扫一下,就像买菜那样。祝好!