文章目录
- nginx安装教程
- nginx常用命令
- nginx配置教程
- root和alias 区别
- nginx常用通配符配置
- nginx配置防盗(限制文件访问)
- try_files $uri $uri/ /index.html含义
- try_files 踩坑记录
- 其它参数的含义
- nginx配置模板
- nginx实现负载均衡
- nginx为页面设置账号密码
nginx安装教程
- Nginx下载:
# 以下载1.21.6 版本为例 其它版本地址具体进入Nginx官网查看
wget https://nginx.org/download/nginx-1.21.6.tar.gz
- 解压
# 解压
tar -zxvf nginx-1.21.6.tar.gz
# 进入目录
cd nginx-1.21.6
- 配置
# 配置configure --prefix 安装路径 注意不要和解压目录在一起 且不要用相对路径!
#--with-http_ssl_module 安装ssl,--with-http_stub_status_module查看nginx的客户端状态
./configure --prefix=/app/nginx --with-http_ssl_module --with-http_stub_status_module
======== 可能遇到的报错 分割线开始:(如果没报错则忽略分割线内容) ============
这个步骤可能会报错
./configure: error: xxx modules require the xxx library.
需要安装openssl 组件 ,gcc组件, pcre依赖库 ,zlib依赖库,当然 有些是系统内置的,取决于你的是什么系统,比如我们用的较多的centos7云服务器 基本就只需要装个openssl了,下面分别通过centos和kali(debian分支,和Ubuntu一个体系的)进行举例。
centos:
yum install -y openssl*
yum -y install ncurses-devel
再次输入命令:./configure --prefix=/app/nginx --with-http_ssl_module --with-http_stub_status_module
kali:
和centos7不同,我们自己安装的kali系统 在devops方面的环境中 基本是一贫如洗, 所以拿来做教程也比较有代表性。
Nginx是C语言开发,安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境
sudo apt-get install gcc
(gcc应该是包含了下面的依赖 保险起见都安装一遍吧 占用内存也不高)
sudo apt-get install build-essential
sudo apt-get install libtool
(centos:yum install gcc-c++ )
Perl库,包括 perl 兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,
所以需要在linux上安装pcre库
sudo apt-get update
sudo apt-get install libpcre3 libpcre3-dev
(centos:yum install -y pcre pcre-devel)
zlib库提供了很多种压缩和解压缩的方式,nginx使用zlib对http包的内容进行gzip,
所以需要在linux上安装zlib库
sudo apt-get install zlib1g-dev
(centos:yum install -y zlib zlib-devel)
OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。
nginx不仅支持http协议,还支持https(即在ssl协议上传输http),所以需要在linux安装openssl库。
sudo apt-get install openssl
sudo apt-get install libssl-dev
(centos在上文已经提过了)
再次输入命令:./configure --prefix=/app/nginx --with-http_ssl_module --with-http_stub_status_module
=============================== 分割线结束=============================
- 安装
(还是在当前目录 不需要切换)
make & make install
上面操作可能会报错* No rule to make target build', needed by
default’. Stop.
回到第3点仔细阅读吧 ,这是缺少环境包导致的
- 进入安装目录 (这是我的安装目录 没该目录需要先创建)
cd /app/nginx
# 查看是否有安装的内容
ls
- 配置一个反向代理 体验/验证我们Nginx的效果
vim /app/nginx/conf/nginx.conf
# 另起一个server节点
# 这个配置的含义是 当访问地址为 本机ip:6768 时 ,其实是访问 /app/nginx-file/ 目录
server{
listen 6768;
server_name localhost;
location / {
root /app/nginx-file;
index index.html index.htm;
}
}
# 在 /app/nginx-file/ 目录下建一个名为 hello-nginx 的文件
# 步骤略
- 启动Nginx
cd /app/nginx/sbin
#启动nginx
./nginx
- 别忘记了开放监听端口的防火墙
- 访问Nginx配置的地址:
地址为服务器地址+ 监听端口 + hello-nginx - 成功完成一个demo流程
nginx常用命令
启动
./nginx
验证配置文件是否能正常启动
./nginx -t
正常停止
./nginx -s quit
快速停止
./nginx -s stop
重新加载
./nginx -s reload
查看版本信息
./nginx -V
nginx配置教程
root和alias 区别
location /api {
#root /path;
alias /path;
}
root 会拼接location后面的路径,而alias不会拼接。
习惯上 location / 时用root , 而location / 后面有路径时,用alias
如上面的例子, 客户端访问/api时 ,如果用root配置的 ,实际访问的是 /path/api
nginx常用通配符配置
如下配置
= 表示精确匹配 优先级最高
^~ 表示以某字符串开头 , ^~ /app/ 则表示127.0.0.1/app/ 下的所有路径
server {
listen 2700;
server_name 127.0.0.1;
rewrite_log on;
root html;
index index.html index.htm;
client_max_body_size 1024M;
add_header X-Frame-Options DENY;
location = /login {
echo "==login="
}
location ^~ /app/ {
internal;
alias /app/storage/;
}
location ^~ /download/ {
rewrite ^/download/(.*)$ /download/$1 break;
proxy_pass http://192.168.1.10:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
nginx配置防盗(限制文件访问)
还是这段配置, ^~/download/ 表示 127.0.0.1:2700/download 路径下的所有接口,
通过 proxy_pass 转发到127.0.0.1:8080 端口,
8080部署了我们的java项目,而在项目中,我们将地址重定向到 /app/
核心在于 ^~ /app/ 中的 internal ,它表示仅允许内部访问。
整体流程就是:我们由外部访问 2700端口的/download ,
再由nginx将 2700端口的 /download请求转到我们的8080项目/download接口
在8080 /download 接口中,通过代码 先进行一步自定义的校验 再将请求转到 /app
最后由nginx 的 /app配置下的internal 完成限制
server {
listen 2700;
server_name 127.0.0.1;
rewrite_log on;
root html;
index index.html index.htm;
client_max_body_size 1024M;
add_header X-Frame-Options DENY;
location ^~ /app/ {
internal;
alias /app/storage/;
}
location ^~ /download/ {
rewrite ^/download/(.*)$ /download/$1 break;
proxy_pass http://127.0.0.1:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
java代码示例
// @RestController
// @RequestMapping("/download")
@RequestMapping(value = "/{directory1}/{directory2}/{directory3}/{name}", method = RequestMethod.GET)
public void downloadFile(@PathVariable String directory1,
@PathVariable String directory2,
@PathVariable String directory3,
@PathVariable String name,
@RequestParam(required = false) String g,
@RequestParam(required = false) String t,
HttpServletRequest request, HttpServletResponse response) throws Exception {
this.deal(directory1, g, t, request, response);
}
private void deal(String directory1, String g, String t,
HttpServletRequest request, HttpServletResponse response) {
Object jwtUser = cacheApplicationService.getTokenUser(t);
if (jwtUser == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
String requestUri = request.getRequestURI();
String uri = requestUri.replaceAll("/download", "");
if (!"export".equals(directory1)) {
OssFileInfoVO fileInfo = storageService.getFileInfo(g);
if (fileInfo == null) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
uri = fileInfo.getPath();
}
response.setHeader("X-Accel-Redirect", "/app/" + uri);
}
try_files $uri $uri/ /index.html含义
location /api {
#root /path;
alias /path;
try_files $uri $uri/ /index.html;
}
try_files :当找不到root或alias的资源时,跳转路径至
$uri:查找当前访问下的文件 $ui/:查找当前访问下的文件夹 (当前访问 例子中的客户端发起对 /api 请求)
try_files 踩坑记录
场景还原:从浏览器访问192.168.1.1服务器,再经过192.168.1.1的nginx 转发至192.168.1.2:8888,
此时发现,项目其它接口返回都是200。
但是 有个图形验证码的接口,它不能正确的返回验证码,通过192.168.1.2:8888服务器项目的接口访问记录详细日志发现,访问的是192.168.1.2:8888/index.html 。
推测: 验证码接口是图片流资源接口 末尾隐式带html ,nginx识别错误,自动拼接了一个index.html (这是个疑惑点 有清楚的朋友欢迎留言指教)
操作: 把try_files行配置注释(或删除)
server {
listen 18080;
server_name xx.xxx.xxx.x;
root html;
index index.html index.htm;
add_header X-Frame-Options DENY;
location /{
add_header Access-Control-Allow-Origin '*';
proxy_pass http://192.168.1.xx:8888;
#try_files $uri $uri/ /index.html;
}
}
其它参数的含义
$args #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名.请求中的主机头字段,如果请求中的主机头不可用,则为服务器处理请求的服务器名称
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr #获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传 递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie #请求的所有cookie
$http_host #请求地址,即浏览器中你输入的地址(IP或域名)
$http_referer #url跳转来源,用来记录从那个页面链接访问过来的
$http_user_agent #用户终端浏览器等信息
$http_x_forwarded_for #客户端的IP和代理服务器的IP,以逗号隔开;可伪造
$http_x_forwarded_proto #请求的协议
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
nginx配置模板
#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;
#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;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# 使用导入配置的方式
# 例如下面的目录中 有a.conf,b.conf 里面的内容是 server{ ....}
# 那就在本配置 server同级节点引入即可
# include /mnt/app/nginx/*.conf;
# 设置 defalut port 也可以说不是什么默认端口 就是打开Nginx默认的那个index页面
server {
listen 6080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
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;
#}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# demo port 用于将服务器文件 直接提供url 供下载
# 当访问 localhost:6768/app/nginx-file 时 能下载该文件
server{
listen 6768;
server_name localhost;
location / {
root /app/nginx-file;
index index.html index.htm;
}
}
# mark: ${server_name} can be overwirte $host
server{
listen 80;
# 域名
server_name xxx.cn;
location / {
# 假设该vue前端项目 已打包成dist 并使用tomcat启动 (也可以直接用Nginx启动)
# 7081是tomcat端口 vue是webapps下的项目文件夹 (dist改名成了vue 放在tomcat webapps目录下)
proxy_pass http://127.0.0.1:7081/vue/;
# dev: proxy_pass http://x.x.x.x:vueProjectPort/;
# 直接Nginx启动的配置
location / {
# alias和root区别: root会拼接location后面的路径
#例如 location /api {root /路径/dist/} 的配置 , 访问localhost:/api其实是访问 /路径/dist/api/文件夹
alias /路径/dist/;
# 找不到路径时转发到Nginx默认页
try_files $uri $uri/ /index.html;
}
}
# 转到https
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
# 443端口 https代理 (和上面的配置 配套使用)
server{
listen 443 ssl;
server_name xxx.cn;
ssl on;
ssl_certificate /路径/xxx.cn.cer;
ssl_certificate_key /路径/xxx.cn.key;
# 例如前端访问后端的url(注意是https 如果是http 则配到上面80端口里面)为:
# https:xxx.cn/api/login 其中/api是vue项目指定的proxy
# 将https:xxx.cn/api 开头的所有请求 代理到后端项目端口
location /api {
# 后端项目
proxy_pass http://127.0.0.1:8051/;
}
# 将https:xxx.cn/python 开头的所有请求 代理到后端python项目端口
location /python {
# py项目
proxy_pass http://127.0.0.1:8052/;
}
# 剩下的请求(静态页面 纯前端的东西) 代理到vue项目
location / {
# dev: proxy_pass http://127.0.0.1:7081/; 且不需要上面两个location
proxy_pass http://127.0.0.1:7081/vue/;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# 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;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
nginx实现负载均衡
这个其实也特别简单,在上面的配置中加上
# clusterserver 是自定义的名字
upstream clusterserver{
// 下面两个是服务地址,weight表示权重
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8090 weight=1;
}
server{
listenn 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
proxy_pass http://clusterserver;
}
}
nginx为页面设置账号密码
- 为我们的前端页面设置一个账号密码
一般情况下 我们的项目都是会配合权限框架来设置账号密码的,
这里例举一个Nginx设置账号密码的场景:为第三方中间件控制台设置账号密码(不是我们自己写的项目)
例如skywalking的控制台界面 就是没有账号密码的。
#yum安装htpassed工具
yum -y install httpd-tools
#设置用户名和密码,并把用户名、密码保存到指定文件中:
#新增一个用户 注意,先创建好文件夹/文件,不然创建文件失败,如果文件已存在会覆盖之前文件
# 例如 cd /app mkdir nginx-for-webpwd touch pwd.db
# 对应的命令即 htpasswd -c /app/nginx-for-webpwd/pwd.db myUserName
htpasswd -c [passwfile] [username]
删除账号命令:
htpasswd -D [passwdfile] [username]
htpasswd命令选项参数说明:
-c 创建一个加密文件
-n 不更新加密文件,只将htpasswd命令加密后的用户名密码显示在屏幕上
-m 默认htpassswd命令采用MD5算法对密码进行加密
-d htpassswd命令采用CRYPT算法对密码进行加密
-p htpassswd命令不对密码进行进行加密,即明文密码
-s htpassswd命令采用SHA算法对密码进行加密
-b htpassswd命令行中一并输入用户名和密码而不是根据提示输入密码
-D 删除指定的用户
最后需要在Nginx的配置里面指定:
server{
# nginx的监听端口
listen 11111;
server_name localhost;
location / {
# 页面端口
proxy_pass http://xxx.xxx.xx.xx:11110/test/;
# 提示语
auth_basic "please input password";
# 密码文件所在路径
auth_basic_user_file /app/nginx-for-webpwd/pwd.db;
}
}