格物躬行博客开启全站 HTTPS ( SSL ) & 解决外链(跨域资源) HTTP 问题

HTTPS 的好处与坏处就无庸赘述了,但对于本博客来说,重要的是开启 HTTPS 后,能一定程度抵御中国互联网防火长城的封锁拦截。其实,格物躬行博客在2016年底发现被中国网络防火墙给封锁拦截后就开启了 HTTPS ,但博客里引用的一些外部资源或者链接,因它们未开启使用HTTPS,所以导致浏览器会提示“连接不安全”或“安全警告:此网页包含的内容······”。经过探索,发现可以用重定向跳转的方式解决外链(跨域资源)为HTTP 影响全站 HTTPS 的麻烦。

利用Nginx解决HTTPS引用跨域外链HTTP

利用Nginx解决HTTPS引用跨域外链HTTP

要想解决外链(跨域资源) HTTP 影响全站 HTTPS 的问题,有一个前提条件:自主可控的开启了 HTTPS 链接的域名。本博客为了达到目的,开启了一个新二级域名,即 link.go2do.net 专门用于外部资源和链接的跳转,开启新的二级域名也比较简单,就是在 DNS 服务商/域名管理商网站,增加一条新的解析记录即可,下面重点说说为 link.go2do.net 开启 HTTPS 和 外链重定向的配置。

1.开启 HTTPS

个人小站一般使用的是 Let`s encrypt 免费的 https 证书,本博客也不能免俗,咳咳···安装及配置步骤如下。

  1. # centos6.9(Final) , 内核 2.6.32-042stable
  2. #基于Nginx,编译时指定 –with-http_ssl_module 和 ngx_http_proxy_module,安装了openssl和openssl-devel和libssl-dev
  3. #下载自动安装配置脚本、赋予权限及运行脚本。注:本站该脚本放在 /etc/letsencrypt/ 目录中
  4.  
  5. wget https://dl.eff.org/certbot-auto   # 或者用 yum install certbot 取代左侧三行命令
  6. chmod a+x certbot-auto
  7. ./certbot-auto
  8.  
  9. #如果 Python 版本在2.7以下,会有 “DeprecationWarning” 警告信息
  10. #如果 没有使用 apachectl ,会有 “Failed to find···”  提示信息
  11. #对于已上警示信息,可以忽略不管(包括后续操作中的),继续操作即可,无非是需要手动配置而已
  12.  
  13. ./certbot-auto certonly  #或者 certbot certonly --webroot -w /var/www/example  -d www.example.com 取代下面后续命令
  14.  
  15. #会出现2个选项,一个是standalone,另一个是webroot 我们选择webroot服务,但是有些时候一些服务并没有根目录,
  16. #例如一些微服务,这时候使用 webroot 就走不行。通过 standalone 模式,这种模式不需要指定网站根目录,
  17. #它会自动启用服务器的 80 或 443 端口,来验证域名的归属,验证域名的时候,需关闭的端口占用的原有程序,如nginx先stop。
  18. # yum方式安装使用standalone 模式: certbot certonly --standalone -d www.example.com
  19.  
  20. #它会要求我们输入email(可以不输入),那我们输入email————————这个没看见,在certbot-auto 0.19.0版
  21.  
  22. #会提示:Please enter in your domain name(s)... 就是输入我们要注册证书的域名了,比如:link.go2do.net
  23.  
  24. #然后会提示:Press 1 [enter] to confirm ...  就是确认所选了,输入:1 , 然后按下回车
  25.  
  26. #再然后提示:Input the webroot... 输入域名所绑定的文件路径,如 /home/wwwroot/link.go2do.net 或者 /data/wwwroot/link.go2do.net 
  27. #要保证该文件路径为www权限,且要正确配置了 Nginx (可以放置index.html 进行测试),因为要生成.well-known验证域名所有权。
  28. #可以多域名共用一个证书,即在输入域名时可输入多个域名(用空格分隔),但只输入一个域名所绑定的文件路径
  29.  
  30. #返回如下代码,表示获得SSL 证书成功: 
  31.    IMPORTANT NOTES: 
  32.    Congratulations! Your certificate and chain have been saved at.........(注意看,at 后面是证书存放路径)
  33.  
  34. #证书的生成之后,会在"/etc/letsencrypt/live/link.go2do.net/"域名目录下有4个文件就是生成的密钥证书文件。
  35. # cert.pem  - Apache服务器端证书; chain.pem  - Apache根证书和中继证书
  36. # fullchain.pem  - Nginx所需要ssl_certificate文件; privkey.pem - 安全证书KEY文件

注1:如果没有看到“Congratulations!”就是不成功了,而且提示“… the DNS A/AAAA recode(s)…”就是域名解析服务器的问题了,尤其是使用DNSpod它们家DNS服务器的小伙伴,可以临时替换一下,如使用Godaddy的。

注2:某些虚拟主机Nginx里是禁止访问 . 开头的隐藏文件及目录的,所以访问http://link.go2do.net/.well-known/acme-challenge/**** 这个链接的话返回403错误,所以必须要将对应虚拟主机配置文件里的

location ~ /\.{
       deny all;
    }
# 用#注释/删掉上面这段配置 或者 在这段配置前面加上如下配置
location ~ /.well-known {
      allow all;
    }
# 配置好 Nginx 配置文件,重载(sudo nginx -s reload)使修改生效

注3:测试及证书到期(有效期只有 90 天)的自动更新配置

  1. #测试一下更新,这一步没有在真的更新,注意执行目录,我的在/etc/letsencrypt/下
  2. #如果出现有 Congratulations 的表示测试成功
  3. ./certbot-auto renew --dry-run
  4.  
  5. #手动强制更新更新的方法
  6. ./certbot-auto renew 
  7.  
  8. #使用crontab进行自动续期(每隔 两个月的 凌晨 2:15 执行 更新操作)
  9. #前面如果选择的是 standalone 模式,用下面的方式续签证书
  10. 15 2 * */2 * /etc/letsencrypt/certbot-auto renew --pre-hook "service nginx stop" --post-hook "service nginx start"--quiet
  11.  
  12. #前面如果选择的是 webroot 模式,用下面的方式续签证书,也可以用上面的形式
  13. 15 2 * */2 * /etc/letsencrypt/certbot-auto renew --disable-hook-validation --renew-hook "nginx -s reload"--quiet
  14.  
  15. #--pre-hook 表示执行更新操作之前要做的事情,如 standalone 模式的证书,需要停止 nginx 服务,解除端口占用。
  16. #--post-hook 表示执行更新操作完成后要做的事情,这里就恢复 nginx 服务
  17. #--force-renewal, --renew-by-default 在证书到期前强制更新(--keep-until-expiring, --keep, --reinstall 更好);
  18. #certbot-auto 和 certbot 本质上是完全一样的;不同之处在于运行 certbot-auto 会自动安装它自己所需要的一些依赖,并且自动更新客户端工具。
2.HTTPS重定向 跨域 HTTP 外链

主要思想是:将外链 HTTP(跨域资源) 转成支持 HTTPS “内链”,然后在用户点击该外链时,进行重定向跳转即可。Nginx核心配置方式如下:

  1. server {
  2.    listen 80;
  3.    server_name link.go2do.net;
  4.  
  5.    #301转移,http到https的跳转
  6.    return 301 https://link.go2do.net$request_uri;
  7. }
  8.  
  9. server {
  10.    listen 443 ssl http2;
  11.    server_name link.go2do.net;
  12.  
  13.    root /data/wwwroot/go2do.net/link.go2do.net;
  14.  
  15.    index index.html index.htm
  16.    access_log /data/wwwlogs/link.go2do.net_nginx.log combined;
  17.  
  18.    ssl on;
  19.  
  20.    #证书及私钥 位置路径,“Ctrl + c ”和“Ctrl + v ”时注意修改成自己的域名路径
  21.    ssl_certificate /etc/letsencrypt/live/link.go2do.net/fullchain.pem;
  22.    ssl_certificate_key /etc/letsencrypt/live/link.go2do.net/privkey.pem;
  23.  
  24.    #客户端能够重复使用存储在缓存中的会话参数时间,避免SSL重复握手操作
  25.    ssl_session_timeout 5m;
  26.    #会话缓存用于保存SSL会话,这些缓存在工作进程间共享
  27.    ssl_session_cache shared:SSL_L:5m;
  28.  
  29.    #指定使用的ssl协议,禁用不安全的SSLv1 2 3,只使用TLS
  30.    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  31.    #协商加密算法时,优先使用服务端的加密套件,而不是客户端浏览器的加密方式
  32.    ssl_prefer_server_ciphers on;
  33.  
  34.    #加密算法,RC4也是不安全的,去掉;Nginx默认使用DHE算法性能不佳
  35.   # ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
  36.     ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;
  37.  
  38.    location = / {
  39.         # ****以下 location 配置可简化用 rewrite 指令,本次为了知识的完备,用了反向代理(Reverse  Proxy)的思想 ,其实反代更配负载均衡或资源分布式****
  40.        #利用 proxy 模块,nginx 可与其它服务器进行关联,极大地提高了 nginx 的灵活性。如proxy 请求跨域资源(当然也可本域)
  41.  
  42.        #proxy_pass 默认使用的是 http 1.0,通过 proxy_http_version 指令使用 http 1.1,以便开启 keepalive 之类的功能
  43.        proxy_http_version 1.1;
  44.  
  45.        #避免nginx 启动 proxy_pass 时去查询 DNS(可能失败而报错),故 proxy_pass 时到 IP 上 类似于下面的方式
  46.        proxy_set_header Host www.go2do.net;
  47.  
  48.        # Host 表示请求的主机名, 因浏览器发送的主机名(即host)是反向代理服务器的名称,反向代理服务器转发前需替换成真实目标后端服务器的host 
  49.        # proxy_set_header Host $host:$proxy_port;  # 与上面方式重复,故注释掉
  50.  
  51.        #传达真实IP至目标服务器
  52.        proxy_set_header  X-Real-IP $remote_addr;  
  53.        proxy_set_header x-forwarded-for  $remote_addr; # 比另一种写法安全,但也去掉了代理中间代理服务器IP
  54.  
  55.        #如果请求头的值为空,那么这个请求头将不传送给后端服务器:
  56.        proxy_set_header Accept-Encoding "";
  57.        #user-agent,很多网站会通过这个来判断是不是机器访问
  58.        proxy_set_header User-Agent $http_user_agent; 
  59.  
  60.        #proxy_cache相关内容略,暂未使用   
  61.        proxy_buffer_size    64k;  
  62.        proxy_buffers        32 64k;
  63.  
  64.       #修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段。proxy_redirect [ default|off|redirect replacement ] 
  65.        proxy_redirect off;
  66.  
  67.       # proxy_pass 默认会将当前 URL 的 $uri 带过去,这样浏览器地址栏带有URI(即/xxxx/资源路径),如果不希望待URI,可加"?"
  68.       # proxy_pass 配合 rewrite 可修改 $uri ,比如去掉URI的一些内容...e.g:rewrite ^/xxx/(.*)  /$1 break;
  69.       # 但要注意 rewrite 会重新匹配 location,由于 proxy_pass 的处理阶段比 location 晚,所以需要 break 掉
  70.       # location /a/ { proxy_pass 的重定向里包括URI(即/xxxx/资源路径),浏览器地址栏会被 proxy_pass 后面URL中的URI替换}
  71.       # proxy_pass http://127.0.0.1/b/; ———>请求 http://www.go2do.net/a/c.html 会被重定向 http://127.0.0.1/b/c.html
  72.       # proxy_pass http://127.0.0.1;    ———>请求 http://www.go2do.net/a/c.html 会被重定向 http://127.0.0.1/a/c.html
  73.         proxy_pass https://127.0.0.1:443;
  74.  
  75.       }
  76.  
  77.  #            ***HTTPS重定向跨域 HTTP 外链   ***************      关键部分***:
  78.  # 在自己的博客插入外链资源时要用“https://link.go2do.net/jump/?url=跨域HTTP外链 ”,注意跨域外链是去掉了 http:// 或 https:// 后的链接路径。
  79.  # 通过判断匹配链接带有“ /jump/ ”,就表明是需要跳转的跨域外链(资源),用Nginx的自带变量 $arg_XXXX 获取需要的变量值
  80.  # $arg_XXXX 中的 XXXX 可以是 我们自定义链接“?”后面的任意预匹配的目标名称,本博客的取的就是 url 这个目标名称
  81.  #  所以$arg_XXXX ——————> $arg_url  此外,rewrite 后的"?" 用于去掉让跳转后的链接 不会 带有原始跳转前链接的URI 
  82.    location /jump/ {
  83.        #rewrite ^/(.*)$ $scheme://$arg_url? permanent;
  84.         rewrite ^/(.*)$  http://$arg_url? permanent;  #使用http通用性较好,因为如果启用了https,http会自动跳转为https
  85.  
  86.     }
  87.  
  88.  location / {
  89.         proxy_redirect off;
  90.  
  91.        #传达真实Host至目标服务器
  92.        proxy_set_header Host $host:$proxy_port;  
  93.        #传达真实IP至目标服务器
  94.        #还可用 –with-http_realip_module 模块实现相同的功能
  95.        proxy_set_header  X-Real-IP $remote_addr;    
  96.        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  97.        #或 proxy_set_header X-Forwarded-For $http_x_forwarded_for;
  98.  
  99.        #如果请求头的值为空,那么这个请求头将不传送给后端服务器:
  100.        proxy_set_header Accept-Encoding "";
  101.        #User-Agent,很多网站会通过这个来判断是不是机器访问
  102.        proxy_set_header User-Agent $http_user_agent; 
  103.  
  104.        proxy_pass https://www.go2do.net:443;
  105.     }
  106.  
  107. }

注1:补充一点Nginx 的 rewrite知识,这个也是很有用的

  1.  ################################################################################################################################################
  2.   #rewrite regex replacement [flag];  
  3.     #regex :正则表达式,用于匹配用户请求的uri  
  4.     #replacement:重写后的结果  
  5.     #flag 可以有四个值分别为last,break,redirect,permanent,flag没有指定,则默认为last
  6.        #last:重写完成之后停止对当前uri的进一步处理,改为对新uri的新一轮处理,还会在nginx内部重新自上而下检查rewrite匹配规则,break则不会
  7.       #break:重写完成后,停止对当前uri的处理,转向其后面的其他处理
  8.  
  9.     #   e.g:  rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;      # /download/a/media/12.php--->/download/a/mp3/12.html
  10.     #    ^ 匹配字符串的开始   $ 匹配字符串的结尾 .*表示任意内容,\.表示对.进行转义  $1引用前面的第一个()中的内容,$2引用第二个()中的内容以此类推
  11.     #     ~  为区分大小写匹配; !~为区分大小写不匹配  ;  ~* 为不区分大小写匹配;!~为不区分大小写不匹配
  12.     #     =  URI的精确匹配 ;~ 做正则表达式匹配,区分字符大小写 ;~* 做正则表达式匹配,不区分字符大小写 ;^~ URI的左半部分匹配,不区分字符大小写
  13.  
  14.     #    -f和!-f判断是否存在文件 ; -d和!-d判断是否存在目录 ; -e和!-e判断是否存在文件或目录 ; -x和!-x判断文件是否可执行
  15.  
  16.     #    PCRE正则表达式元字符 :  字符匹配 . [] [^] ; 次数匹配 * + ? {m} {m,} {m,n}  ; 位置定位 ^,$ ; 或者 |  ; 分组 () 后向引用 $1 $2…
  17.  
  18.     #    如果nginx 正则内有用{}的话,只要在正则的两边加上单引号或双引号就行了。花括号( { 和 } ) 他们既能用在重定向的正则表达式里,也是用在配置文件里分割代码块, 为了避免冲突。
  19.  
  20. # URI 一般格式为:scheme:[//] [[用户名[:密码]@]主机名:[端口号]][/资源路径名],如http://www.a.com:8080/path/file/index.html
  21. # Nginx的rewrite就是对其中的URI /path/file这部分进行处理和匹配,但是不能处理http://www.a.com,因为Nginx的rewrite接受到的URL不包含http://www.a.com。
  22. # URL 般格式为:scheme://主机名[:端口号][/资源路径],如:http://www.a.com:8080/path/file/index.html就是一个URL路径
  23. # URI 就是一种资源定位机制,它是比较笼统地定位了资源,并不局限于客户端和服务器,而URL就定位了网上的一切资源,只要是网上的资源,都有唯一的URL。
  24. ################################################################################################################################################

注2:Nginx做反向代理(Reverse Proxy)时X-Forwarded-For信息头的处理

remote_addr代表客户端的IP,如果没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了代理(包括Nginx类的反向代理),这样web服务器就会把remote_addr设为这台代理机器的IP。当使用了代理时,服务器就不知道你的真实IP了,为了避免这个情况,代理服务器通常会增加一个叫做x_forwarded_for的头信息,把连接它的客户端IP(即你的机器IP)加到这个头信息里,这样就能保证被带代理服务器能获取到真实IP。Nginx里面的 X_Forward_For 表示该条请求是谁发起的,如果反向代理服务器不重写该请求头,那么后端真实服务器会认为所有的请求都来在反向代理服务器, X-Forwarded-For:简称XFF头,它代表HTTP的请求端真实的IP,标准格式如下:X-Forwarded-For: client1, proxy1, proxy2…从标准格式可以看出,XFF头信息可以有多个IP,用逗号分隔,第1项为真实的客户端ip,剩下的就是曾经过的代理或负载均衡的ip地址,经过几个就会出现几个。当Nginx设置X-Forwarded-For为 $proxy_add_x_forwarded_for 后会有两种情况发生:

a、如果请求是从CDN或者代理过来的 ,且没有设置X-Forwarded-For头(通常这种事情不会发生),如果我们将Nginx设置将其设置为$proxy_add_x_forwarded_for的话,X-Forwarded-For的信息应该为CDN或者代理的IP,因为相对于Nginx负载均衡来说客户端即为CDN,这样的话,后端的web程序时死活也获得不了真实用户的IP的。

b、CDN或者代理设置了X-Forwarded-For,我们的服务器里又设置了一次,且值为$proxy_add_x_forwarded_for的话,那么X-Forwarded-For的内容变成 “客户端IP,Nginx负载均衡服务器IP”如果是这种情况的话,那后端服务器上的程序通过X-Forwarded-For获得客户端IP,即取逗号分隔的第1项即可。

如上两点所说,如果我们知道了CDN或者正向代理设置了X-Forwarded-For信息,且只有客户端真实的IP的话,那么我们的Nginx负载均衡服务器可以不必理会该头,让它默认即可。

其实Nginx中还有一个$http_x_forwarded_for变量,这个变量中保存的内容就是请求中的X-Forwarded-For信息。如果后端获得X-Forwarded-For信息的程序兼容性不好的话(没有考虑到X-Forwarded-For含有多个IP的情况),最好就不要将X-Forwarded-For设置为 $proxy_add_x_forwarded_for。应该设置为$http_x_forwarded_for或者 不设置!

欢迎投稿、分享转载,转载请保留如下信息:格物躬行博客[https://www.go2do.net]

本文由 [go2do] 原创,本文链接: https://www.go2do.net/vps/how-use-https-ssl-tls-performance-optimization.html



You may also like...

发表评论

电子邮件地址不会被公开。

本页共执行140次数据库查询,耗时0.266秒,使用内存 1.78 MB