安装nginx并安全地配置和启动
摘要:centos中的nginx安装教程,以低权限用户启动nginx,使用防火墙转发流量解决非root用户无法使用1024以下端口问题,nologin用户执行命令的方法。
文章目录见右侧
一、安装nginx
1.1 下载
# 如果centos服务器是最小体量安装,则先安装weget
yum install -y wget
#下载nginx,截至写稿最新是1.23.1
cd /home
wget http://nginx.org/download/nginx-1.23.1.tar.gz
tar -zxvf nginx-1.23.1.tar.gz
cd nginx-1.23.1
1.2 安装编译依赖
安装gcc环境,以及pcre等依赖
yum install -y pcre pcre-devel openssl openssl-devel gcc gcc gcc-c++ ncurses-devel perl
1.3 提前下载第三方依赖
编译时的模块越多越好,如果安装了以后还想加模块,就得重新编译
第三方依赖:
# more_clear_headers
# 不用找最新版本,很久没更新了
git clone https://github.com/openresty/headers-more-nginx-module.git
# git clone git@github.com:ohmyzsh/ohmyzsh.git
1.4 编译
#可选编译步骤:去掉debug,提高一点编译速度
#vim auto/cc/gcc
#在179行这样注释掉 CFLAGS="$CFLAGS -g" 使用:set nu显示行号
./configure --prefix=/usr/local/nginx --user=nobody --group=nobody --with-http_ssl_module --with-http_sub_module \
--with-http_gzip_static_module --with-http_stub_status_module --with-http_gunzip_module \
--with-stream --with-stream_ssl_module \
--add-module=./headers-more-nginx-module
ssl是支持https,sub_module和gzip、gunzip用于代理时修改报文中src的链接地址什么的
headers-more-nginx-module用于清除响应的http headers
至少在nginx-1.23.1以后,默认待ipv6模块所以不用 --with-ipv6
详细信息使用./configure --help
#编译
make -j8 # 根据cpu最大线程数决定,为cpu核心的2倍,减少编译时间
1.5 安装
make install
#安装成功
#安装目录
cd /usr/local/nginx
二、配置教程
安全地配置nginx,主要是以低权限用户运行nginx,这样即使出现漏洞,攻击者也难以反弹shell
2.1 创建用户和组
groupadd nologin
useradd nginx-nologin -M -s /sbin/nologin -g nologin
#-M 不指定家目录
#-s 指定shell ,nologin代表该用户无法用于登录,但是可以指定以此用户执行命令,详情在后面
#-g 指定组
觉得麻烦直接用系统自带的 nobody 用户,本文后续使用nobody用户
2.2 获取https证书
这是可选的,如果你还没有域名,则需先购买域名,国内😉购买域名还需要备案。
如果你有域名,那么推荐使用https,证书可以免费申请,无需备案。
以阿里云为例,你使用域名申请后,推荐使用文件验证,因为dns验证的话需要等dns传播。验证通过一分钟左右就会审核通过,接着下载证书文件,要下载nginx的。下载后解压重命名为cert.pem
和cert.key
,传到服务器/usr/local/nginx/conf/
目录下。
后续配置中取消掉有关ssl的配置的注释。
2.3 配置防火墙
如果操作系统是最小安装,没有防火墙的话,还需要安装防火墙
可以运行命令检测是否安装
iptables
firewalld #centos7默认
如果两个都报错找不到命令的话需要安装,推荐firewalld
yum install -y firewalld
systemctl enable firewalld #开机启动
systemctl start firewalld #启动
接下来是防火墙配置
#开放端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent
#流量转发
firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8800 --permanent
firewall-cmd --add-forward-port=port=443:proto=tcp:toport=4433--permanent
#配置立即生效
firewall-cmd --reload
2.4 配置文件权限
这是最后一步,推荐把这些命令存为sh文件,并设置权限755,因为改动文件时可能需要重复执行。
chown -R nobody:nobody /usr/local/nginx
#chmod -R 755 /usr/local/nginx
三、配置nginx.conf
vi /usr/local/nginx/conf/nginx.conf
下面贴出博主自用的配置
# 运行用户和组
user nobody;
worker_processes 1;
# 去掉注释
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#去掉注释
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# 隐藏Server信息,再处理好各报错页面,nmap也扫不出你是啥服务
more_clear_headers Server;
# more_clear_headers Date;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
# 流量控制,开辟10m内存存储相关信息,访问频率限制为一秒3次,访问频率超过会返回500状态码
#limit_req_zone $binary_remote_addr zone=mylimit:10m rate=3r/s;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# 文件上传最大限制,避免报413
client_max_body_size 50m;
# 给后端用
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
# 强制http转https,
# server {
# listen 80;
# return 301 https://www.xx.com;
# }
server {
listen 2000 ssl;
listen [::]:2000 ipv6only=on;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# 流量控制,继承上面的配置,并且新增一个缓冲区能缓存2次请求
#limit_req zone=mylimit burst=2;
ssl_certificate cert.pem;
ssl_certificate_key cert.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:MD5;
ssl_prefer_server_ciphers on;
root html;
location / {
#root html;
alias html/;
index 404.html;
#add_header Content-Type 'text/html; charset=UTF-8';
default_type 'text/html; charset=UTF-8';
more_clear_headers Last-Modified;
more_clear_headers ETag;
more_clear_headers Accept-Ranges;
more_clear_headers Date;
}
# 一个钓鱼的webshell
location ^~ /webshell.php/ {
# proxy_send_timeout 3;
# proxy_connect_timeout 3;
# proxy_read_timeout 3;
proxy_pass http://127.0.0.1:3002/webshell.php;
error_page 404 = /404.html;
error_page 504 = /504.html;
error_page 500 = /500.html;
error_page 502 = /502.html;
}
# nginx实现返回ip
location ^~ /ip {
default_type application/json;
if ($http_x_forwarded_for ~ "<"){
return 200 "{\"ip\":\"$remote_addr\",\"xff\":\"\"}";
}
return 200 "{\"ip\":\"$remote_addr\",\"xff\":\"$http_x_forwarded_for\"}";
}
# 初次安装gitea时使用,可以把 2000:/gitea_init_xxx/ 映射到 300:/
# 需要解析http报文,将里面的href= src= 以及set-cookie等都换掉。还涉及zip压缩等
# location ^~ /gitea_init_xxx/ {
# proxy_pass http://127.0.0.1:3000/;
# proxy_redirect / /gitea_init_xxx/;
# proxy_set_header Accept-Encoding '';
# gunzip on;
# gzip off;
# sub_filter 'href="/' 'href="/gitea_init_xxx/';
# sub_filter 'src="/' 'src="/gitea_init_xxx/';
# sub_filter '="/' '="/gitea_init_xxx/';
# sub_filter_types *;
# sub_filter_once off;
# }
# gitea安装时,可以配置一个路径 https://www.xxx.top:2000/gitea_web/
# 和这里一致即可
location ^~ /gitea_web/ {
proxy_pass http://127.0.0.1:3000/;
}
# 前后端分离部署web
# location /kingyan-plus {
# alias kingyan-plus;
# index index.html;
# default_type 'text/html; charset=UTF-8';
# }
# location ^~ /kingyan-plus-api/ {
# proxy_pass http://127.0.0.1:8080/kingyan-plus-api/;
# }
# 错误的请求,http不规范,比如用nc连接,设置这个可以避过nmap扫描
error_page 400 /400.html;
# http请求https端口
error_page 497 /400.html;
error_page 405 /405.html;
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;
}
}
}
#stream {
# squid https代理,实现外网访问家庭网络,但软路由vpn更靠谱
# server {
# listen [::]:2043 ssl ipv6only=on;
# listen 2043 ssl;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:MD5;
# ssl_prefer_server_ciphers on;
# proxy_pass 127.0.0.1:2080;
# }
#}
3.1 配置路由,添加前后缀
location 是匹配请求,语法:
location [=|~|~*|^~] /uri/ {… }
符号 | 含义 |
---|---|
= | 精确匹配 |
^~ | 非正则匹配 |
~ | 正则匹配(区分大小写) |
~* | 正则匹配(不区分大小写) |
!~ | 正则不匹配(区分大小写) |
!~* | 正则不匹配(不区分大小写) |
普通匹配(这里没有符号的时候) |
匹配后缀可以用:location ~* \.(gif|jpg|png)$ { ... }
匹配并代理具有前缀的接口:
比如想通过http://127.0.0.1:80/lib
访问http://127.0.0.1:8080/lib
location ^~ /prefix/ {
# 设置路由的目标(上游)地址
proxy_pass http://127.0.0.1:3000/;
}
而接口本身没有前缀,代理时为其添加前缀就复杂一点
比如想通过http://127.0.0.1:80/lib
访问http://127.0.0.1:8080/
location ^~ /prefix/ {
# 设置路由的目标(上游)地址
proxy_pass http://127.0.0.1:3000/prefix/;
# 当出现跳转时,修改报文的Location header
proxy_redirect / /prefix/;
# 如果sub_filter不生效,可能是服务器启用了zip压缩
proxy_set_header Accept-Encoding '';
#gunzip on;
#gzip off;
# 修改html中的链接
sub_filter 'href="/' 'href="/prefix/';
sub_filter 'src="/' 'src="/prefix/';
sub_filter_types *;
sub_filter_once off;
}
3.2 添加http header
header配置location内的会覆盖server中的
使用
add_header Content-Type text/html;
default_type 'text/html; charset=UTF-8';
真正要设置Content-Type第一句是无法生效的,因为nginx默认配置有default_type application/octet-stream;
,使用add_header
只会让响应出现两个Content-Type
所以我们要设置Content-Type的话要在location中使用default_type去覆盖
3.3 清除http header
为什么要删除http header,为了安全,最常见的就是隐去Server不暴露nginx版本
其次,还有一些高级玩法,比如静态页面伪装成动态
more_clear_headers
使用模块headers-more-nginx-module
前文描述了如何下载安装,如果已经安装了nginx,想添加模块,重新编译,但是使用--add-dynamic-module动态模块,这样在编译目录下找到/objs/ngx_http_headers_more_filter_module.so
配置文件中加上
load_module /home/nginx-1.20.2/objs/ngx_http_headers_more_filter_module.so;
http {
more_clear_headers Server;
......
location ~ ^.*\.jsp$ {
# 把静态资源伪装成动态
# 浏览器缓存相关
more_clear_headers Last-Modified;
more_clear_headers ETag;
# 静态文件下载-断点续传
more_clear_headers Accept-Ranges;
四、启动nginx
一切准备就绪,现在可以启动,推荐把启动命令保存为sh文件,并设置权限755
这里演示了nologin用户如何执行命令
启动和重启:
#su即使用另一个用户执行命令,-s指定了shell,-c是命令内容
#nginx -c是检查配置是否正确
su -s /bin/bash -c "/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf" nobody
#-s reload用于运行时重载配置文件无需停止,也可以用于启动
su -s /bin/bash -c "/usr/local/nginx/sbin/nginx -s reload" nobody
建议修改配置后都 -c 重新加载配置文件再 -s reload
如果要停止,可以使用
su -s /bin/bash -c "/usr/local/nginx/sbin/nginx -s quit" nobody
查看版本用-v
,查看详细信息,安装了哪些模块用-V
4.1 运行脚本
最后附上博主的nginx运维脚本,方便重启nginx
以下脚本可以放在nginx目录中,我们稍后把他注册成服务由systemctl管理
#!/bin/bash
# chkconfig:2345 60 30
# description: nginx
# 以上为开机自启配置
service_name=Nginx
key_word=nginx
function findps()
{
if [ "$1" = "print" ]
then
ps -ef|grep $key_word|grep -vE "(grep|$0|service.*$key_word|systemctl)"
else
fps=`ps -ef|grep $key_word|grep -vE "(grep|$0|service.*$key_word|systemctl)"`
fi
}
function startps()
{
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx -s reload
}
function killps()
{
/usr/local/nginx/sbin/nginx -s quit
# ps -ef|grep $key_word|grep -vE '(grep|$0|service.*$key_word|systemctl)'| cut -c 7-16|xargs kill -9
}
case "$1" in
start)
findps;
if [ -z "$fps" ]
then
startps;
echo -e "\033[32;1mStarted successfully\033[0m"
else
echo -e "\033[31;1m$service_name service is already running! \033[0m"
exit 1
fi
;;
################################
stop)
findps;
if [ -z "$fps" ]
then
echo -e "\033[31;1m$service_name service is not running! \033[0m"
exit 1
else
killps;
fi
echo -e "\033[32;1mStopped successfully\033[0m"
;;
#################################
restart|force-reload)
findps;
if [ -n "$fps" ]
then
killps;
fi
echo -e "\033[32;1mStopped successfully\033[0m"
sleep 0.5
startps;
echo -e "\033[32;1mStarted successfully\033[0m"
;;
########################################
status)
findps;
if [ -z "$fps" ]
then
echo -e "\033[31;1m$service_name service is stopped\033[0m"
else
echo -e "\033[32;1m$service_name service is running\033[0m"
findps print
fi
;;
*)
echo $"Usage: $0 {start|stop|status|restart|force-reload}"
esac
exit 0
以下文件保存为.service结尾,调用上面的脚本
放在/usr/lib/systemd/system目录下
[Unit]
Description=nginx
After=network-online.target
[Service]
Type=forking
ExecStart=/usr/bin/bash /root/nginx start
ExecStop=/usr/bin/bash /root/nginx stop
ExecReload=/usr/bin/bash /root/nginx restart
[Install]
WantedBy=multi-user.target
end
往期精彩文章推荐:
《动态svg图片简单制作》