1. 首页
  2. Nginx私房菜

Nginx 入门实战

级别: ★★☆☆☆
标签:「Nginx」「https」「负载均衡」
作者: 九点下班
审校: QiShare团队


1. Nginx简介

Nginx 是一款轻量级的 Web 服务器。通常用在反向代理负载均衡HTTP 缓存。目前全球很多知名互联网公司在使用 Nginx。

反向代理和正向代理

Nginx 的一个作用是反向代理,那什么是正向代理和反向代理?在知乎上有一个回答总结的不错放到这里。

以下内容来自知乎用户班长他姐夫的回答

正向代理隐藏真实客户端,反向代理隐藏真实服务端。

以下内容来自知乎用户刘志军的回答

我们常说的代理也就是只正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求,某些科xue学上网工具扮演的就是典型的正向代理角色。用浏览器访问 www.google.com 时,被残忍的block,于是你可以在国外搭建一台代理服务器,让代理帮我去请求google.com,代理把请求返回的相应结构再返回给我。

image.png

反向代理隐藏了真实的服务端,当我们请求 www.baidu.com 的时候,就像拨打10086一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器,用来做负载均衡。

两者的区别在于代理的对象不一样:正向代理代理的对象是客户端,反向代理代理的对象是服务端

image.png

基于对上面的理解,我们可以看到 Nginx 对于处理有高并发需求的网站是有非常大的作用的。下面我们看一下在 MacOS 上 Nginx 的安装和基本使用。

2. Nginx基本使用

Nginx安装

我们使用 homebrew 来安装 Nginx

  • 搜索Nginx

brew search nginx //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列
  • 安装Nginx

brew install nginx

如果 homebrew 需要更新的话这个过程会比较慢,耐心等待即可。安装完成后会有如下提示:

Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

To have launchd start nginx now and restart at login:
  brew services start nginx
Or, if you don't want/need a background service you can just run:
  nginx
==> Summary
🍺  /usr/local/Cellar/nginx/1.17.8: 25 files, 2MB
==> `brew cleanup` has not been run in 30 days, running now...
Removing: /usr/local/Cellar/pcre/8.43... (204 files, 5.5MB)
Pruned 1 symbolic links and 1 directories from /usr/local
==> Caveats
==> nginx
Docroot is: /usr/local/var/www

The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that
nginx can run without sudo.

nginx will load all files in /usr/local/etc/nginx/servers/.

To have launchd start nginx now and restart at login:
  brew services start nginx
Or, if you don't want/need a background service you can just run:
  nginx
  • 查看Nginx信息

brew info nginx

这个命令和安装完成之后的提示基本一致,会显示 Nginx 的基本配置信息。

  • 卸载Nginx

brew uninstall Nginx

注意这个命令只会卸载 Nginx 软件本身,并不会删除配置文件。如果我们想彻底删干净 Nginx,需要手动删除 /usr/local/var/www/usr/local/etc/nginx/ 下的文件。

  • 查看Nginx版本

nginx -v //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

我本机的 Nginx 版本如下


nginx version: nginx/1.17.8 //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列
  • 检查Nginx配置是否正常

nginx -t //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

如果正常的话,我们会得到如下输出:


nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列
  • 配置文件

cat /usr/local/etc/nginx/nginx.conf //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

以上命令可以输出 nginx.conf 默认状态下的配置,在关键的地方我加了注释说明。


\#user nobody; worker_processes 1; #(1)进程数 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #(2)错误日志位置 Mac上在/usr/local/var/log/nginx/ #pid logs/nginx.pid; events { worker_connections 1024; #(3)最大连接数 } 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"'; #(4)日志格式 #access_log logs/access.log main; #(5)访问日志位置 Mac上在/usr/local/var/log/nginx/ sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 8080; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; #(6)第一种情况 拒绝访问ip地址段为 50-100 的ip访问 deny 192.168.10.50/100; # 第二种情况 只允许ip地址为 192.168.10.50 的ip访问 allow 192.168.10.50; deny all; # 第三种情况 这样配置都不能访问,从上到下依次匹配 deny all; allow 192.168.10.50; } #(7)精确匹配 /test 路径拒绝访问 location =/test { deny all; } #(8)精确匹配 /test2 路径都可以访问 location =/test2 { allow all; } #(9)精确匹配 已 php 结尾拒绝访问 location ~ \.php$ { # 正则匹配 deny all; } #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; #} } # 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; # } #} include servers/*; #(10)其他配置文件 } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列
  • 启动Nginx

cd /usr/local/Cellar/nginx/1.17.8/bin ./nginx //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列
  • 重新加载配置文件

./nginx -s reload //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

启动完成之后执行 ps -ef|grep nginx,如果出现下面日志则说明访问成功。


501 65101 1 0 8:59下午 ?? 0:00.00 nginx: master process ./nginx 501 65102 65101 0 8:59下午 ?? 0:00.00 nginx: worker process 501 65173 63026 0 9:00下午 ttys001 0:00.00 grep nginx //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

访问http://localhost:8080,如果出现以下页面说明我们配置成功,并且访问正常。

image.png

3. 实战

现在我们已经安装和配置好了 Nginx,那我们先来看一下在反向代理这种场景下 Nginx 是如何使用的。首先我们先用 SpringBoot 创建一个 Web 服务。

start.spring.io 初始化一个项目方便我们测试。

image.png

用 Eclipse 或 InteliJ IDEA 打开刚刚初始化好的项目,整个工程的目录如下。

image.png

NginxTestController 中写两个简单的接口,分别是 /hello/nginx/hi/nginx,同时在接口的响应中返回当前程序在监听哪个端口即 serverPort


@RestController public class NginxTestController { @Value("${server.port}") private int serverPort; @RequestMapping(value = "/hello/nginx", method = RequestMethod.GET) public TestResponse getNginx() throws Exception { TestResponse response = new TestResponse(); response.setCode(200); response.setMessage("success"); response.setName("hello nginx"); response.setServerPort(serverPort); return response; } @RequestMapping(value = "/hi/nginx", method = RequestMethod.GET) public TestResponse getIncome() throws Exception { TestResponse response = new TestResponse(); response.setCode(200); response.setMessage("success"); response.setName("hi nginx"); response.setServerPort(serverPort); return response; } } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

application.properties 配置文件中添加监听的端口。


server.port=8090 //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

server.port=9090 //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

使用 maven 分别打包两个监听 8090 和 9090 端口的 Web 服务的 jar 包为 nginxdemo-SNAPSHOT-8090.jarnginxdemo-SNAPSHOT-9090.jar

分别启动两个 server


启动第一个 server java -jar nginxdemo-SNAPSHOT-8090.jar //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

启动第二个 server java -jar nginxdemo-SNAPSHOT-9090.jar //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

在不使用 Nginx 做反向代理的情况下,我们先访问下两个 server 的接口是否都能正常使用,如下图表示均正常。

监听 8090 端口的 tomcat

image.png

监听 9090 端口的 tomcat

image.png

反向代理

  • 规则匹配

我们先来看一下上面讲过的关于访问规则的匹配,在 server 块中添加以下 location。


location =/hello/nginx { deny all; } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

server 块的完整配置如下,修改完成后重新加载 Nginx 配置。


server { listen 9000; server_name localhost; location / { proxy_pass http://localhost:8090; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location =/hello/nginx { deny all; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

由上面的配置可以 /hello/nginx 被拒绝访问,我们在浏览器访问可得到如下图结果:

/hello/nginx 被拒绝访问。

image.png

/hi/nginx 仍然可以访问。

image.png

  • 使用端口号进行反向代理

\#user nobody; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 9000; server_name localhost; location / { proxy_pass http://localhost:8090; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 9001; server_name localhost; location / { proxy_pass http://localhost:9090; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } include servers/*; } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

使用端口进行反向代理比较简单,我们在配置文件中添加两个 server 块,让 Nginx 分别监听 9000 端口和 9001 端口。然后在 location 块中通过 proxy_pass 分别代理到 tomcat 的 8090 端口和 9090 端口。

通过 Nginx 访问 9000 端口,可以看到返回的是 tomcat 8090 端口的内容。

image.png

通过 Nginx 访问 9001 端口,可以看到返回的是 tomcat 9090 端口的内容。

image.png

这样做的目的是,在真实的服务器环境中,我们不可能把所有的端口都开放出去,比如 mysql 常用的 3306 端口,这样会有很大的安全问题,通过 Nginx 的反向代理就可以解决。

  • 使用域名进行反向代理

上面讲过了使用端口进行反向代理,在真实的开发环境中,我们更多的是使用域名或者二级域名来访问某些页面或接口,我们通常是不需要在域名上加上端口号的。这是因为 80 是 http 协议的默认端口。我们在访问 http://baidu.com 时其实是访问 http://baidu.com:80

那么我们来看一下如何使用 Nginx 通过域名来做反向代理。由于我是在本地进行开发测试的,是没有公网的 ip 地址的,这时候怎么让一个域名解析到我自己的 ip 上呢?我们可以修改 hosts 文件。


127.0.0.1 hello.democome.local 127.0.0.1 hi.democome.local //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

以上是我给本机的 hosts 文件添加的两行配置,我们知道是没有 .local 这个域名的,但是加上上面的配置之后当我访问 hello.democome.localhi.democome.local 时,就会解析到我的本机,这样就可以通过 Nginx 进行反向代理了,我们看看具体的 Nginx 配置文件。


\#user nobody; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name hello.democome.local; location / { proxy_pass http://localhost:8090; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name hi.democome.local; location / { proxy_pass https://www.javascriptc.com; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } include servers/*; }

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

以上配置,我们把两个 server 块中监听的端口都改为了 80,然后两个二级域名 hello.democome.localhi.democome.local 分别代理到了 http://localhost:8090http://localhost:9090 两个 web server。

在浏览器访问 http://hello.democome.local/hello/nginx 可以看到可以正常返回 8090 端口的内容。

image.png

在浏览器访问 http://hi.democome.local/hello/nginx 可以看到可以正常返回 9090 端口的内容。

image.png

通过以上测试,我们的配置是生效的。

如果不想使用默认的 80 端口,我们依然可以使用域名加上端口的形式访问,配置如下:


server { listen 9000; server_name hello.democome.local; location / { proxy_pass http://localhost:8090; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

修改完配置重新加载,可以看到通过域名加端口也可以正常访问。

image.png

  • 代理到其他网站

server { listen 80; server_name hi.democome.local; location / { proxy_pass https://www.so.com/; } } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

我们把 server 块改成如下配置,然后重新加载 Nginx 配置,可以发现虽然我们访问的是 hi.democome.local 但是真正返回的页面是 360 搜索的页面,并且域名也不会变化。

image.png

负载均衡

说到负载均衡,那么什么是负载均衡,先来看一下维基百科的定义

负载平衡(Load balancing)是一种计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。 使用带有负载平衡的多个服务器组件,取代单一的组件,可以通过冗余提高可靠性。负载平衡服务通常是由专用软件和硬件来完成。 主要作用是将大量作业合理地分摊到多个操作单元上进行执行,用于解决互联网架构中的高并发和高可用的问题。

总结来说负载均衡就是解决高并发的。假如我们有多台服务器,我们在每台服务器上都跑了相同的应用,当用户访问时,我们希望 Nginx 把用户的请求根据一定的策略转发的不同的服务器,已解决单个服务器访问压力大的问题。

为了测试这个效果,我先把之前打包的 jar 文件上传一个到远程的服务器上,并启动。

我们看一下具体如何配置:


\#user nobody; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream localhost { server 62.234.66.219:8090 weight=1; #远程服务器 server 192.168.0.101:8090 weight=3; } server { listen 80; server_name hello.democome.local; location / { add_header Backend-IP $upstream_addr; proxy_pass http://localhost; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } include servers/*; } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

其中主要是 upstream 块的配置,我配置了两个服务器,其中 62.234.66.219:8090 是腾讯云服务器的地址, 192.168.0.101:8090 是我本机的 ip 地址。策略是按照比重来分别转发到两个服务器上,比例为1:3。关于策略还有很多规则,比如根据 ip hash 等。我们这里只演示 weight 策略。


upstream localhost { server 62.234.66.219:8090 weight=1; #远程服务器 server 192.168.0.101:8090 weight=3; } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

完成好上面的配置执行 nginx -s reload 重新加载配置。继续访问http://hello.democome.local/hello/nginx

如下图,本次请求来自192.168.0.101

image.png

如下图,本次请求来自 62.234.66.219

image.png

通过多次请求我们发现,转发到各个服务器的比例基本是 1:3,以上说明我们配置的负载均衡策略是生效的。

https证书配置


server { listen 443 ssl; server_name democome.com www.democome.com; #配置域名 ssl_certificate /etc/letsencrypt/live/democome.com/fullchain.pem; #配置证书位置 ssl_certificate_key /etc/letsencrypt/live/democome.com/privkey.pem; #配置证书位置 location /{ #反向代理配置 proxy_pass http://localhost:8080; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } //JS中文网 – 前端进阶资源分享 https://www.javascriptc.com/ 趣聊CSS系列

配置证书比较简单,首先监听 443 端口,然后执行证书位置即可。

更多推荐

免费 https 证书申请 letsencrypt

原文链接:九点下班


推荐文章:
iOS中的3D变换(二)
iOS中的3D变换(一)
WebSocket 双端实践(iOS/ Golang)
今天我们来聊一聊WebSocket(iOS/Golang)
用 Swift 进行贝塞尔曲线绘制
Swift 5.1 (11) – 方法
Swift 5.1 (10) – 属性
iOS App后台保活
奇舞周刊

作者:QiShare
链接:https://juejin.im/post/6844904082067423246

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「IT平头哥联盟」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:Nginx 入门实战

链接:https://www.javascriptc.com/4171.html

« LeetCode 031. 下一个排列
Docker安装nginx以及配置nginx https域名»
Flutter 中文教程资源

相关推荐

QR code