前言
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,以其占有内存少、并发能力强等特点,被广泛应用于各种网站中。本文所述过程为必要环节和主要参数,介绍的Nginx的安装和使用步骤都是干货。至于细节和扩展知识,各位可以额外去学习下。
Nginx的安装
EPEL仓库
sudo yum install epel-release
如果在尝试安装 epel-release 时遇到“No package epel-release available.”的错误:
[root@localhost ~]# sudo yum install epel-release
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
No package epel-release available.
Error: Nothing to do
这通常意味着你的 CentOS 系统没有配置为访问包含 EPEL 仓库的源。EPEL(Extra Packages for Enterprise Linux)是一个由 Fedora 社区构建的、包含了许多企业级 Linux 发行版(如 CentOS)可能不包含的额外软件包的仓库。
要解决这个问题,你可以按照以下步骤操作:
1,检查 CentOS 版本
首先,确认你的 CentOS 版本。你可以通过运行以下命令来查看:
cat /etc/centos-release
2,手动添加 EPEL 仓库
如果你的 CentOS 版本较新(如 CentOS 8 或更高),你可能需要手动添加 EPEL 仓库的 URL。对于 CentOS 8,EPEL 仓库已经不再由官方维护,但你可以使用第三方仓库如 PowerTools 或考虑升级到 CentOS Stream。不过,对于 CentOS 7 及其之前的版本,你可以手动添加 EPEL 仓库。
对于 CentOS 7,你可以使用以下命令添加 EPEL 仓库的 URL:
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
也可以通过
sudo yum localinstall --nogpgcheck https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
或者直接:
sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
请注意,上述 URL 中的 7
表示 CentOS 7。如果你使用的是其他版本的 CentOS,请相应地更改 URL 中的版本号。 ,
3,清理 YUM 缓存并尝试再次安装
在添加 EPEL 仓库的 RPM 包后,你可能需要清理 YUM 的缓存,以确保它能够识别新添加的仓库:
sudo yum clean all
sudo yum makecache
然后,再次尝试安装 epel-release
(但实际上,如果你已经通过 RPM 包安装了它,这一步可能是多余的):
sudo yum install epel-release
4,检查仓库列表
如果 epel-release
已经安装,你可以通过以下命令检查仓库列表,确保 EPEL 仓库已经被添加:
yum repolist
在输出中,你应该能看到类似 epel/x86_64
的仓库。,
5,尝试安装 Nginx
现在,EPEL 仓库应该已经设置好了,你可以尝试再次安装 Nginx:
sudo yum install nginx
6,检查 SELinux 状态(如果适用)
如果你的系统启用了 SELinux,并且 Nginx 安装后无法正常工作,请检查 SELinux 的状态并适当调整其策略。这个后面再提,这确实是很多人遇到的坑,包括我。
Nginx的使用
安装好 Nginx 后,你可以通过几个基本步骤来开始使用它。Nginx 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。这里我们主要关注其作为 Web 服务器的使用。
1. 启动 Nginx
首先,你需要启动 Nginx 服务。在 CentOS 7 上,你可以使用 systemctl
命令来管理 systemd 服务,包括 Nginx。
sudo systemctl start nginx
这个命令会启动 Nginx 服务。如果你想让 Nginx 在系统启动时自动启动,可以使用:
sudo systemctl enable nginx
2. 检查 Nginx 状态
要检查 Nginx 是否正在运行,你可以使用以下命令:
sudo systemctl status nginx
这个命令会显示 Nginx 服务的状态,包括它是否正在运行。
3. 访问 Nginx 默认页面
安装并启动 Nginx 后,默认情况下,它会在你的服务器上监听 80 端口(HTTP)和/或 443 端口(HTTPS,如果你配置了 SSL/TLS)。你可以通过在浏览器中输入服务器的 IP 地址或域名(如果已配置 DNS)来访问 Nginx 的默认页面。
例如,如果你的服务器 IP 地址是 192.168.1.100
,你应该在浏览器中输入 http://192.168.1.100
来查看 Nginx 的默认欢迎页面。
4. 配置 Nginx
Nginx 的配置文件通常位于 /etc/nginx/
目录下。主要的配置文件是 nginx.conf
,但你也可以在 /etc/nginx/conf.d/
目录下创建额外的配置文件来管理不同的网站或应用。
-
编辑配置文件:使用文本编辑器(如
nano
、vim
或vi
)编辑 Nginx 配置文件。例如,要编辑主配置文件,你可以使用:sudo nano /etc/nginx/nginx.conf
或者,如果你正在编辑一个特定站点的配置文件,它可能位于
/etc/nginx/conf.d/
目录下:sudo nano /etc/nginx/conf.d/your_site.conf
重新加载 Nginx 配置:在编辑配置文件后,你需要重新加载 Nginx 以应用更改。这可以通过以下命令完成:
sudo systemctl reload nginx
或者,你也可以使用
nginx
命令的-s reload
选项:sudo nginx -s reload
5. 管理 Nginx 网站
对于每个你想要通过 Nginx 托管的网站,你都需要在 Nginx 的配置文件中设置一个
server
块。这个块将定义如何处理对该网站的请求,包括如何处理不同的 URL 路径、如何记录访问日志等。6. 使用 Nginx 作为反向代理
Nginx 也可以配置为反向代理服务器,将传入的请求转发到后端的服务器或应用。这通常用于负载均衡、提高性能、提供安全性或隐藏后端服务器的细节。
7. 监控和日志
Nginx 提供了详细的访问和错误日志,这些日志通常位于
/var/log/nginx/
目录下。你可以使用这些日志来监控网站的性能、诊断问题或分析访问模式。
Nginx的负载均衡
在Nginx的配置中,除了定义upstream块来指定后端服务器组之外,通常还需要确保server {}块中的location / {}部分正确地将请求代理到这个后端服务器组。
以下是一个简化的Nginx配置示例,来实现nginx+spring boot实现反向代理和负载均衡的基本设置。
步骤 1: 确定后端Spring Boot实例的地址
首先,您需要知道每个Spring Boot实例的IP地址和端口号。例如:
- 实例1:
192.168.1.10:8080
- 实例2:
192.168.1.11:8080
- 实例3:
192.168.1.12:8080
并且每个spring boot里面加个controller,做个简单的get打印:
@Controller
public class BasicController {
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "我是1号";
//return "我是2号";
//return "我是3号";
}
}
步骤 2: 编写Nginx配置文件
在Nginx的配置文件中(通常是nginx.conf
,或者是在sites-available/
目录下的某个文件,取决于您的Nginx安装和配置方式),您需要定义upstream
块和server
块。
Nginx配置文件示例:
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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 /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
upstream demo {
least_conn; # 指定最少连接负载均衡算法
server 172.16.8.59:8081 weight=3;
server 172.16.8.59:8082;
server 172.16.8.59:8083 down;
# 可以继续添加更多的server指令...
}
server {
listen 81;
server_name 0.0.0.0;
location / {
proxy_pass http://demo; # 将请求转发到demo上游服务器组,使用最少连接算法
# 其他与代理相关的配置...
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# ...
}
# 其他location块...
}
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
关于proxy_set_header
在Nginx的proxy_set_header
指令中,你通常会设置HTTP请求头,这些请求头随后会被发送到上游服务器(例如,另一个Web服务器、API或任何Nginx作为反向代理时转发的目标)。proxy_set_header
指令允许你覆盖或添加请求头,这些请求头原本可能由客户端发送,或者完全由Nginx自己生成。
proxy_set_header
指令的基本语法如下:
proxy_set_header <header-field> <value>;
# 设置Host请求头为原始请求中的Host值
proxy_set_header Host $host;
# 设置X-Real-IP请求头为客户端的真实IP地址(如果Nginx是反向代理)
proxy_set_header X-Real-IP $remote_addr;
# 设置X-Forwarded-For请求头,以包含客户端的原始IP地址(如果Nginx是反向代理)
# 注意:如果请求已经包含X-Forwarded-For头,Nginx会追加客户端IP到该头,而不是覆盖它
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 设置X-Forwarded-Proto请求头为原始请求使用的协议(http或https)
proxy_set_header X-Forwarded-Proto $scheme;
$host
、$remote_addr
、$proxy_add_x_forwarded_for
和$scheme
是Nginx变量,它们分别代表原始请求的Host头、客户端的IP地址、通过代理链的客户端IP地址列表(如果适用),以及原始请求使用的协议(http或https)。
步骤 3: 理解proxy_pass
和upstream
的关系
proxy_pass
指令用于指定请求应该被转发到的地址。在这个例子中,它被设置为http://spring_boot_app
,其中spring_boot_app
是在Nginx配置中定义的upstream
块的名称。upstream
块定义了后端服务器组,Nginx会根据这个块中的服务器列表来转发请求。Nginx会根据配置的负载均衡算法(默认为轮询)来选择服务器。proxy_pass
中的URL格式是http://
或https://
加上upstream
块的名称。这个名称与最终用户看到的URL无关;用户看到的是Nginx监听的地址和端口(在这个例子中是http://example.com
或http://www.example.com
),而Nginx负责将请求转发到upstream
块中定义的服务器。
步骤 4: 设置DNS和/或Web服务器(可选)
- 如果您的域名(如
example.com
)还没有指向您的Nginx服务器的IP地址,您需要在DNS提供商处设置A记录或CNAME记录,将域名解析到Nginx服务器的IP地址。 - 如果您使用的是虚拟主机提供商,并且Nginx服务器是该提供商托管的一部分,那么您可能需要在提供商的控制面板中设置域名到Nginx服务器的映射。
- 在某些情况下,您可能还需要在Nginx服务器上配置SSL/TLS证书,以便通过HTTPS提供加密的连接。这通常涉及到在Nginx配置文件中添加
ssl_certificate
和ssl_certificate_key
指令,并将监听端口更改为443。
步骤 5: 重启Nginx以应用更改
在修改了Nginx配置文件后,您需要重启Nginx服务以使更改生效。这通常可以通过运行sudo systemctl restart nginx
(在基于systemd的系统中)或使用Nginx的特定命令来完成。
步骤6:打开nginx服务器的地址及绑定的端口
我们可以发现,http://demo:81/hello的结果,会分别出现“我的1号”、“我是2号”……
实验成功!
一个错误:
有时候我们会发现可以在nginx上curl服务端,但是就是访问不了,提示502。在nginx的access日志提示:
[22/Jul/2024:10:58:56 +0800] "GET /favicon.ico HTTP/1.1" 502 559 "http://192.168.226.218:81/hello" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0" "-"
到了error日志里看到:
2024/07/22 10:58:56 [crit] 96892#96892: *6 connect() to 172.16.8.59:8083 failed (13: Permission denied) while connecting to upstream, client: 192.168.226.1, server: 0.0.0.0, request: "GET /hello HTTP/1.1", upstream: "http://172.16.8.59:8083/hello", host: "192.168.226.218:81"
2024/07/22 10:58:56 [crit] 96892#96892: *6 connect() to 172.16.8.59:8082 failed (13: Permission denied) while connecting to upstream, client: 192.168.226.1, server: 0.0.0.0, request: "GET /hello HTTP/1.1", upstream: "http://172.16.8.59:8082/hello", host: "192.168.226.218:81"
2024/07/22 10:58:56 [crit] 96892#96892: *6 connect() to 172.16.8.59:8081 failed (13: Permission denied) while connecting to upstream, client: 192.168.226.1, server: 0.0.0.0, request: "GET /hello HTTP/1.1", upstream: "http://172.16.8.59:8081/hello", host: "192.168.226.218:81"
2024/07/22 10:58:56 [error] 96892#96892: *6 no live upstreams while connecting to upstream, client: 192.168.226.1, server: 0.0.0.0, request: "GET /favicon.ico HTTP/1.1", upstream: "http://demo/favicon.ico", host: "192.168.226.218:81", referrer: "http://192.168.226.218:81/hello"
错误日志中多次出现 connect() to ... failed (13: Permission denied)
,这通常表明 Nginx 进程没有足够的权限去访问指定的端口或 IP 地址。
首要排查SELinux/AppArmor 状态
# 对于 SELinux
getenforce
# 如果启用了 SELinux,并且您认为是 SELinux 导致的问题,可以尝试临时将其设置为宽容模式
setenforce 0
# 然后再次尝试请求
# 对于 AppArmor(如果适用)
sudo aa-status
# 查看 AppArmor 的策略和状态,并根据需要进行调整
基本上我们发现getenforce如果输出是 Enforcing
,那么 SELinux 正在强制执行其策略。
为了测试是否是 SELinux 导致的问题,您可以暂时将其设置为宽容模式(Permissive),这样 SELinux 仍然会记录违规行为,但不会阻止它们:
#大部分问题来源于此
setenforce 0
其次检查并修改防火墙规则:
# 对于 iptables
sudo iptables -L
# 查看现有的规则,并添加允许 Nginx 访问上游服务器的规则(如果需要)
# 对于 firewalld
sudo firewall-cmd --list-all
# 查看现有的规则,并使用 firewall-cmd 添加新的规则
负载均衡的策略
在Nginx中,当配置为反向代理或负载均衡器时,可以通过不同的负载均衡策略来分配进入的流量到后端服务器(也称为上游服务器或节点)。这些策略帮助实现高可用性、负载均衡和故障转移。以下是一些常见的Nginx负载均衡策略和它们如何工作的概述,包括在节点宕机后的自动转移机制。
1. 轮询(round-robin)
默认策略:Nginx按照配置文件中列出的顺序,将请求依次发送到服务器。当达到列表末尾时,它又会从头开始。
流量负载:均衡地分配请求到每个服务器。
节点宕机:如果某个服务器宕机,Nginx会自动停止向其发送请求,直到它恢复在线。这种自动转移是Nginx负载均衡的一个内置特性,不需要额外的配置。
2. 权重(weight)
配置方式:在upstream
块中,为每个服务器指定一个weight
参数,以控制其接收到的请求数量比例。
流量负载:根据权重分配请求,权重越高的服务器接收到的请求越多。
节点宕机:与轮询类似,如果权重较高的服务器宕机,Nginx会自动将其从负载均衡池中移除,并将请求分配给其他在线服务器。
3. IP哈希(ip_hash)
配置方式:在upstream
块中,使用ip_hash
指令。
流量负载:根据客户端IP地址的哈希值来分配请求到固定的服务器。这意味着来自同一客户端的所有请求都将被发送到同一个服务器(只要该服务器在线)。
节点宕机:如果客户端被分配到的服务器宕机,Nginx会尝试将该客户端的后续请求发送到该服务器组中的另一个服务器。然而,由于IP哈希是基于客户端IP的,因此这种转移可能会导致会话不一致性(特别是如果后端服务器维护会话状态)。
4. 最少连接(least_conn)
配置方式:在upstream
块中,使用least_conn
指令(注意:这个指令在一些Nginx版本中可能不是直接可用的,可能需要通过第三方模块或Nginx Plus来实现)。
流量负载:将请求发送到当前连接数最少的服务器。这有助于避免过载某些服务器,特别是在某些服务器处理请求比其他服务器更快的情况下。
节点宕机:与轮询和权重类似,如果某个服务器宕机,Nginx会自动停止向其发送请求,并将请求分配给其他在线且连接数较少的服务器。
5. 自定义策略(如fair、url_hash等)
Nginx还支持通过第三方模块实现更复杂的负载均衡策略,如fair
(根据服务器的响应时间和其他因素来分配请求)和url_hash
(根据请求的URL的哈希值来分配请求)。这些策略可能需要额外的配置和依赖项。
总结
Nginx的负载均衡功能非常强大,提供了多种策略来分配流量和处理节点宕机。在选择负载均衡策略时,应考虑到应用程序的具体需求,如会话一致性、服务器性能差异和故障转移机制。在大多数情况下,Nginx的自动故障转移机制足以处理节点宕机情况,而无需额外的配置。