十分钟了解Nginx

nginx 入门、安装、命令、配置、优化

操作系统:CentOS 7
Nginx版本:yum安装1.12.2 、编译安装1.14.2

一、安装

1. yum安装

安装源

[root@localhost ~]# yum list nginx
[root@localhost ~]# rm -rf /etc/yum.repos.d/*
[root@localhost ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
[root@localhost ~]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@localhost ~]# yum clean all && yum makecache

启动一个Nginx

[root@localhost ~]# yum install -y nginx
[root@localhost ~]# nginx
[root@localhost ~]# curl localhost

yum安装Nginx的目录结构

[root@localhost ~]# find / -name nginx
/etc/logrotate.d/nginx #滚动日志
/etc/nginx #配置文件
/usr/lib64/perl5/vendor_perl/auto/nginx #http-perl
/usr/lib64/nginx #molules
/usr/sbin/nginx #bin文件
/usr/share/nginx #html/molules
/var/lib/nginx #tmp
/var/log/nginx #log
[root@localhost ~]# yum remove -y nginx
[root@localhost ~]# find / -name nginx

2. 编译安装

准备环境依赖

[root@localhost ~]# rm -rf /etc/yum.repos.d/*
[root@localhost ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo
[root@localhost ~]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@localhost ~]# yum install -y gcc gcc-c++ make pcre-devel zlib-devel

编译安装Nginx

[root@localhost ~]# curl -o nginx-1.14.2.tar.gz http://nginx.org/download/nginx-1.14.2.tar.gz
[root@localhost ~]# tar -xf nginx-1.14.2.tar.gz
[root@localhost ~]# cd nginx-1.14.2
[root@localhost nginx-1.14.2]# ./configure
[root@localhost nginx-1.14.2]# make && make install
[root@localhost nginx-1.14.2]# find / -name nginx
/root/nginx-1.14.2/objs/nginx #编译文件
/usr/local/nginx #安装目录
/usr/local/nginx/sbin/nginx #bin文件

启动一个Nginx

[root@localhost sbin]# ./nginx
[root@localhost sbin]# curl localhost

3. 编译安装进阶

3.1. 指定编译参数

[root@localhost nginx-1.14.2]# ./configure --prefix=$PWD/nginx

3.2. 安装官方模块

[root@localhost nginx-1.14.2]# ./configure --prefix=$PWD/nginx --with-stream

3.3. 安装自定义模块
3.3.1 编写Nginx自定义模块

[root@localhost nginx-1.14.2]# mkdir -p modules/ngx_http_hello_world_module
[root@localhost nginx-1.14.2]# cd modules/ngx_http_hello_world_module
[root@localhost ngx_http_hello_world_module]# touch ngx_http_hello_world_module.c config

ngx_http_hello_world_module.c

#include "ngx_core.h"
#include "ngx_string.h"
#include "ngx_buf.h"
#include "ngx_module.h"
#include "ngx_conf_file.h"
#include "ngx_http.h"
#include "ngx_http_request.h"
#include "ngx_http_config.h"
#include "ngx_http_core_module.h"
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r)
{
    if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD)))
        return NGX_HTTP_NOT_ALLOWED;
    ngx_int_t rc = ngx_http_discard_request_body(r);
    if (rc != NGX_OK)
        return rc;
    ngx_str_t type = ngx_string("text/plain");
    ngx_str_t response = ngx_string("Hello World!\n");
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;
    r->headers_out.content_type = type;
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
        return rc;
    ngx_buf_t *b;
    b = ngx_create_temp_buf(r->pool, response.len);
    if (b == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    ngx_memcpy(b->pos, response.data, response.len);
    b->last = b->pos + response.len;
    b->last_buf = 1;
    ngx_chain_t out;
    out.buf = b;
    out.next = NULL;
    return ngx_http_output_filter(r, &out);
}
static char *ngx_http_hello_world(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t *clcf;
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_hello_world_handler;
    return NGX_CONF_OK;
}
static ngx_command_t ngx_http_hello_world_commands[] = {
    {ngx_string("hello_world"), NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
        NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS, ngx_http_hello_world, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL},
    ngx_null_command
};
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
ngx_module_t ngx_http_hello_world_module = {
    NGX_MODULE_V1,
    &ngx_http_hello_world_module_ctx,
    ngx_http_hello_world_commands,
    NGX_HTTP_MODULE,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NGX_MODULE_V1_PADDING
};

config

ngx_addon_name=ngx_http_hello_world_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"

3.3.2 编译自定义模块

[root@localhost nginx-1.14.2]# ./configure --prefix=$PWD/nginx --with-stream --add-module=modules/ngx_http_hello_world_module
[root@localhost nginx-1.14.2]# make && make install
[root@localhost nginx-1.14.2]# vim nginx/conf/nginx.conf
server {
    listen       80;
    server_name  localhost;
    #charset koi8-r;
    #access_log  logs/host.access.log  main;
    location / {
        # root   html;
        # index  index.html index.htm;
        hello_world;
    }
}

3.3.3 启动nginx,测试hello world

[root@localhost nginx-1.14.2]# nginx/sbin/nginx 
[root@localhost nginx-1.14.2]# curl localhost
Hello World!

3.3.4 Nginx开发
​ Tengine http://tengine.taobao.org/
​ Openresty http://openresty.org/cn/

二、Nginx命令

[root@localhost ~]# nginx -h 
nginx version: nginx/1.14.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /root/nginx-1.14.2/nginx/)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file
[root@localhost ~]# nginx -v
nginx version: nginx/1.14.2
[root@localhost ~]# nginx -V
nginx version: nginx/1.14.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 
configure arguments: --prefix=/root/nginx-1.14.2/nginx --with-stream --add-module=modules/ngx_http_hello_world_module
[root@localhost ~]# nginx -t
nginx: the configuration file /root/nginx-1.14.2/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /root/nginx-1.14.2/nginx/conf/nginx.conf test is successful
[root@localhost ~]# nginx -s quit
[root@localhost ~]# nginx -c /etc/nginx-2.conf
[root@localhost ~]# nginx -g 'worker_processes 4;'

三、Nginx配置文件

#user  nobody; #worker用户
worker_processes  1; #worker进程数,cat /proc/cpuinfo | grep "processor" | wc -l
#error_log  logs/error.log; #错误日志路径
#error_log  logs/error.log  notice; #错误日志路径notice级别
#error_log  logs/error.log  info; #错误日志路径info级别
#pid        logs/nginx.pid; #pid路径
events { #events块
    worker_connections  1024; #每个worker最大开启连接数,ulimit -n
}
http { #http块
    include       mime.types; #引入媒体文件
    default_type  application/octet-stream; #默认响应类型
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    # main级别日志输出格式
    #access_log  logs/access.log  main; #访问日志main级别
    sendfile        on; #开启sendfile,作为静态服务器时性能显著提高
    #tcp_nopush     on; #包攒到一定大小再发送,开启sendfile时生效
    #keepalive_timeout  0;
    keepalive_timeout  65; #连接超时(秒)
    #gzip  on; #开启压缩
    server { #server段
        listen       80; #监听80端口
        server_name  localhost; #绑定localhost
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / { #匹配uri
            root   html; #设置root目录
            index  index.html index.htm; #默认首页
        }
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html; #错误码和错误页
        location = /50x.html {
            root   html;
        }
    }
}

main/events块指令集 http://nginx.org/en/docs/ngx_core_module.html
http块指令集 http://nginx.org/en/docs/http/ngx_http_core_module.html

四、基本用例

1. 静态资源服务器

直接启动Nginx就是个静态资源服务器。
alias和root的区别

location /foo {
    root /a/b;
}
# 当请求的uri为/foo/c.html时,实际请求的文件路径是/a/b/foo/c.html
location /bar {
    alias /x/y;
}
# 当请求的uri为/bar/z.html时,实际请求的文件路径是/x/y/z.html
# alias对末尾的/敏感,alias末尾与uri末尾保持一致

rewrite的用法

location /foo {
    rewrite /foo/(.*) /bar/$1 break;
    root /a/b;
}
# 当请求的uri为/foo/c.html时,将请求改写为/bar/c.html,实际请求的文件路径是/a/b/bar/c.html
location /foo {
    rewrite /foo/(.*) /bar/$1 last;
    root /a/b;
}
# 当请求的uri为/foo/c.html时,将请求改写为/bar/c.html,重新寻找location块匹配,实际请求的文件路径是/x/y/c.html
location /foo {
    rewrite /foo/(.*) /bar/$1 permanent;
}
# 当请求的uri为/foo/c.html时,将请求改写为/bar/c.html,直接返回301跳
location /foo {
    rewrite /foo/(.*) /bar/$1 redirect;
}
# 当请求的uri为/foo/c.html时,将请求改写为/bar/c.html,直接返回302跳

break/last是同一个连接的内部处理过程,permanent/redirect是两次连接;
break不再执行location匹配,last执行多次location匹配,通常在server中使用last,在location中使用break;
301跳会缓存,302跳不会;

2. 简单文件服务器

server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    root         /usr/share/nginx/html;
    include /etc/nginx/default.d/*.conf;
    location / {
        autoindex on;
    }
    error_page 404 /404.html;
        location = /40x.html {
    }
    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}

当路径下存在index.html index.htm 时autoindex不生效

3.代理服务器

3.1正向代理

正向代理:代理客户端称为正向代理,如爬虫使用的代理服务器。基本是固定写法。

server {  
    resolver 8.8.8.8;
    listen 8888;
    location / {
        proxy_pass http://$http_host$request_uri;
        proxy_set_header HOST $http_host;
    }
}

3.2 反向代理

正向代理:代理服务端称为反向代理,如通过代理java隐藏端口。基本是固定写法。

server {
    listen       80;
    server_name  _;
    location =/index.html {
        return 200 "index\n";
    }
}
server {
    listen       81;
    server_name  _;
    location /proxy {
        proxy_pass http://localhost/;
    }
}

如果不想改变原地址中的uri,proxy_pass中就不要写uri!

4.负载均衡

利用一定的策略将网络负载分摊到网络集群的各个服务上,从而减轻服务器负载并提高用户体验。

server {
    listen       80 default_server;
    server_name  _;
    location / {
        proxy_pass http://balance;
    }
}
upstream balance {
    server localhost:81;
    server localhost:82;
}
server {
    listen       81;
    server_name  _;
    location / {
        return 200 "1\n";
    }
}
server {
    listen       82;
    server_name  _;
    location / {
        return 200 "2\n";
    }
}

Nginx负载均衡策略:round robin、weight、ip_hash、least_conn、fair(3)、url_hash(3)

5.TCP/UDP代理

TCP/UDP协议的反向代理。

stream{
    upstream mysql{
        server localhost:3306;
    }
    server{
        listen 3307;
        proxy_pass mysql;
    }
}

需要stream模块支持

五、深度优化

1、安全优化

1.1 隐藏Nginx软件名和版本号

[root@localhost /]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 23 Apr 2019 06:23:27 GMT
Content-Type: application/octet-stream
Content-Length: 2
Connection: keep-alive
  • 方案1:修改nginx.conf添加
server_tokens off;
  • 方案2:修改$NGINX_HOME/src/core/nginx.h(不推荐
#define NGINX_VERSION      "1.14.2"
#define NGINX_VER          "nginx/" NGINX_VERSION
// 随意修改以上两个字段(注意这是C代码,#不是注释的意思)
#define NGINX_VERSION      "7.5.1"
#define NGINX_VER          "IIS/" NGINX_VERSION
  • 方案3:修改$NGINX_HOME/src/core/nginx.h
static u_char ngx_http_server_string[] = "Server: nginx" CRLF;
static u_char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
// 随意修改以上两个字段
static u_char ngx_http_server_string[] = "Server: IIS" CRLF;
static u_char ngx_http_server_full_string[] = "Server: " "IIS/7.5.1" CRLF;
  • 隐藏40x、50x页面的软件名版本号:修改nginx.conf添加
error_page 400 401 402 403 404 405 415 /40x.html;
location = /40x.html {
    return 200 "not found.";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    return 200 "error.";
}

1.2 非法域名解析

server {
    listen 80 default_server;
    server_name _;
    rewrite ^(.*) http//:www.example.com/$1 permanent;
}

1.3 黑白名单

location / {
   allow 127.0.0.1;
   deny 192.168.1.1;
}

1.4 DDOS攻击

# 访问频率限制
limit_req_zone $binary_remote_addr zone=perip:100m rate=1r/s;
server {  
    limit_req zone=perip burst=5 nodelay;
}

2、性能优化

2.1 优化进程和连接数

worker_processes    4; #auto=逻辑核数,高io的可以再调大;如果服务器有其他负载按需设置;
worker_cpu_affinity 0001 0010 0100 1000; #cpu亲和性,指定每个线程运行在哪个核上;
events {
    use epoll;  #显式指定采用epoll,如果不知道是什么请让Nginx自己决定最优方案;
    worker_connections  1024;#每个进程最大可打开连接数受制于ulimit -n;
}

2.2 高效文件传输

# 设置传输参数
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
server_names_hash_bucket_size 128;
server_names_hash_max_size 512;
keepalive_timeout 65;
client_header_timeout 15s;
client_body_timeout 15s;
send_timeout 60s;
# 设置压缩参数
gzip on;
gzip_disable "msie6";
gzip_min_length 1k;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png;
# 为静态资源设置合理的过期时间
expires    -1;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容