Nginx (发音 “Engine X”) 是一款轻量级且高性能的 Web 服务器、反向代理服务器,同时也是一个 IMAP POP3 SMTP 服务器,完全通过 C 语言编写,支持多平台,并且在 BSD-like 协议下发行。
是由俄罗斯的 Igor Sysoev 开发,其特点是占有内存少、并发能力强、丰富的功能集和示例配置文件。在此仅简单介绍其安装使用方法。
简介
很多操作可以直接参考官方网站的文档 www.nginx.org ,在此仅列举其中比较常用的一些操作,使用的操作系统是 CentOS 。
----- 在CentOS中直接通过yum安装
# yum install nginx --enablerepo=epel
----- 启动,然后可以通过127.1直接访问,也可以通过enable设置开机启动
# systemctl start nginx.service
仅介绍一下安装 Nginx 之后的默认配置选项:默认的服务器根目录是 /usr/share/nginx/html
,配置文件在 /etc/nginx
目录下,默认是 /etc/nginx/nginx.conf
,日志默认在 /var/log/nginx
目录下。
常用操作
如下是经常会使用的命令。
----- 查看相关进程的资源
# ps axw -o pid,ppid,user,%cpu,vsz,wchan,command | egrep 'nginx:'
----- 其它的一些常见的命令
# kill -QUIT `cat /run/nginx.pid` ← 从容停止
# kill -TERM|INT `cat /run/nginx.pid` ← 快速停止
# kill -USR1 `cat /run/nginx.pid` ← 重新打开一个日志文件
# kill -USR2 `cat /run/nginx.pid` ← 升级可执行文件
# pkill -9 nginx ← 强制停止
# nginx -t -c /etc/nginx/nginx.conf ← 检查配置文件的语法
# kill -HUP `cat /run/nginx.pid` ← 重新加载配置文件
# nginx -s reload ← 同上
另外,为了防止由于安全配置导致报错,可通过 setenforce 0
关闭 SeLinux,之前被坑过 ^_^
现在可以直接通过浏览器打开 http://localhost/ 即可。当然,如果发现不符合期望的,可以直接查看默认的错误日志 /var/log/nginx/error.log
。
源码安装
如下是,如何通过源码安装、配置 nginx 。
1. 安装头文件
安装时依赖 pcre、openssl、gzip 三个库,在 CentOS 中,可以通过如下命令查看以及安装。
# rpm -qa | grep -E '(zlib|pcre|openssl)'
# yum install zlib zlib-devel pcre pcre-devel openssl openssl-devel
# yum install libxslt libxslt-devel
# yum install perl-ExtUtils-Embed
其中各个库的作用如下:
- pcre: 用来作地址重写的功能;
- zlib:用于传输数据打包,省流量,但消耗资源;
- openssl:提供ssl加密协议;
- xslt:用于过滤转换XML请求;
- gd: 用于JPEG/GIF/PNG图片的一个过滤器
2. 添加用户
一般启动时会使用 nginx 用户,所以通过如下方式添加相应的用户、用户组。
# groupadd nginx
# useradd -r -g nginx -s /sbin/nologin -M nginx
其中 -r 指定系统用户;-g 指定用户组;-s 指定 shell;-M 不创建 home 。
3. 下载编译
直接从官网 www.nginx.org 下载源码,然后通过如下方式编译、安装。
$ ./configure \
--prefix=/usr/share/nginx \ ← 安装目录,存放服务器文件
--sbin-path=/usr/sbin/nginx \ ← 可执行文件路径
--conf-path=/etc/nginx/nginx.conf \ ← 默认配置文件
--error-log-path=/var/log/nginx/error.log \ ← 报错文件,通过error_log修改
--http-log-path=/var/log/nginx/access.log \ ← 日志文件,通过access_log修改
--pid-path=/run/nginx.pid \ ← 存储主进程号,通过pid修改
--user=nginx \ ← 进程工作用户,通过user指定
--group=nginx \ ← 用户组,通过user指定
--lock-path=/run/lock/subsys/nginx \
--http-client-body-temp-path=/var/lib/nginx/tmp/client_body \
--http-proxy-temp-path=/var/lib/nginx/tmp/proxy \
--http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi \
--http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi \
--http-scgi-temp-path=/var/lib/nginx/tmp/scgi \
--with-file-aio \ ← 依赖libaio库
--with-ipv6 \ ← 支持IPV6
--with-http_ssl_module \ ← 使用https协议模块
--with-http_spdy_module \ ← Google的SPDY协议支持
--with-pcre \ ← 支持地址重写
--with-pcre-jit \
--with-google_perftools_module \ ← 依赖Google Perf工具,没有研究过
--with-debug \ ← 添加调试日志
--add-module=/path/to/echo-nginx-module ← 编译添加三方模块
--with-ld-opt='-Wl,-E'
nginx 没有通过 autotools 进行编译,而是通过自己的 shell 脚本实现,其中相应的脚本都在 auto 目录下,其中编译生成的文件都保存在 objs 目录下。
编译完成之后,可以通过如下命令安装即可。
# make install
4. 启动测试
源码编译完成之后,可以直接通过如下方式启动。
# /usr/sbin/nginx
5. systemd 支持
对于新一代的 init 支持,需要添加如下文件。
$ cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
然后就可以通过如下方式进行控制了。
$ systemctl [start|reload|restart|stop] nginx.service
$ journalctl -f -u nginx.service ← 查看日志
环境
配置完 Nginx 服务之后,实际上会在设置的 root 目录下添加符号 接,从而可以针对不同的运行环境,如 Bootstrap、echarts、php、DVWA,可以直接通过如下方式设置:
basic: 只包括了基本的测试。
ln -s basic html
bootstrap: 一个不错的前端框架。
ln -s ../bootstrap/bootstrap-3.3.5-dist html
echarts:
cd echarts-roots
ln -s ../../echarts/echarts.min.js echarts.js
cd ..
ln -s echarts-root html
php-root: PHP的安装环境
ln -s php-root html
DVWA: 一个安全测试环境
ln -s /home/andy/Workspace/security/dvwa/DVWA-1.9 html
变量
Nginx 配置文件的使用就像是一门微型的编程语言,既然如此,肯定不会少 “变量”,其支持内建变量,可以直接查看源码 http/ngx_http_variables.c
中 ngx_http_core_variables[]
的实现。
如下,使用了 ngx_rewrite
标准模块的 set
配置指令对变量 $foobar
进行了赋值操作,也即把字符串 hello world 赋给了它;如下需要依赖 echo 模块,详细安装方法参考下面的内容。
location /hello {
set $foobar "hello world";
echo "foobar: $foobar";
}
然后使用类似如下的 curl 命令测试即可。
$ curl 'http://localhost:80/hello'
内置变量
与 Apache 类似,在 core module 中支持一些内置的变量,常见的如下:
- $arg_PARAMETER
GET 请求的 PARAMETER 值。 - $args
请求行中的参数。 - $query_string
与 $args 相同。 - $binary_remote_addr
二进制码形式的客户端地址。 - $body_bytes_sent
发送页面的字节数。 - $content_length
请求头中的 Content-length 字段。 - $content_type
请求头中的 Content-Type 字段。 - $cookie_COOKIE
COOKIE 的值。 - $document_root
当前请求在 root 指令中指定的值。 - $document_uri
与 $uri 相同。 - $uri
请求中的当前URI,不含请求参数,参数位于$args,如 “/foo/bar.html” 。 - $request_uri
包含客户端请求参数的原始 URI,无法修改,可以查看 $uri 改写。 - $is_args
如果 $args 设置,值为 “?",否则为 “"。 - $limit_rate
可以限制连接速率。 - $nginx_version
当前运行的 nginx 版本号。 - $remote_addr
客户端的 IP 地址。 - $remote_port
客户端的端口。 - $remote_user
已经经过 Auth Basic Module 验证的用户名。 - $request_filename
当前连接请求的文件路径,由 root 或 alias 指令与 URI 请求生成。 - $request_body
包含请求的主要信息,在 proxy_pass、fastcgi_pass 中比较有意义。 - $request_method
客户端请求的动作,通常为 GET 或 POST。 - $server_addr
服务器地址。 - $server_name
服务器名称。 - $server_port
请求到达服务器的端口号。 - $server_protocol
请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。
配置文件
server_name
根据 HTTP 请求的 header Host 选择 nginx 配置文件里符合条件的 server_name 的 server 配置,也就是说一个配置文件里可以配置多个不同域名的服务。
其匹配的顺序如下: 1) 完全匹配 (www.example.com);2) 后缀匹配 (*.example.com);3) 前缀匹配 (www.example.*);4) 正则匹配。
若前面四项都没匹配上,则根据以下顺序:1) listen 指令里配置了 default 或 default_server 的 server;2) 第一个匹配上 listen 的 server。
server {
listen 8000;
server_name www;
location / {
echo "first";
}
}
server {
listen 8000;
server_name www.example.com;
location / {
echo "second";
}
}
server {
listen 8000;
server_name www.example.*;
location / {
echo "third";
}
}
server {
listen 8000;
server_name ~\w+.com;
location / {
echo "forth";
}
}
server {
listen 8000;
server_name ~.*example.com;
location / {
echo "fifth";
}
}
对于如上的示例,可以通过如下命令进行测试,当然为了测试需要在 /etc/hosts 配置文件中添加如下内容。
127.1 www www.example.com www.example.org www.foobar.com example.com example.org
注意 fifth 实际与 forth 冲突,不会出现 fifth 的。
$ curl http://www:8000/ ← 全匹配
first
$ curl http://www.example.com:8000/ ← 全匹配
second
$ curl http://www.example.org:8000/ ← 前缀匹配
third
$ curl http://example.com:8000/ ← 第一个正则匹配
forth
$ curl http://www.foobar.com:8000/ ← 同上
forth
$ curl http://example.org/ ← 无匹配,返回第一个符合的listen的
first
如果在配置文件里再加入一个配置。
server {
listen 8000 default;
server_name _;
location / {
echo "sixth";
}
}
则访问 http://example.org/ 返回 sixth 。
accept_mutex
简单来说,这个参数主要用来处理惊群问题,可以通过如下方式配置。
events {
accept_mutex off;
}
当新连接到达时,如果激活了 accept_mutex
,那么多个 worker 将以串行方式来处理,只有一个会被唤醒,其它的 worker 继续保持休眠状态;如果没有激活 accept_mutex
,那么所有的 worker 都被唤醒,不过只有一个 worker 能获取新连接,其它的 worker 会重新进入休眠状态。
不过不像 Apache 会启动成百上千的进程,如果发生惊群问题的话,影响相对较大;但是对 Nginx 而言,一般来说,worker_processes
会设置成 CPU 个数,所以最多也就几十个,即便发生惊群问题的话,影响相对也较小。
另外,高版本的 Linux 中,accept 不存在惊群问题,但是 epoll_wait 等操作还有。
如果关闭了它,可能会引起一定程度的惊群问题,表现为上下文切换增多 (sar -w
) 或者负载上升,但是如果网站访问量比较大,为了系统的吞吐量,建议关闭。
关闭之后一般各个工作进程的负载会更均衡,可以通过 github ngx-req-distr 测试。
文件服务器
可以通过 Nginx 搭建静态服务器,可以支持断点续传、多线程下载。
增加配置
在 /etc/nginx/conf.d
目录下包含了各种配置文件,如果要增加新配置,可以直接在该目录下新增配置文件 fileserver.conf
。
server {
listen 80; # 监听端口
server_name hostname; # 如果没有DNS解析,可以设置IP地址
client_max_body_size 4G; # 设置最大文件大小
charset utf-8; # 防止出现中文乱码
root /files; # 指定相对路径的根目录,如下的location会相对该路径
location /packages { # 实际存放文件的目录为/files/packages/
auth_basic "Restricted"; # 输入密码时的提示语
auth_basic_user_file /etc/nginx/pass_file; # 认证时用户密码文件存放路径
autoindex on; # 自动生成文件索引
autoindex_exact_size on; # 显示文件大小
autoindex_localtime on; # 显示本地文件时间
}
}
然后通过 nginx -t
检查语法是否正确,通过 nginx -s reload
重新加载配置。
可以通过如下方式添加用户。
htpasswd -c -d /etc/nginx/pass_file foobar
断点续传
一般第一次请求时会得到 200 状态码,而 206 则表示客户端通过发送范围请求头 Range 抓取到了资源的部分数据,通常用于断点续传、并发下载。
在使用前,需要知道文件大小以及远程服务器是否支持 206 请求,可以使用 curl -I URL
查看头部信息。
在相应的头部信息中,包含了两个关键的请求头:
Accept-Ranges: bytes
表明服务器支持Range请求,而且服务器所支持的单位是字节,支持断点续传、同时下载文件的多个部分;如果是none表示不支持。Content-Length: 36907
表明了响应实体的大小。
通过如上的方式,可以判断是否支持断点续传,在发送请求的时候,只需要添加类似 Range: bytes=0-1024
的头部即可。
常用模块
安装完 Nginx 之后,可以通过 -V 参数,查看编译时使用的参数;很多三方的模块可以参考 NGINX 3rd Party Modules ,保存了一个比较详细的列表。
对于三方模块,可以通过如下方法添加到二进制文件中。
$ ./configure \
--add-module=/path/to/echo-nginx-module
echo
用来显示一些常见的变量,不过这个模块不包含在 Nginx 源码中,可以通过如下方法进行安装;首先从 github openresty/echo-nginx-module 。
可以下载之后通过如下方式编译。
$ ./configure --add-module=/path/to/echo-nginx-module
简单的可以通过如下方式使用,也可以从官网查看详细的使用方法。
location /hello {
echo "hello, world!";
}
然后执行如下命令测试即可。
$ curl 'http://localhost:80/hello'
ngx_http_map_module
该模块可以用来创建变量,将这些变量的值与其它变量相关联,允许分类或者同时映射多个值到多个不同值并储存到一个变量中,而且仅在变量被接受的时候执行视图映射操作,对于处理没有引用变量的请求时,这个模块并没有性能上的缺失。
详细可以参考 Nginx 官方文档 Module ngx_http_map_module 。
auth_basic_module
关于该模块的内容详细可以查看 Nginx 基本认证模块 ,使用简单介绍如下。
需要保证已经安装了 ngx_http_auth_basic_module
模块,同样可以通过 nginx -V
查看,如果不需要可以使用 --without-http_auth_basic_module
。
location / {
auth_basic "closed site";
auth_basic_user_file conf/htpasswd;
}
其中 auth_basic
的字符串内容可以任意,例如 Restricted
、NginxStatus
等;另外,需要注意的是 auth_basic_user_file
的路径,否则会出现 403 错误。
其中密码文件的格式内容如下,其中密码通过 crypt()
函数加密,以及 Apache 基于 MD5 的变种 Hash 算法 (apr1) 生成,可以通过 Apache 中的 httpd-tools
中的 htpasswd
加密,或者使用 openssl passwd
获取。
# comment
name1:password1
name2:password2:comment
name3:password3
可以通过如下命令生成密码。
$ sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
$ printf "ttlsa:$(openssl passwd -crypt 123456)\n" >>conf/htpasswd
$ htpasswd -c conf/htpasswd username
其它
记录一些常见的问题,以及解决方法。
管理脚本
一个 Bash 管理脚本。
#!/bin/bash
# chkconfig: - 30 21
# description: http service.
# Source Function Library
. /etc/init.d/functions
# Nginx Settings
#the shell is used as a tool that start, stop, restart the servie nginx
NGINX_SBIN="/usr/local/nginx/sbin/nginx"
NGINX_CONF="/usr/local/nginx/conf/nginx.conf"
NGINX_PID="/usr/local/nginx/logs/nginx.pid"
RETVAL=0
prog="Nginx"
start() {
echo -n $"Starting $prog: "
mkdir -p /dev/shm/nginx_temp
daemon $NGINX_SBIN -c $NGINX_CONF
RETVAL=$?
echo
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -TERM
rm -rf /dev/shm/nginx_temp
RETVAL=$?
echo
return $RETVAL
}
reload(){
echo -n $"Reloading $prog: "
killproc -p $NGINX_PID $NGINX_SBIN -HUP
RETVAL=$?
echo
return $RETVAL
}
restart(){
stop
start
}
configtest(){
$NGINX_SBIN -c $NGINX_CONF -t
return 0
}
case "$1" in
start)
start
;;
stop)
stop
;;
reload)
reload
;;
restart)
restart
;;
configtest)
configtest
;;
*)
echo $"Usage: $0 {start|stop|reload|restart|configtest}"
RETVAL=1
esac
exit $RETVAL
监控 nginx 的工作状态
监控需要在编译时添加 --with-http_stub_status_module
选项,默认不会包含在内;然后在配置文件中添加如下内容。
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
修改完之后重新加载,然后可以通过 http://localhost/status 查看,此时会显示如下信息。
Active connections: 557 # 对后端发起的活动连接数
server accepts handled requests # 总共处理的链接数;成功握手次数;总共处理的请求
35 35 65
# 读取到客户端Header信息数;返回给客户端的Header信息数;等待下次请求的驻留连接
Reading: 3 Writing: 16 Waiting: 8
注意,对于最后一行的 Waiting,当开启 keep-alive 的情况下,这个值等于 active - (reading + writing),意思就是说已经处理完正在等候下一次请求指令的驻留连接。
启动报错
记录下遇到的一些常见问题。
Can’t load XXX
例如报错为 Can't load '/usr/local/lib64/perl5/auto/nginx/nginx.so'
,该报错是在使用 perl 模块时可能引入的报错,也就是编译时使用 --with-http_perl_module
参数。
# /usr/sbin/nginx
Can't load '/usr/local/lib64/perl5/auto/nginx/nginx.so' for module nginx:
/usr/local/lib64/perl5/auto/nginx/nginx.so: undefined symbol:
ngx_http_perl_handle_request at /usr/share/perl5/XSLoader.pm line 68.
at /usr/local/lib64/perl5/nginx.pm line 56.
Compilation failed in require.
BEGIN failed–compilation aborted.
nginx: [alert] perl_parse() failed: 255
此时,需要在编译的时候添加一个连接选项。
$ ./configure --with-http_perl_module --with-ld-opt="-Wl,-E"
然后,重新安装即可。
403 Forbidden
可以通过查看 error 日志,通常是由于权限不足导致,最简单的方式可以尝试在配置文件中设置 user root;,也就是 nginx 的子进程采用 root 用户。
当然,通常也可以使用 chown nginx:nginx -R /var/www
解决。
参考
可以参考官方文档 nginx.org docs 。