如何实现Nginx的防盗链功能?

未分类

1、前言

为了避免博客的图片等资源被盗链而增加网络开销,笔者需要实现防盗链功能。

2、实践部分

2.1 基础环境搭建

请参阅下文搭建http与https的LNMP环境,如果你已经有此环境,请直接跳过。
https://www.cmdschool.org/archives/1

2.2 配置防盗链

2.2.1 创建防盗链规则

mkdir /etc/nginx/global/
vim /etc/nginx/global/anti-theft-chain.conf

加入如下配置:

location ~* .(gif|jpg|png|webp)$ {
    root /var/www/www.cmdschool.org;
    valid_referers none blocked server_names
                                *.cmdschool.org cmdschool.*
                                ~.google. ~.baidu. ~.sogou.;
    if ($invalid_referer) {
        return 403;
        #rewrite ^/ http://www.cmdschool.org/403.jpg;
    }
}

注:留意”root”指令的配置(由于server{}标签没有定义root)

2.2.2 引用防盗链规则

vim /etc/nginx/conf.d/www.cmdschool.org_80.conf

将80端口的http服务配置文件修改如下:

server {
    listen       80;
    server_name  www.cmdschool.org;

    location / {
        root   /var/www/www.cmdschool.org;
        index  index.php;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    #引用防盗链规则
    include global/anti-theft-chain.conf;
}

注:综合之前的配置,配置文件的三个location优先级别请参考下表,

“=”精确匹配
“^~”不做模式匹配
“~”正则表达式的模式匹配
“~*”正则表达式的模式匹配
“” 无符号匹配模式

2.2.3 重载或重启服务

systemctl reload nginx

2.2.4 测试防盗链

2.2.4.1 向服务发送头Referer头模拟从百度引用图片链接

curl -I https://www.cmdschool.org/wp-content/uploads/2017/12/Nginx.png -H 'Referer:http://www.baidu.com'

信息显示如下:

HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Tue, 12 Dec 2017 05:18:40 GMT
Content-Type: image/png
Content-Length: 33308
Last-Modified: Sun, 10 Dec 2017 03:35:31 GMT
Connection: keep-alive
ETag: "5a2cab83-821c"
Accept-Ranges: bytes

2.2.4.2 向服务发送头Referer头模拟从QQ引用图片链接

curl -I https://www.cmdschool.org/wp-content/uploads/2017/12/Nginx.png -H 'Referer:http://www.qq.com'

信息显示如下:

HTTP/1.1 403 Forbidden
Server: nginx/1.12.1
Date: Tue, 12 Dec 2017 05:18:57 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive

Caddy、 SSLDocker、Nginx 性能比较及使用体验

Caddy、 SSLDocker、Nginx 都是可以用来做前端代理的服务,前两者是用go来写,部署比较简单。

Nginx 在部署HTTPS 时比较麻烦(相对其它两者来说),Caddy、 SSLDocker 都是自动配置并且更新HTTPS,这对我这样的懒人来说很有用。个人一直用Nginx (openresty) 1,后来在go 的世界发现了Caddy 4名器,然后在解决多域名反向代理时发现了SSLDocker 10小神器。

以下是在一台128MB单核的VPS 上部署一个应用,然后分别用Caddy、 SSLDocker、Nginx做前端,反向代理到该应用端口, 在另外一台VPS 做并发请求。开启ssl、gzip,使用hey 1 做并发请求:

# ./hey -n=20000 -c=5 https://mydomain.com/

Caddy、 SSLDocker、Nginx 并发测试结果

Caddy 并发请求测试结果

Summary:
  Total:    64.9214 secs
  Slowest:  0.7156 secs
  Fastest:  0.0031 secs
  Average:  0.0161 secs
  Requests/sec: 308.0650

Response time histogram:
  0.003 [1] |
  0.074 [19888] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.146 [2] |
  0.217 [2] |
  0.288 [2] |
  0.359 [90]    |
  0.431 [1] |
  0.502 [11]    |
  0.573 [1] |
  0.644 [1] |
  0.716 [1] |

SSLDocker 并发请求测试结果

Summary: 
  Total:    63.0618 secs 
  Slowest:  0.4883 secs 
  Fastest:  0.0030 secs 
  Average:  0.0156 secs 
  Requests/sec: 317.1490 

Response time histogram: 
  0.003 [1] | 
  0.052 [19865] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 
  0.100 [1] | 
  0.149 [2] | 
  0.197 [1] | 
  0.246 [0] | 
  0.294 [15]    | 
  0.343 [95]    | 
  0.391 [0] | 
  0.440 [2] | 
  0.488 [18]    | 

Nginx (openresty)并发请求测试结果

Summary:
  Total:    57.8501 secs
  Slowest:  0.0523 secs
  Fastest:  0.0029 secs
  Average:  0.0144 secs
  Requests/sec: 345.7212

Response time histogram:
  0.003 [1] |
  0.008 [539]   |∎∎
  0.013 [4327]  |∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.018 [13150] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.023 [1397]  |∎∎∎∎
  0.028 [404]   |∎
  0.033 [120]   |
  0.037 [35]    |
  0.042 [18]    |
  0.047 [4] |
  0.052 [5] |

都很稳定,没有失败请求,从 Requests per second (RPS)看:

Caddy 308 < SSLDocker 317 < Nginx 345

三者相差不大,Nginx 和SSLDocker 稍有优势。

顺便测一下应用裸跑的结果,ssl、gzip 为on,RPS为367

Summary:
  Total:    54.3886 secs
  Slowest:  0.4766 secs
  Fastest:  0.0026 secs
  Average:  0.0136 secs
  Requests/sec: 367.7241

Response time histogram:
  0.003 [1] |
  0.050 [19995] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  0.097 [2] |
  0.145 [0] |
  0.192 [0] |
  0.240 [0] |
  0.287 [1] |
  0.334 [0] |
  0.382 [0] |
  0.429 [0] |
  0.477 [1] |

再测ssl、gzip 为off 情况,具体数据就不贴了,总对比如下:

# 数值为每秒请求数 RPS 
# ssl、gzip on 
Caddy 308 < SSLDocker 317 < Nginx 345 < 裸跑 367
# ssl、gzip off
Nginx 376 < 裸跑 424

拿nginx 反向代理和裸跑对比:

开启ssl、gzip 时性能损失 float(367-345)/367 = 5.99%,
关闭ssl、gzip 时性能损失 float(424-376)/424 = 11.32%。

配置文件

Caddy 配置

mydomain.com {
    gzip
    proxy  / 127.0.0.1:8999
}
mydomain2.com {
    proxy  / 127.0.0.1:8888
}

多个服务

SSLDocker 配置

{
  "Email": "[email protected]",
  "GzipOn": true,
  "Http2https": true,
  "MaxHeader": 10,
  "Certs": "certs",
  "ProxyItems": [
    {"Host": "mydomain.com", "Target": "http://localhost:8999"},
    {"Host": "mydomain2.com", "Target": "http://localhost:8888"}
  ]
}

也是两个服务

Nginx 配置

主配置nginx.conf 使用默认,使用epoll 模式

server {
    listen 443;
    server_name mydomain.com;

    ssl on;
    ssl_certificate /root/ssl/chained.pem;
    ssl_certificate_key /root/ssl/domain.key;

    ssl_session_timeout 5m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_prefer_server_ciphers on;

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/myapp/;
        try_files $uri =404;
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8999;
    }
}

总结

上面的比较是针对个人的使用场景:在一个小VPS 上多挂几个网站而且都使用HTTPS,嫌配置HTTPS 麻烦。以前使用Nginx 则需要注册、配置、验证、添加自动更新任务到Cronjob,如果用Caddy 或SSLDocker,对HTTPS 不用做任何配置,一切都自动完成,其实过程是一样,只是Caddy 和SSLDocker 把这些任务都集成了(go 协程管理真方便)。

Nginx 功能多,成熟稳定;Caddy 功能也在慢慢增多,试着以不同方式实现Nginx 的功能和新鲜的功能;SSLDocker 专注于HTTPS管理和反向代理。如果说Nginx 是成功中年人士,则Caddy 是年轻高富帅,SSLDocker 是嫩屌丝。

相关项目

  • Nginx (Openresty) https://openresty.org/en/

  • Caddy https://caddyserver.com/

  • SSLDocker https://ssldocker.com/

解决Nginx服务返回500状态码问题

最近鼓捣博客服务器,不经意间误操作改了一些目录的用户组及权限,导致博客文件上传功能失败,周末检查了一天依然没有解决问题,在不经意间意识到了问题所在,其实有时候一些小问题会花费一大波时间去解决,于是博主记录本篇,总结一下发现问题,调试,解决问题的过程,希望以后解决问题能直指根本。

发现问题

首先是在12月9号发行博客文件上传功能失败,查看前端请求,发现是服务端返回500状态码,表明发生服务端内部异常:

未分类

如上图接口返回详情所示,nginx服务异常,服务暂时转移了,当前不可访问。

分析并解决问题

其实问题比较简单,但是奈何博主当时短路了,因为博主在浏览器直接访问该异常接口时,出现如下提示:

未分类

于是搜索了关于wordpress关于Are you sure相关问题,结果跑偏了,跑去分析wordpress源码,分析上传文件php代码,分析php内存使用是否达到上限,结果分析完一下午过去了,发现其实nginx没有转发该上传请求至php-fpm服务,我应该首先去看nginx输出日志。

于是跑去查看nginx日志:

vi /var/log/nginx/error.log

哎,发现是空的,并没有异常日志,怎么回事?确认日志路径无误后就可以考虑是因为文件权限的原因了,执行ll或ls -al指令:

未分类

哎,果然,nginx文件目录所属用户是root,而nginx执行用户配置了nginx,于是将其修改成nginx服务配置文件内配置的用户:

chown -R nginx /var/log/nginx
  • -R代表迭代设置目录及其子目录;
  • 第二个参数为为目录指定的所属用户名;

另外设置nginx用户对于/var/log/nginx目录的权限等级:

chmod -R 755 /var/log/nginx

再次执行ll查看目录信息:

未分类

nginx输出日志文件权限没问题了,再次上传文件,发现依然返回500状态码,这时查看nginx异常日志文件:

vi /var/log/nginx/error.log

发现终于有日志了:

未分类

看到是权限问题Permission Denied,打开/var/lib/nginx/tmp/client_body/0000001失败,说明启动转接服务失败,那就需要修改/var/lib/nginx目录的权限,使用ll查看该目录信息,发现,果然所属用户被改为root了,于是再次设置:

chown -R nginx /var/lib/nginx

然后重启nginx服务:

systemctl restart nginx

再次上传文件,上传成功,问题得到圆满解决。

LVS负载均衡+动静分离+高可用(nginx+tomcat+keepalived)

一、环境介绍

基于LVS(linux virtual server)linux虚拟服务器的http集群搭建
环境:使用VMware pro10,CentOS6.5
一共使用4台虚拟机,两台安装Ngnix,两台安装tomcat。
这四台服务器的作用分别是:其中一台nginx作为主服务器,另一台nginx_bk作为备用服务器,然后两台安装tomcat的虚拟机作为调度服务器。
安装并克隆虚拟机后,将四台虚拟机重新命名,分别命名为nginx, nginx_bk,server1,server2:

四台虚拟机的ip地址分别如下:

centOS_nginx 192.168.20.2.135
centOS_nginx_bk 192.168.20.2.139
CentOS_server1 192.168.20.2.134
CentOS+server2 192.168.20.2.137

未分类

二、环境安装

1、安装JDK

四台虚拟机均安装JDK,因安装过程是一样的,所以此处只截图一台虚拟机jdk安装过程。
首先查看jdk版本,centos默认安装openJDK:
未分类
检查可用的JDK版本:
[图片上传失败…(image-2ebecc-1512133579646)]

卸载原来openJDK
未分类
再次查看,已经卸载成功:
未分类
开始安装JDK,到oracle官网下载liunx jdk包,解压到当前目录下
解压好,进入目录查看:
未分类
配置JDK环境变量,修改/etc/profile
未分类
使环境变量生效:
未分类
参看结果:
未分类
此时可以看到jdk已经安装成功
这边liun下jdk的安装有很详细教程,可以去网上搜

2.两台服务器安装tomcat

下载tomcat,解压到/opt目录
解压后查看:
未分类
Root权限进入/bin目录,启动tomcat
未分类
配置防火墙端口:
未分类
未分类
重新加载防火墙配置:
未分类
未分类
启动tomcat访问,首页访问成功:

至此,tomcat安装完成,另一台server虚拟机可克隆该台虚拟机来实现。

3、nginx安装

下载nginx,解压到/usr/local目录下,解压后查看:
未分类
进入解压目录执行./configure命令进行安装
出现错误及解决方法:
错误1:
未分类
原因:缺少gc++
解决:
未分类
错误2:
未分类
解决:
未分类
错误3:
未分类
解决:
未分类
解决上述错误后,再执行安装命令:
未分类
查看nginx进程号:
未分类
启动nginx
未分类
关闭nginx命令是./nginx -s stop
默认端口是80,此时可在网页访问到:
未分类
至此,Nginx安装完成。

4、keepalive安装

Keepalived是一个基于VRRP协议来实现的服务高可用方案,作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器。
Keepalived实现服务的高可用(HA),应用已经非常广泛,很多软件都会和他搭配使,比如LVS,Nginx,Redis等
下载keepalie,解压到/opt/keepalive目录下
安装依赖插件:

yum install -y gcc openssl-devel popt-devel

编译安装:

./configure –prefix=/usr/local/keepalive
Make
Make install

编译之后的配置:
未分类
获得权限:
未分类
修改/etc/init.d/keepalived文件,将默认路径改成当前alive安装路径
未分类
即默认为前一行注释掉的路径,改为下一行,指向了正确的配置文件位置。

配置环境变量
未分类
建立软连接:
未分类
修改/usr/local/keepalive/etc/sysconfig/keepalived文件,修改正确的启动参数
未分类
启动Keepalived
未分类
设置keepalived服务为开机自启动
未分类
至此keepalived安装配置成功,另一两台nginx_bk可以克隆该台虚拟机。


其实在centos下可以直接用yum install keepalived来安装。默认安装路径为/etc/keepalived
用yum来装比较方便

三、负载均衡

现在有两台服务器192.168.204.134和192.168.204.137,服务器上各有一台tomcat,端口均为8080,在192.168.204上有Nginx
修改nginx安装目录中conf目录下的nginx.conf文件
主要配置信息如下:
未分类

补充知识了解:
nginx负载均衡到多台服务器上时,默认采用轮询策略:
常见策略:
1、轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况,数字越大命中率越高。
例如:轮询几率是2:1
upstream bakend {
server 192.168.0.14 weight=2;
server 192.168.0.15 weight=1;
}
2、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
例如:
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}

启动两台tomcat,重新启动nginx,访问192.168.204.135就会随机访问192.168.204.134和192.168.204.137
测试:
在两台tomcat服务器下webapps目录下创建文件夹21751152,新建index.html文件,index.html文件内容分别如下:
Server1下index.html文件:
未分类
Server2下index.html文件:
未分类
首先测试在两台tomcat服务器下本地能访问这两个页面:
Server1下:
未分类
Server2下:
未分类
可以看到两台服务下均可正常访问
然后在安装Nginx服务器下测试:
未分类
未分类
可以看到,在nginx服务器下,在网页中每次刷新都会随机访问到两台Tomcat服务器中的任意一台,可以看出,已经完成了负载均衡的效果。

四、动静分离

为了提高网站的响应速度,减轻程序服务器(tomcat)的负载,对于js,css,图片等静态文件可以在nginx反向代理服务器中进行缓存,这样浏览器在请求一个静态资源的时候,代理服务器就可以直接处理,而不用将请求转发给后端服务器。而用户请求的动态文件比如jsp则会转发给tomcat服务器处理,这就是动静分离,也是反向服务器的一个重要作用。
在server1这台服务器webapp/21751152目录下建index.jsp文件:
Index.jsp内容如下:
未分类
然后进行Nginx.conf配置文件的修改:
主要修改内容如下:
未分类
Root /usr/local/webapps 这段代码的意思是指定Nginx访问的目录,即静态资源所在的目录。

Expires 30d.指这些资源文件在客户端浏览器的缓存时间,30d值30天,1h指一小时
开始测试:
首先在server1本地进行测试,页面可以正常访问:
未分类
然后在nginx服务器下进行测试:
未分类
可以看到,向日葵这张图片作为静态文件,没被加载出来。这是因为静态资源访问请求已经被Nginx拦截,由Nginx进行处理。但是Nginx服务器的 /usr/local/webapps 目录下并没有图片资源,所以图片没有加载出来。index.jsp页面能够显示,说明动态的请求已经转发到了Tomcat,Tomcat对index.jsp进行了解析。
在Nginx服务器 /usr/local/webapps 目录下放置图片文件,将tomcat上把21751152/img/flower.jpg整个目录拷贝到其中。然后再次刷新。
未分类
未分类
此时,图片就被加载出来了。至此,可以看出已经Nginx已经实现了动静分离的功能。
在配置动静分离后,用户请求你定义的静态资源,默认会去nginx的发布目录请求,而不会到后端请求,这样可以提高网站响应速度,减轻真实Web服务器的负载压力。
不过在开发环境下,为了便于开发,咱们的静态资源和代码还是放在一起的,等开发测试完成,才会将完成的完整程序部署到生成环境上,然而程序代码和静态资源是分别放置到不同的服务器上的。

五、keepalive高可用

编辑ngin服务器的keepalived.conf文件,keepalived.conf文件如下图所示:
未分类
未分类
画出红线部分是主要需要注意的地方
备份的nginx_bk配置文件与此类似
需要注意的以下几个点:
需要修改state为BACKUP , priority比MASTER低,virtual_router_id和master的值一致
配置文件如下:
未分类
未分类
注:在主备机中vip应设置一致

1、遇到的问题1及解决过程

用keepalived方式在主nginx服务器中添加了虚拟Ip,但是用ip addr查看发现仍然只有一个IP地址,即keepaLived.cof文件里面配置的vip没有起到效果
未分类
解决问题过程:
(1)尝试一:
可能是keepalived没有安装成功,所以采用yum重新安装keepalived
但是重装后还是发现VIP没有生效。
(2)最终解决:
后来在同学的提醒下,发现是自己的keepalived服务没有启动好,nginx服务也需要重启。这两个服务启动好后,就可以了。
开始测试:
在两台nginx和nginx_bk服务器中keepalived服务和nginx服务都开启的情况下:
首先测试nginx的IP:
未分类
可以看到在Nginx中已经有虚拟ip了
而在Nginx_bk服务器中:
未分类
可以看到没有绑定虚拟ip
访问192.168.204.177
未分类
未分类
这是访问虚拟ip地址,发现也被转发到了Nginx主机192.168.204.135指向的tomcat服务器上,同时也是随机分配到了两天Tomcat服务器上,即实现了负载均衡。

2、遇到的问题2及解决过程

Nginx主从机器没有顺利切换
在模仿Nginx主机宕机过程中:
用service keepalived stop 命令将Nginx主机服务的keepalived服务停止。
未分类
可以看到虚拟ip就没有绑在主机上
此时再去查看nginx_bk服务器,按道理来说此时Nginx_bk这台机器上应该会绑定vip,但实际查看的时候,发现并没有绑定过来
解决过程:
(1) 尝试1
因为nginx_bk这台服务器是我克隆nginx主机这台虚拟机得到的,所以存在mac地址冲突问题,猜想可能是这个原因导致的无法主从切换。
所以我对nginx_bk这台虚拟机重新生成了mac地址
过程如下:
首先关闭该虚拟机
然后选中该虚拟机点击“设置”,选择“网络适配器”,“高级”
未分类
然后点击“生成”
未分类
这样就重新生成了一个MAC地址。
然后对该虚拟重启后,重新启动keepalived,nginx等服务,发现还是无法正常切换
(2) 尝试2
因为我的几台虚拟机都没有设置静态IP,在同学的建议下,可能是没有设置静态IP导致的问题,所以我对nginx和nginx_bk这两台服务器都设置了静态ip,
设置过程如下:
Nginx主机:
未分类
未分类
对Nginx_bk服务器静态地址设置与此类似

如上设置了静态IP后,问题还是没有得到解决。
但是在多次尝试中,意外发现,当把nginx_bk这台虚拟机的nginx服务关闭后,两台虚拟机之间的主从关系是能够体现的
即当nginx主机中keepalive和nginx服务都正常开启的情况下,nginx主机下绑定了192.168.204.177这个Vip
未分类
当nginx_bk主机中keepaliv服务正常开启的情况下,而nginx服务停止的情况下,该虚拟机是没有绑定虚拟ip的
未分类
然后将nginx主机的keepalived服务停止时:
未分类
如上两张图所示:
主机下绑定的vip已经漂移到了nginx_bk这台主机上
然后此时把nginx_bk这台主机上的nginx服务启动,发现在浏览器上访问vip地址时也顺利转发到了两台tomcat服务器上。
未分类
这时再把nginx主机上的keepalive重新启动,同时关闭nginx_bk主机上的nginx服务
未分类
此时nginx主机上又重新绑定了vip,同时网页也恢复了访问。
再去查看nginx_bk主机情况:
未分类
Nginx_bk上仍然定着vip,当把nginx主机重启后,在该虚拟机上通过vip也能访问到两台tomcat上的内容。
未分类
所以在这种情况下相当于两台nginx都同时被作为了访问入口。
最终我没有把该问题很好的解决掉,猜测的原因可能与Nginx有关。可能会在后期继续研究这个问题

参考博客:
http://www.cnblogs.com/mrlinfeng/p/6146866.html
http://blog.csdn.net/u010028869/article/details/50612571
上述的实现过程我主要参照了这两篇博客,感谢他们的无私分享。

微服务架构日志集中化 安装 EFK (Fluentd ElasticSearch Kibana) 采集nginx日志

本文描述如何通过FEK组合集中化nginx的访问日志。本人更喜欢按顺序来命名,所以使用FEK而不是EFK.

首先在nginx服务器上执行以下操作.

安装ruby

http://blog.csdn.net/chenhaifeng2016/article/details/78678680

安装Fluentd

curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh
systemctl start td-agent

安装插件

td-agent-gem install fluent-plugin-elasticsearch
td-agent-gem install fluent-plugin-typecast

安装ElasticSearch

下载软件包并解压

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.0.0.tar.gz

创建组和用户

groupadd elsearch
useradd elsearch -g elsearch -p elsearch
chown -R elsearch:elsearch /usr/local/src/elsearch

编辑/etc/sysctl.conf

vm.max_map_count=655360

查看一下是否生效

sysctl -p

编辑/etc/security/limits.conf,在文件尾添加以下内容

elsearch soft nofile 65536
elsearch hard nofile 65536

编辑config/elasticsearch.yml,修改以下配置项

network.host: 0.0.0.0

切换到用户elsearch

su elsearch

运行elasticsearch

bin/elasticsearch

如果要以守护进程方式运行加上参数-d

未分类

安装Kibana

下载并解压缩文件。

wget https://artifacts.elastic.co/downloads/kibana/kibana-6.0.0-linux-x86_64.tar.gz

修改配置文件configkibana.yaml

server.port: 5601
server.host: "0.0.0.0"
elasticsearch.url: "http://localhost:9200"

运行kibana

bin/kibana

安装Logstash (这一步非必须)

下载并解压缩文件

wget https://artifacts.elastic.co/downloads/logstash/logstash-6.0.0.tar.gz

创建配置文件logstash.conf

<img src="http://devops.webres.wang/wp-content/uploads/2017/12/2-16.png" alt="" width="340" height="258" class="alignnone size-full wp-image-16270" />

运行./logstash -f logstash.conf

输入hello the world

未分类

在kibana创建索引模式

未分类

在kibana的Discover界面就可以看到信息了

未分类

接下来配置fluentd

编辑配置文件/etc/td-agent/td-agent.conf

[plain] view plain copy
<source>  
  @type tail  
  path /usr/local/nginx/logs/access.log  
  pos_file /usr/local/nginx/logs/access.log.pos  

  tag nginx.access  
  format /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) 
(?<time>[^
]*)] "(?<method>S+)(?: +(?<path>[^ ]*) +S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^"]*)" "(?<agent>[^"]*)")?$/  
  time_format %d/%b/%Y:%H:%M:%S %z  
</source>  
<match nginx.access>  
  @type elasticsearch  
  host localhost  
  port 9200  
#  index_name fluentd  
  flush_interval 10s  
  logstash_format true  
#  typename fluentd  
</match>  

在/usr/local/nginx/logs/下面创建access.log.pos文件

touch access.log.pos

chmod a+rw access.log.pos

重启fluentd

systemctl restart fluentd

修改nginx.conf, 更改日志格式

[plain] view plain copy
log_format  main  '$remote_addr $http_host [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';  

重启nginx

nginx -s reload

通过浏览器访问nginx

查看fluentd的日志

tail -f /var/log/td-agent/td-agent.log

说明fluent读取nginx的access.log成功并发给了elasticsearch.

在kibana查看日志

未分类

参考资料

正则表达式:http://fluentular.herokuapp.com/
http://blog.csdn.net/qq_27252133/article/details/53520416

补充说明:

采集端可以使用logstash, filebeat, 也可以使用fluentbit。因为fluent是CNCF的项目,所以只是为了了解一下。

修改Nginx与Apache上传文件大小限制

修改 Nginx 上传文件最大值限制

我们使用 ngnix 做 web server 的时候,nginx 对上传文件的大小有限制。

这个时候我们要修改 nginx 参数。

sudo vim /etc/nginx/nginx.conf 
#在http段里面添加:
client_max_body_size 100m;  //举例设置上传最大值为100m

然后重启nginx

systemctl restart nginx

修改 Apache 上传文件最大值限制

打开 php.ini, 找到下面的项并修改之。下面以上传100M为例。

sudo vim /etc/php.ini
file_uploads = on ;是否允许通过HTTP上传文件的开关。默认为ON即是开 
upload_tmp_dir ;文件上传至服务器上存储临时文件的地方,如果没指定就会用系统默认的临时文件夹 
upload_max_filesize = 100m ;望文生意,即允许上传文件大小的最大值。默认为2M 
post_max_size = 100M ;指通过表单POST给PHP的所能接收的最大值,包括表单里的所有值。默认为8M

一般地,设置好上述四个参数后,上传<=8M的文件是不成问题,在网络正常的情况下。

但如果要上传>8M的大体积文件,只设置上述四项还一定能行的通。除非你的网络真有100M/S的上传高速,否则你还得关心关心下面的参数:

max_execution_time = 600 ;每个PHP页面运行的最大时间值(秒),默认30秒 
max_input_time = 600 ;每个PHP页面接收数据所需的最大时间,默认60秒 
memory_limit = 128M ;每个PHP页面所吃掉的最大内存,默认8M

全部设置好之后,重启

systemctl restart httpd

配置搭建阿里云服务器nginx+uwsgi (python)

关于使用nginx+uwsgi搭建web服务器,网上有很多教程,但是对新手来说都有些不好理解。下面我总结了一下,纯基础、好使。

首先理解一些基本概念:

WSGI是什么?

WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。

WSGI 的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。

uWSGI是什么?

uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

nginx、uwsgi、flask之间的关系

  • 首先nginx 是对外的服务接口,外部浏览器通过url访问nginx

  • nginx 接收到浏览器发送过来的http请求,将包进行解析,分析url,如果是静态文件请求就直接访问用户给nginx配置的静态文件目录,直接返回用户请求的静态文件。如果是动态那么nginx就将请求转发给uwsgi,通过flask框架转换为某一函数或者方法进行调用,并处理后,返回给uwsgi。uwsgi转发给nginx,nginx最终将返回结果返回给浏览器。

  • 由此可见nginx并不是必须的,uwsgi完全可以完成整个的和浏览器交互的流程。但是要考虑到某些情况。

  • 安全问题程序不能直接被浏览器访问到,而是通过nginx,nginx只开放某个接口,uwsgi本身是内网接口,这样运维人员在nginx上加上安全性的限制,可以达到保护程序的作用。

  • 负载均衡问题一个uwsgi很可能不够用,即使开了多个work也是不行,毕竟一台机器的cpu和内存都是有限的,有了nginx做代理,一个nginx可以代理多台uwsgi完成uwsgi的负载均衡。

  • 静态文件问题用django或是uwsgi这种东西来负责静态文件的处理是很浪费的行为,而且他们本身对文件的处理也不如nginx好,所以整个静态文件的处理都直接由nginx完成,静态文件的访问完全不去经过uwsgi以及其后面的东西。

好的接下来直接进入搭建过程。 首先你得有一台服务器。这个是我自己的阿里云esc服务器。然后通过ssh root@云服务器ip地址,然后输入密码进行登录。

安装 Python 环境

不多说,一般系统都自带python环境以及pip

安装Nginx

pip install nginx

或者

yum install nginx

安装VirtualEnv

不同的项目可能会引用各种不同的依赖包,为了避免版本与和应用之间的冲突而造成的“依赖地狱”。VirtualEnv 可以为每个Python应用创建独立的开发环境,使他们互不影响。

pip install virtualenv

安装VirtualEnv 后只需要在项目目录内运行 virtualenv 目录名 就可以建立一个虚拟环境文件夹。 假定我的项目目录叫 /home/www/myproj进入该目录后运行

virtualenv venv

项目目录下得到新的venv目录即虚拟环境 (虚拟环境目录可以叫venv,自己随意)

输入

source venv/bin/activate 

进入虚拟环境,前面多了虚拟目录名(venv)

安装 uWSGI

pip install uwsgi

安装 Flask

pip install flask

项目文件

假设到现在为止项目里面只有一个最简单的文件 hello.py,里面内容如下:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

配置uwsgi

同志们,项目的准备工作准备的差不多了。接下来就是一些配置问题(哎,以前碰到的坑巨多)。

好,在项目目录下新建一个uwsgi.ini

touch uwsgi.ini

创建好了以后,用vim在uwsgi.ini写入以下内容:

[uwsgi]
master = true
home=/home/www/myproj/venv
wsgi-file = hello.py
callable = app
socket=127.0.0.1:5000
stats=127.0.0.1:9191
processes = 4
threads = 4
buffer-size=32768

运行uwsgi试试,如果输出类似以下信息,说明成功。

uwsgi --ini uwsgi.ini
(venv)my_flask root$ uwsgi uwsgi.ini

[uWSGI] getting INI configuration from uwsgi.ini

*** Starting uWSGI 2.0.8 (64bit) on [Tur Sep 19 14:34:11 2017] 
// 此处略去那些无用的启动信息
Stats server enabled on 127.0.0.1:9191 fd: 15 ***

ok,uwsgi已经配置完成,ctrl+c 关闭程序。

配置Nginx

找到配置文件nginx.conf(我的在目录/etc/nginx/nginx.conf),修改以下部分

server {
        charset      utf-8;
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  xxxx域名地址
        root         /home/www/myproj;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
           include      uwsgi_params;
           uwsgi_pass   127.0.0.1:5000;
           uwsgi_param UWSGI_PYHOME /home/www/myproj/venv;
           uwsgi_param UWSGI_CHDIR  /home/www/myproj;
        }
    }

启动Nginx服务器、启动uwsgi服务器

这个地方要注意,我在这卡了我1天。因为有俩个服务器,所以俩个都要启动。

service nginx restart

uwsgi --ini uwsgi.ini

大功告成

nginx+uwsgi+django部署python项目

初次部署nginx+uwsgi+django真是经历了千难万险,因此在这里整理分享一下,希望在这条路上行走的你有所帮助。

我使用的系统是fedora27,已经安装了python3和pip3,这两个没有安装的各位先自行安装。

Nginx

  • 安装
dnf install nginx
  • 配置
location / {
    uwsgi_pass  127.0.0.1:9090;
    include     uwsgi_params; # the uwsgi_params file you installed
}

nginx的配置只需要改这些

Django

  • 安装
dnf install setuptools
pip3 install django
pip3 install PyMySQL
pip3 install mysqlclient
#安装mysqlclient可能会遇到以下下问题,
dnf install mysql-devel # 解决 OSError: mysql_config not found
dnf install gcc # 解决 unable to execute 'gcc': No such file or directory
dnf install redhat-rpm-config # 解决gcc: 错误:/usr/lib/rpm/redhat/redhat-hardened-cc1:No such file or directory
#python-devel for python2.x
#python3-devel for python3.x
dnf install python3-devel 解决 致命错误:Python.h:No such file or directory
  • 启动
#在你的项目目录下
[jeffery@localhost pythontest]$ python3 manage.py runserver 0.0.0.0:8000
Performing system checks...

System check identified no issues (0 silenced).
November 30, 2017 - 08:11:58
Django version 1.11.7, using settings 'pythontest.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

这样django就启动成功了,可以在浏览器中用8000端口访问一下项目

uwsgi

  • 安装
pip3 install uwsgi
  • django_socket.ini配置
[uwsgi]
socket = 127.0.0.1:9090
chdir = /projects/pythontest
module = pythontest.wsgi
processes = 2
pidfile = uwsgi.pid
daemonize = /var/log/uwsgi/uwsgi9090.log

chdir——你的项目根目录
module——入口文件,即wsgi.py相对于项目根目录的位置,“.”相当于一层目录。如果是用django创建的项目,wsgi.py这个文件是自动生成的,自己找一下。
daemonize——作为后台进程执行,日志输出的地方,目录没有的自己创建下

  • wsgi.py
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pythontest.settings")

application = get_wsgi_application()
  • 启动
uwsgi --ini django_socket.ini

启动完我们就可以去上面daemonize 配置的日志中看看是否启动成功
Nginx中配置的地址端口要和django_socket.ini中保持一致
接下来用浏览器访问下Nginx,有人应该已经能够成功看到自己的python项目了

不行的请继续往下看

VirtualEnv

VirtualEnv的作用:创建隔离的Python环境,解决模块或库的版本冲突或依赖。(我的系统中既有python2.7又有python3.6)

  • 安装
pip3 install virtualenv
  • 创建虚拟环境
virtualenv mytest

mytest是我这边起的名字,可以随便起
创建不了的看下自己当前用户权限够不够, 不是root用户就到 /home目录下找你现在登录的角色的目录,然后进入用户目录下再执行上面的安装命令,执行完以后用ls看下有没有mytest这个文件夹,进入mytest的bin中

[jeffery@localhost /]$ cd /home/jeffery/mytest/bin/
[jeffery@localhost bin]$ ls
activate          django-admin      pip          python         wheel
activate.csh      django-admin.py   pip3         python3
activate.fish     easy_install      pip3.6       python3.6
activate_this.py  easy_install-3.6  __pycache__  python-config
  • 激活mytest虚拟环境
[jeffery@localhost bin]$ source ./activate
(mytest) [jeffery@localhost bin]$ 

此时我们看到命令行前面加上了(mytest),这代表我们在mytest的虚拟环境中,这个时候按照上面django的安装配置重新配置一次,最后在这个虚拟环境中启动django。(我们上面启动的可以不要了,虚拟环境中启动就可以了)

  • 修改django_socket.ini
[uwsgi]
socket = 127.0.0.1:9090
chdir = /projects/pythontest
module = pythontest.wsgi
processes = 2
pidfile = uwsgi.pid
daemonize = /var/log/uwsgi/uwsgi9090.log
home = /home/jeffery/mytest

这里面我们加上了最后一行,也就是配置home——虚拟环境mytest的根目录。

重新启动uwsgi,用浏览器访问Nginx,成功访问python项目。

在阿里云上通过Ubuntu+uwsgi+nginx+mysql部署Flask(新手向)

0. 前言

这其实也是你所看到的这个网站的部署方式。

老规矩,上环境。截至2017年11月:

Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-62-generic x86_64)

uwsgi –version 2.0.15

nginx version: nginx/1.10.3 (Ubuntu)

supervisord -v 3.2.0

而我的个人电脑是

4.13.12-1-ARCH x86_64 GNU/Linux

1. 创建Ubuntu并创建新用户

在阿里云购买好ECS,我选择的最便宜的1核那个,一年300多,买完之后在控制台可以选择系统,选择好后输入root用户的密码。

未分类

随后会告诉你一个网页上可以连接到服务器的密码,你得记住。随后在网页上登录到服务器。键入

adduser edison

创建一个新用户,当然了用户名你自己取,这里是我的名字。

随后在我的电脑上用ssh连接服务器,这样方便操作些,此处怎么ssh连接服务器就不说了,百度谷歌一大把。

此处先用

ssh root@ip 

来连接。会提示加入密钥回车就好,然后输入你root也就是刚开始创建云盘时的那个密码。就连接成功了。

输入

nano /etc/sudoers

为新创建的用户加入sudo权限:

未分类

输入

apt-get update

更新索引,这里如果比较慢的话可以替换成中科大的源,如何替换百度谷歌就好也很简单。随后开始安装必要的软件。

2.安装python3和git

先安装python3

apt install python3-pip

随后使用pip3安装虚拟环境模块

pip3 install virtualenv

此时可以切换至edison这个新用户。

ssh edison@ip

我是把网站放在了github上,之后更新程序也方便管理。所以这里安装git

未分类

这里发现提示了

sudo: unable to resolve host:xxx

的信息,不影响使用的。可以通过修改hosts文件解决

未分类

未分类

输入y然后回车继续安装git。

在/home/edison下新建目录blog,在blog下git clone把源代码拷下来。

创建虚拟环境:

未分类

注意这里的虚拟环境使用的python3版本。

可以通过启动虚拟环境查看,确实是py3:

未分类

在blog下再新建一个logs文件夹。此时blog应该有三个文件夹,其他两个一个是venv文件夹一个是你的程序的文件夹。

未分类

3. 安装nginx

输入

sudo apt-get install nginx

安装nginx。输入

sudo /etc/init.d/nginx start

启动服务,shell会显示ok提示启动nginx服务成功。这时候打开浏览器,直接输入你的ECS服务器的公网ip就可以看到

未分类

就说明nginx启动成功。接下来用一个小的flask程序进行小小的演示。

创建一个test.py:

未分类

然后在虚拟环境下(根据前文,这时候已经在虚拟环境中了,可以从下图的shell里第一行的前面的venv字眼看出)

pip3 install flask

安装flask模块。

4. 安装uwsgi和supervisor并配置

接下来安装

pip install uwsgi

未分类

然后(此时所在文件夹是blog里)新建一个uwsgi的配置文件,并编辑以下内容,然后启用uwsgi:

未分类

未分类

未分类

可以看到uwsgi已经在运行了。这时候ctrl+c退出uwsgi。

接下来安装supervisor后进入配置文件夹,新建一个文件并输入:

sudo apt-get install supervisor
cd /etc/supervisor/conf.d
sudo nano blogSupervisor.conf

未分类

然后输入

sudo service supervisor start

开启进程管理。

5. 配置nginx

进入/etc/nginx/sites-available/,编辑里面default文件,其中内容是:

未分类

然后输入

sudo service nginx restart

重启nginx服务器。打开浏览器输入你的公网ip,就能看到

Hello World! 啦

未分类

这里部署就基本完了,只要把上述的配置文件里提到test这个py文件替换成你的文件,例如manage.py就好了。

6. Mysql和后续

接下来简单说说怎么使用mysql:

安装pymysql,在config.py里使用

“mysql+pymysql://root:xxx@localhost:3306/xxxxx”

的方式启用mysql。

p.s

在使用mysql上尝试了很多方法,但是由于ubuntu的系统python是2,而虚拟环境中python为3,所有总有一些包安装不上,特别是mysqldb的问题,只能使用mysql+pymysql的方法。但是很奇怪的现象是,我的archlinux默认的python是3.6,使用的mariadb,但是不用pymysql也能连接上mysql,而且:

$ python                                                           
Python 3.6.3 (default, Oct 24 2017, 14:48:20) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
>>> 

百思不得其解,如果有缘人看到了这里希望能给出答复。

CentOS 7 Nginx配置Let’s Encrypt SSL证书

去年购买的阿里云到期了,由于阿里云续费比新买贵很多,所以重现买了一台虚拟机,迁移过程中需要重新配置Let’s Encrypt证书,在执行过程中发现了一些问题,经过几个小时的摸索,终于搞定。

安装Let’s Encrypt证书一般的流程

yum install epel-release -y
yum install certbot -y

然后执行:

certbot certonly --webroot -w /home/www/www.biaodianfu.com -d www.biaodianfu.com -m [email protected] --agree-tos

相关参数含义:

  • –webroot是运行模式
    1.standalone模式:需要停止当前的 web server 服务,让出 80 端口,由客户端内置的 web server 启动与Let’ s Encrypt通信。
    2.webroot模式:不需要停止当前 web server,但需要在域名根目录下创建一个临时目录,并要保证外网通过域名可以访问这个目录。
  • -w 指定网站所在目录
  • -d 指定网站域名
  • -m 指定联系邮箱,填写真实有效的,letsencrypt会在证书在过期以前发送预告的通知邮件
  • –agree-tos 表示接受相关协议
    使用webroot模式,Certbot在验证服务器域名的时候,会生成一个随机文件,然后Certbot的服务器会通过HTTP访问你的这个文件,因此要确保你的 Nginx 配置好,以便可以访问到这个文件。
    因为默认LNMP的虚拟主机里是禁止 . 开头的隐藏文件及目录的,所以访问http://www.biaodianfu.com/.well-known/acme-challenge/**** 这个链接的话返回403错误,所以必须在nginx配置的server节点下添加
location ~ /.well-known {
    allow all;
}

最终的配置文件如下:

server {
    listen       80;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;

    root   /home/www/www.biaodianfu.com;

    location / {
        try_files $uri $uri/ =404;
    }
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }

    location ~ .*.(js|css)$
    {
        expires      12h;
    }

    location ~ /.well-known {
        allow all;
    }
}

重新nginx后执行申请证书的操作,正常情况下可以看到如下的显示内容:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem. Your cert will
   expire on 2018-02-25. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you lose your account credentials, you can recover through
   e-mails sent to [email protected].
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - 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

完成后,再配置nginx服务器,将服务器配置成支持https的访问。

server {
  listen 80;
  server_name biaodianfu.com www.biaodianfu.com;
  return 301 https://www.biaodianfu.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;

    root   /home/www/www.biaodianfu.com;

    ssl_certificate /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.biaodianfu.com/privkey.pem;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }

    location ~ .*.(js|css)$
    {
        expires      12h;
    }

    location = /favicon.ico {
    log_not_found off;
    access_log off;
    }

    location ~ /.well-known {
        allow all;
    }
}

以上为一般的步骤与过程,现在在执行centos 7.2时并没有遇到什么问题,这次使用的是centos 7.4却发生了问题。

解决证书安装中的问题

问题一:ImportError: No module named ‘requests.packages.urllib3’
原因是系统自带的requests的版本太低,参照这个地址上的临时解决方案:

pip install requests urllib3 pyOpenSSL --force --upgrade

执行完引发第二个问题:ImportError: ‘pyOpenSSL’ module missing required functionality. Try upgrading to v0.14 or newer.
主要原因是RHEL/CentOS的官方源和epel源的pyOpenSSL版本太旧了,新版的certbot依赖于高版本的pyOpenSSL库,从而失败。
解决方案,卸载epel中的certbot和PyOpenSSL,使用pip进行安装certbot。

pip search certbot
yum remove certbot pyOpenSSL
pip install certbot

pip install certbot。 如果碰到了Python.h或者pyconfig.h找不到的错误,可以安装Python的devel包: yum install -y python-devel;再次运行命令,提示找不到opensslv.h头文件,再安装OpenSSL的devel包: yum install -y openssl-devel;再次运行pip install certbot命令,成功安装certbot。
完成后执行 certbot certificates 进行验证。输出正常,说明pip安装了最新版的certbot,并且能正确运行。

证书的自动更新

由于这个证书的时效只有 90 天,我们需要设置自动更新的功能,帮我们自动更新证书的时效。首先先在命令行模拟证书更新:

certbot renew --dry-run

模拟更新成功的效果如下:

[root@iZuf64dhkm7u57qfwrrhw6Z ~]# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/www.biaodianfu.com.conf
-------------------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for www.biaodianfu.com
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
** 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/www.biaodianfu.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
-------------------------------------------------------------------------------

IMPORTANT NOTES:
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
[root@iZuf64dhkm7u57qfwrrhw6Z ~]#

在无法确认你的 nginx 配置是否正确时,一定要运行模拟更新命令,确保certbot和服务器通讯正常。使用 crontab -e 的命令来启用自动任务,命令行:

crontab -e

添加配置:(每隔两个月凌晨2:30自动执行证书更新操作)后保存退出。

30 2 * */2 * /usr/bin/certbot renew --quiet && /bin/systemctl restart nginx

查看证书有效期的命令:

openssl x509 -noout -dates -in /etc/letsencrypt/live/www.biaodianfu.com/cert.pem

测试服务器 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。理想情况下得分是A+,如果你和我一样获得的是A-那么还有很多的改善空间。另外又扑云也有一个测试https的工具:https://www.upyun.com/https
相关改进:

1、生成Perfect Forward Security(PFS)键值

mkdir /etc/ssl/private/ -p
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem

Perfect Forward Security(PFS),中文翻译成完美前向保密,2014年时候,由于心血漏洞(存在服务器私钥泄漏的可能),没有使用前向保密的站点,加密通信的数据可以通过私钥来解密,导致信息泄漏,这使得前向保密被重视起来。总的来说会更加安全,不能获得A+的评分主要原因也是因为它。(生成的时间有点长)

2、更新配置文件

# https://mozilla.github.io/server-side-tls/ssl-config-generator/
server {
    listen 80;
    server_name biaodianfu.com www.biaodianfu.com;
    return 301 https://www.biaodianfu.com$request_uri;
}
server {
    listen 443 ssl http2;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;

    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    root   /home/www/www.biaodianfu.com;

    ssl_certificate /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.biaodianfu.com/privkey.pem;

    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/ssl/private/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # 一般推荐使用的ssl_ciphers值: https://wiki.mozilla.org/Security/Server_Side_TLS
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }

    location ~ .*.(js|css)$
    {
        expires      12h;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location ~ /.well-known {
        allow all;
    }
}

其他参考:

  • https://certbot.eff.org/#centosrhel7-nginx
  • https://ruby-china.org/topics/31942
  • https://security.stackexchange.com/questions/54639/recommended-ssl-ciphers-for-security-compatibility-perfect-forward-secrecy