Nginx 配置 HTTP 跳转 HTTPS

本文介绍 Nginx 访问 HTTP 跳转 HTTPS 的 4 种配置方式。

1. rewrite

Nginx rewrite 有四种 flag:

  • break:在一个请求处理过程中将原来的 url 改写之后,再继续进行后面的处理,这个重写之后的请求始终都是在当前这一个 location 中处理
  • last:相当于一个新的 request,需要重新走一遍 server,提供了一个可以转到其他 location 的机会
  • redirect:表示 302 temporarily redirect
  • permanent:表示 301 permanently redirect

要使用 HTTP 跳转 HTTPS,当然是需要 301 跳转,即使用 permanent 这个标签:

rewrite  ^(.*)  https://$server_name$1 permanent;

提醒:以上配置涉及到三个本文并未提及的点:rewrite 用法、全局变量、正则匹配。

2. 301 状态码

Nginx 使用 ruturn ${http_code} 指定对应状态码的处理。这里我们使用 return 301 指定 301 重定向的目标:

return  301  https://$server_name$request_uri;

3. 497 状态码

当 server 只允许 HTTPS 请求时,基于 HTTP 的访问会被 Nginx 返回 497 错误。这时我们使用 error_page 将访问重定向至 HTTPS 上:

error_page  497  https://$server_name$request_uri;

4. meta

还有一种方式是,返回一个写入 meta 标签的 html 页面,让浏览器跳转。和上面三种方式不同,此方案不在 Nginx 上进行跳转,节约服务器资源,而缺点是不能写入 $request_uri 变量,只能跳转到固定地址。

server {
    ...

    index  meta.html;
    error_page 404 meta.html;
}

在要返回的 meta.html 中写入:

<html>
  <meta http-equiv="refresh" content="0; url=${你要跳转的目标地址}">
</html>

本站就使用这个方案,所以我是这样写的:

<html>
  <meta http-equiv="refresh" content="0; url=https://sometimesnaive.org/">
</html>

nginx配置正向代理支持HTTPS

未分类

nginx当正向代理的时候,通过代理访问https的网站会失败,而失败的原因是客户端同nginx代理服务器之间建立连接失败,并非nginx不能将https的请求转发出去。因此要解决的问题就是客户端如何同nginx代理服务器之间建立起连接。有了这个思路之后,就可以很简单的解决问题。我们可以配置两个SERVER节点,一个处理HTTP转发,另一个处理HTTPS转发,而客户端都通过HTTP来访问代理,通过访问代理不同的端口,来区分HTTP和HTTPS请求。

#HTTP
server{
resolver 8.8.8.8;
access_log /data/logs/nginx/access_proxy.log main;
listen 80;
location / {
root html;
index index.html index.htm;
proxy_pass $scheme://$host$request_uri;
proxy_set_header HOST $http_host;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#HTTPS
server{
resolver 8.8.8.8;
access_log /data/logs/nginx/access_proxy.log main;
listen 443;
location / {
root html;
index index.html index.htm;
proxy_pass https://$host$request_uri;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_next_upstream error timeout invalid_header http_502;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

如果访问HTTP网站,可以直接这样的方式: curl –proxy proxy_server:80 http://www.taobao.com/
如果访问HTTPS网站,例如https://www.alipay.com,那么可以使用nginx的HTTPS转发的server:
curl –proxy proxy_server:443 http://www.alipay.com

2013年12月9日补记:

之前nginx配置透明代理的时候,没有特别针对端口的配置,如果之前的url是http://www.test.com:8080/这样的地址过来,通过nginx转发之后实际到了http://www.test.com:80/上面,为了修复这个问题,增加如下配置:

proxy_pass http://$host:$cookie_passport$request_uri;

其中$cookie_是获取请求中cookie的信息,这个passport的cookie值是原URL中端口号。由此可以看出,如果要通过该NGINX转发,需要首先设置一个cookie,这个cookie名为passport,cookie的值为原url中的端口号。

如果使用CURL命令请求链接,可以这样子:

curl -b passport=80 --proxy proxy_server:80 http://www.taobao.com/

其中-b参数是为了添加cookie

nginx 出现504 Gateway Time-out的解决方法

本文介绍nginx出现504 Gateway Time-out问题的原因,分析问题并提供解决方法。

1. 问题分析

nginx访问出现504 Gateway Time-out,一般是由于程序执行时间过长导致响应超时,例如程序需要执行90秒,而nginx最大响应等待时间为30秒,这样就会出现超时。

通常有以下几种情况导致

1.程序在处理大量数据,导致等待超时。
2.程序中调用外部请求,而外部请求响应超时。
3.连接数据库失败而没有停止,死循环重新连。

出现这种情况,我们可以先优化程序,缩短执行时间。另一方面,可以调大nginx超时限制的参数,使程序可以正常执行。

对于访问超时的设定,nginx与php都有相关的设置,可以逐一进行修改。

2. 解决方法

nginx配置

nginx.conf中,设置以下几个参数,增加超时时间

fastcgi_connect_timeout 

fastcgi连接超时时间,默认60秒

fastcgi_send_timeout 

nginx 进程向 fastcgi 进程发送请求过程的超时时间,默认值60秒

fastcgi_read_timeout 

fastcgi 进程向 nginx 进程发送输出过程的超时时间,默认值60秒

php配置

php.ini

max_execution_time 

php脚本最大执行时间

php-fpm

request_terminate_timeout 

设置单个请求的超时时间

php程序中可加入set_time_limit(seconds)设置最长执行时间

例如 set_time_limit(0) 表示不超时。

NGINX实现图片防盗链(REFERER指令)

Nginx referer指令简介

nginx模块ngx_http_referer_module通常用于阻挡来源非法的域名请求.我们应该牢记,伪装Referer头部是非常简单的事情,所以这个模块只能用于阻止大部分非法请求.我们应该记住,有些合法的请求是不会带referer来源头部的,所以有时候不要拒绝来源头部(referer)为空的请求.

图片防盗链一般配置:

location ~* .(jpg|jpeg|bmp|gif|png|css|js|ico|webp|tiff|ttf|svg) {
    valid_referers none blocked *.wuditnt.com wuditnt.com ~.google. ~.baidu.;
    if ($invalid_referer) {
        return 403;
        #rewrite ^/ http://XXXX/403.gif; ##这个图片不能被防盗链,不然显示不正常。除非把上面的GIF过滤删除。
    }
    expires 30d;
}

以上所有来至*.wuditnt.com和域名中包含google和baidu的站点都可以访问到当前站点的图片,如果来源域名不在这个列表中,那么$invalid_referer等于1,在if语句中返回一个403给用户,这样用户便会看到一个403的页面,如果使用下面的rewrite,那么盗链的图片都会显示403.gif。如果用户直接在浏览器输入你的图片地址,那么图片显示正常,因为它符合none这个规则.

!!!!!!!!!

注意: http://XXXX/403.gif; ##这个图片不能被防盗链,不然显示不正常,会出现重复过滤。

除非把上面(jpg|jpeg|bmp|gif|png|css|js|ico|webp|tiff|ttf|svg) 中的gif过滤删除。

不过这个不是真正的防盗链方式,右键点击保存图片链接,还是可以在浏览器中显示的。

网上有的人说把none blocked删除掉,就形成了真正的防盗链方式,还有待测试。

!!!!!!!!!!

疑问:

经过测试,这个设置方式对Google Chrome的隐身模式和手机的Chrome浏览器似乎无效,一样可以看到图片。

其他浏览器如猎豹、微软的Edge、IE都有效果。

语法说明

valid_referers none | blocked | server_names | string …;
默认值: —
配置段: server, location
指定合法的来源’referer’, 它决定了内置变量$invalid_referer的值,如果referer头部包含在这个合法网址里面,这个变量被设置为0,否则设置为1.记住,不区分大小写的.

参数说明

none:“Referer” 来源头部为空的情况
blocked:“Referer”来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头.
server_names:“Referer”来源头部包含当前的server_names(当前域名)
arbitrary string:任意字符串,定义服务器名或者可选的URI前缀.主机名可以使用*开头或者结尾,在检测来源头部这个过程中,来源域名中的主机端口将会被忽略掉
regular expression:正则表达式,~表示排除https://或http://开头的字符串.

宝塔部署ubuntu+nginx+flask环境

准备

  1. 搭建好宝塔的vps,我用的是vultr
  2. flask应用在本地运行成功

在宝塔界面添加网站

  1. 设置好域名,数据库,php版本不管,或者在软件管理中卸载php
  2. 创建的web文件在/www/wwwroot/目录下
  3. 在本地的flask应用文件打包上传到刚刚创建的web文件中,解压

创建Python环境

$ sudo apt install python3-venv
$ python3 -m venv venv
# 如果venv/bin/下没有activate,就表示没有成功,解决如下
$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"
$ sudo dpkg-reconfigure locales
# 进入虚拟环境
$ source venv/bin/activate
# 安装uWSGI和requirements
$ pip install uwsgi
$ pip install -r requirements.txt
# 退出虚拟环境
$ deactivate

配置uwsgi

在应用根目录创建config.ini文件,内容如下

[uwsgi]
# uwsgi 启动时所使用的地址与端口
socket = 127.0.0.1:8386
# 指向网站目录
chdir = /www/wwwroot/www.itswcg.site
# python 启动程序文件
wsgi-file = main.py
# python 程序内用以启动的 application 变量名
callable = app 
# 处理器数
processes = 4
# 线程数
threads = 2
#状态检测地址
stats = 127.0.0.1:9191

配置nginx

在宝塔面板中,管理网站,设置,配置文件修改如下,
或者在/www/server/panel/vhost/nginx/.conf下修改

server {
  listen  80; 如有多个web应用,都是80端口监听
  server_name resume.itswcg.com; #地址
  location / {
    include      uwsgi_params;
    uwsgi_pass   127.0.0.1:8386;  # 指向uwsgi 所应用的内部地址,所有请求将转发给uwsgi 处理
    uwsgi_param UWSGI_PYHOME /www/wwwroot/www.itswcg.site/venv; # 指向虚拟环境目录
    uwsgi_param UWSGI_CHDIR  /www/wwwroot/www.itswcg.site; # 指向网站根目录
    uwsgi_param UWSGI_SCRIPT main:app; # 指定启动程序
  }
}

重启

$ sudo service nginx restart

这时候运行如下,不出错,输入网址就成功了

$ uwsgi config.ini

配置supervisor

supervisor能同时启动多个应用,能自动重启应用,保证可用性。
安装

$ sudo apt-get install supervisor

在/etc/supervisor/conf.d下添加.conf文件(resume.conf),内容如下

[program:resume] #resume是<name>
##注意项目目录和uwsgi的配置文件地址
command=/www/wwwroot/www.itswcg.site/venv/bin/uwsgi /www/wwwroot/www.itswcg.site/config.ini
directory=/www/wwwroot/www.itswcg.site
autostart=true
autorestart=true
user = root
##log文件的位置
stdout_logfile=/www/wwwroot/www.itswcg.site/logs/uwsgi_supervisor.log

启动

supervisord -c /etc/supervisor/supervisord.conf

客户端管理

$ supervisorctl

这样你就不用每次重启时都运行$ uwsgi config.ini,supervisor帮你自动重启

还有别忘了在宝塔面板安全中,放行端口

未分类

禁止通过IP访问——nginx

有时我们只希望能够通过域名访问,而不希望通过ip访问,这就需要设置nginx.conf配置文件了,现总结如下:

  • 禁止通过http方式访问

主要实现代码如下:

server
 {
    listen 80 default_server;
    server_name _;
    return 500;
  }
  • 禁止通过https防止访问

一定要SSL证书,不然会导致域名也无法访问!证书可以随便填,直接填920.ai域名证书的路径

server 
    {
        listen 443 default_server;
        server_name _;
        ssl on;
        ssl_certificate /etc/letsencrypt/live/920.ai/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/920.ai/privkey.pem;
        return 500;
    }

nginx端口映射tcp

添加到

/etc/nginx/nginx.conf

添加内容:

stream {
    upstream ssr {
        hash $remote_addr consistent;
        server 127.0.0.1:31905 weight=5 max_fails=3 fail_timeout=30s;
    }
    server {
       listen 4008;
       proxy_connect_timeout 1s;
       proxy_timeout 3s;
       proxy_pass ssr;
    }
}

监听4008,映射到127.0.0.1:31905,名字ssr。

CentOS下安装gperftools优化nginx

一、下载软件包

http://mirror.yongbok.net/nongnu/libunwind/libunwind-1.1.tar.gz  #下载libunwind

https://gperftools.googlecode.com/files/gperftools-2.0.tar.gz   #下载gperftools
上传软件包到服务器的/usr/local/src目录下面

二、安装gperftools

1、安装libunwind(安装gperftools前需要先安装libunwind)

cd /usr/local/src  #进入安装目录
tar zxvf libunwind-1.1.tar.gz  #解压
cd libunwind-1.1
./configure #配置
make #编译
make install #安装

2、安装gperftools

cd /usr/local/src
tar zxvf gperftools-2.0.tar.gz
cd gperftools-2.0 #进入目录
./configure --enable-frame-pointers #配置
make
make install

3、配置gperftools

vi /etc/ld.so.conf.d/usr_local_lib.conf  #编辑,添加以下内容
/usr/local/lib
:wq! #保存退出

/sbin/ldconfig  #执行此命令

cd /usr/local/src/nginx-1.2.4 #进入nginx安装包目录

./configure --prefix=/usr/local/nginx --with-google_perftools_module --without-http_memcached_module --user=www --group=www --with-http_stub_status_module --with-openssl=/usr/ --with-pcre=/usr/local/src/pcre-8.31
#重新配置nginx,添加--with-google_perftools_module参数

make #编译
make install  #安装

mkdir /tmp/tcmalloc  #新建目录
chmod  777 /tmp/tcmalloc -R  #设置目录权限

4、配置nginx

未分类

vi /usr/local/nginx/conf/nginx.conf #编辑,在#pid logs/nginx.pid;这行的下面添加
google_perftools_profiles /tmp/tcmalloc;
:wq! #保存退出
service nginx restart  #重启nginx

三、测试

lsof -n | grep tcmalloc #测试tcmalloc
lsof -n | grep nginx  #测试nginx

未分类

未分类

至此,CentOS下安装gperftools优化nginx完成。

分析nginx upstream权重为0和删除节点

前言:

nginx upstream是大家经常使用的东西,通过upstream方法可以轻易的实现服务的负载均衡。 但往往很多人不理解nginx upstream删除主机跟权重配置为0有什么细节上的区别,从官方的介绍里也只能简单得知,weight = 0 不转发新请求,删除主机用来下线。 但你要明白这类操作对于长连接的影响。因为如果你这个理解不到位,很容易造成服务的异常,哪怕只是一小片时间。 好了,闲话不多说,我们直接通过测试来验证他的结果。

权重设为0: upstream把某个节点的权重重置为0,nginx不再往该节点转发新请求,老连接就这么挂着, 已经建立的连接不会中断, 直至超时或主动断开.新连接不会转到节点上来。

移除主机: 在upstream列表中删除该节点,nginx会首先把不在传输中的连接关闭,继而等待数据传输完毕后,把连接关闭掉。

Nginx upstream相关配置

# xiaorui.cc

upstream bakend {
    server 127.0.0.1:7080;
    server 127.0.0.1:7081;
}

server {
    listen       8122 default_server;
    server_name  _;
    root         /var/lib/download;

    include /etc/nginx/default.d/*.conf;

    location / {
        proxy_pass http://bakend;
    }
}

后端服务( 使用golang net/http开发案例)

至于端口变换一下就可以了,另外为了测试活跃的长连接情况,使用chunk分块的方式来延迟返回。

# xiaorui.cc

package main

import (
    "fmt"
    "io"
    "net/http"
    "time"
)

func main() {
    fmt.Println("7080")
    http.HandleFunc("/test", HandlePost);
    fmt.Println(http.ListenAndServe(":7080", nil))
}

func HandlePost(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Connection", "Keep-Alive")
    w.Header().Set("Transfer-Encoding", "chunked")
    w.Header().Set("X-Content-Type-Options", "nosniff")

    ticker := time.NewTicker(time.Second)
    go func() {
        for t := range ticker.C {
            io.WriteString(w, "Chunkn")
            fmt.Println("Tick at", t)
        }
    }()
    time.Sleep(time.Second * 15)
    ticker.Stop()
    fmt.Println("Finished: should return Content-Length: 0 here")
    w.Header().Set("Content-Length", "0")
}

模拟的客户端

# xiaorui.cc

import time
import os

import requests

s = requests.Session()
print os.getpid()
res = s.get("http://127.0.0.1:8122/test")
print res.content
time.sleep(10)

s = requests.Session()
res = s.get("http://127.0.0.1:8122/test")
print res.content

总结, 不管是权重配置为0 和 移除主机 都能保证服务的安全的退出,优雅灰度上下线。

END.

体验nginx端的HTTP2 Server Push 来

未分类

最新的nginx主线版本(1.13.9)终于支持http2 server push了:至于server push是什么,有什么好处,不赘述。

Changes with nginx 1.13.9                                        20 Feb 2018

    *) Feature: HTTP/2 server push support; the "http2_push" and
       "http2_push_preload" directives.

    *) Bugfix: "header already sent" alerts might appear in logs when using
       cache; the bug had appeared in 1.9.13.

    *) Bugfix: a segmentation fault might occur in a worker process if the
       "ssl_verify_client" directive was used and no SSL certificate was
       specified in a virtual server.

    *) Bugfix: in the ngx_http_v2_module.

    *) Bugfix: in the ngx_http_dav_module.

于是将本地服务器的nginx从最新的稳定版(1.12.2)升级到1.13.9。并且根据对应的

http2_push

http2_push_preload

指令,做相应的配置。

未分类

This directive appeared in version 1.13.9.

Pre-emptively sends (pushes) a request to the specified uri along with the response to the original request. Only relative URIs with absolute path will be processed, for example:

http2_push /static/css/main.css;

The uri value can contain variables.

Several http2_push directives can be specified on the same configuration level. The off parameter cancels the effect of the http2_push directives inherited from the previous configuration level.

未分类

This directive appeared in version 1.13.9.

Enables automatic conversion of preload links specified in the “Link” response header fields intopush requests.

默认情况下都是off,关闭的,需要手动去打开,这两个指令都支持在http,server或者location段内配置。一般在server段内配置好全站需要的资源引用即可。而在location端内,则可以针对具体类似页面做配置。

针对http2_push指令这里需要注意的几点:

  1. http2_push 后面必须跟的是资源的绝对路径

  2. 该资源路径可以包含变量

  3. 同一个配置级别(比如,server段内)可以配置多个http2_push

针对http2_push_preload这个指令,用于设置是否让在页面内标记的资源是否主动推送。

这里贴上部分配置:

# the whole www.hzshuangmei.com site
http2_push /alidata1/web/static.hzshuangmei.com/img/pc/favicon.ico ;
http2_push /alidata1/web/static.hzshuangmei.com/img/pc/kst/default.png ;
http2_push /alidata1/web/static.hzshuangmei.com/css/pc/common.css ;
http2_push /alidata1/web/static.hzshuangmei.com/js/pc/layer/theme/default/layer.css ;
http2_push /alidata1/web/static.hzshuangmei.com/js/pc/common.js ;
http2_push /alidata1/web/static.hzshuangmei.com/js/pc/layer/layer.js ;
http2_push /alidata1/web/static.hzshuangmei.com/js/pc/kst_popup.js ;

# the index page
location =/{

  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/index.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/js/pc/js ;

}

# the brand page
location ^~/brand/ {

  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/brandzt/theme.css;
  http2_push /alidata1/web/static.hzshuangmei.com/js/pc/brandzt/theme.js ;

}

# the list of  the projects pages
location ^~/projects/*$
{
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/list_project.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/js/pc/list_project.js ;
}

# the project landing page
location  ^~/projects/*/*.html$ {
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/tjb.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/img/pc/tjb_bg.jpg ;
}

# the list of the doctors pages
location ^~/doctors/*$
{
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/list_doctors.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/js/pc/list_doctors.js ;
}
# the doctor landing page
location  ^~/doctors/*/*.html$
{
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/tjb.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/img/pc/tjb_bg.jpg ;
}

# the list of the cases pages
 location ^~/cases/*$
{
   http2_push /alidata1/web/static.hzshuangmei.com/css/pc/list_case.css ;
   http2_push /alidata1/web/static.hzshuangmei.com/js/pc/list_case.js ;
}

# the case landing page
location  ^~/cases/*/*.html$
{
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/article_case.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/article_common.css ;
   http2_push /alidata1/web/static.hzshuangmei.com/js/pc/article_common.js ;
}

# the list of the news pages
 location ^~/news/*$
{
   http2_push /alidata1/web/static.hzshuangmei.com/css/pc/list_news.css ;
   http2_push /alidata1/web/static.hzshuangmei.com/js/pc/list_news.js ;
}

# the news landing page
location  ^~/news/*/*.html$
{
  http2_push /alidata1/web/static.hzshuangmei.com/css/pc/article_common.css ;
  http2_push /alidata1/web/static.hzshuangmei.com/js/pc/article_common.js;
}

将上面的文件引入到主机配置文件中。另外在http段内设置:

http2_push_preload on;

体验效果:

未分类

检测验证http/2 server push

可以使用以下两种方法之一轻松验证服务器推送是否有效:

  1. Web浏览器中的开发人员工具

  2. 一个命令行的HTTP / 2客户端如 nghttp

使用开发人员工具进行验证(Google Chrome)

以下以Google Chrome为例,说明如何使用Web浏览器中的开发人员工具来验证服务器推送是否有效。在该图中,Chrome开发人员工具的“ 网络”标签上的“ 启动器”列指出,作为/demo.html请求的一部分,有多个资源被推送到客户端。

未分类

使用命令行客户端进行验证(nghttp)

除了Web浏览器工具,您还可以使用nghttp2.org项目中的nghttp命令行客户端来验证服务器推送是否有效。您可以从GitHub下载命令行客户端,或在可用的位置安装相应的操作系统软件包。对于Ubuntu,请使用该软件包。nghttpnghttp2-client

在输出中,星号(*)表示服务器推送的资源。

$ nghttp -ans https://example.com/demo.htmlid  responseEnd requestStart  process code size request path
 13    +84.25ms       +136us  84.11ms  200  492 /demo.html
  2    +84.33ms *   +84.09ms    246us  200  266 /style.css
  4   +261.94ms *   +84.12ms 177.83ms  200  40K /image2.jpg
  6   +685.95ms *   +84.12ms 601.82ms  200 173K /image1.jpg

参考资料:

https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/