惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
A
About on SuperTechFans
The GitHub Blog
The GitHub Blog
U
Unit 42
H
Hackread – Cybersecurity News, Data Breaches, AI and More
云风的 BLOG
云风的 BLOG
IT之家
IT之家
MyScale Blog
MyScale Blog
V
Visual Studio Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
I
InfoQ
博客园 - 司徒正美

胡涂说

当心流量别被 Agent 都吃了 当 AI 构建自己 阿嬷 ā mó Bun 要从 Zig 迁移到 Rust ? 好奇心周刊第25期: 如何让AI写好代码 好奇心周刊第24期: 关于AI编程的一些体会和设想 云何降伏其心 好奇心周刊第23期: Claude Code 氛围编程初体验 好奇心周刊第22期: 纳瓦尔谈人生 不确定性世界的生存策略 好奇心周刊第21期: 推理模型的构建与未来 好奇心周刊第20期: 从四个方面了解Palantir 周刊第19期: 一起学习 MCP 周刊第18期: 什么是理工科思维 周刊第17期: 如何构建智能体(Agent) 周刊第16期: Andrej Karpathy 讲 AI 读《毛泽东传》对个人的启发 周刊第15期:Nat Friedman 和 Derek Sivers 的自我介绍 周刊第14期:罗振宇和《罗辑思维》 我看《哪吒》 为什么写作? 心猿意马 从铁幕到硅幕 银弹飞过先锋大厦 从神经网络到 Hugging Face 在大理,听打雷 Git 纪元 凡所有相,皆是虚妄 马斯克的故事与模式 纳瓦尔的智慧
自建博客 Nginx 基本配置
胡涂说 · 2022-04-10 · via 胡涂说

本博客虽然是静态博客,为了提升国内访问速度,从 GitHub Pages 上迁到了云主机,用 Nginx 搭建的静态网站服务。最近在整理博客站点时发现如果输错 URL 不是返回404页面,而是返回500错误,经定位发现是 Nginx 配置的问题。因此周末花了一天时间好好看了下 Nginx 相关配置指导,正好也做一个学习总结。末尾我会说明下这个问题以及修复方法。

Nginx 介绍

Nginx 是俄罗斯程序员 Igor Sysoev 于2004年开发的 web 服务器软件。2019年 Nginx 被 F5 以6.7亿美元的价格收购。有两件关于 Nginx 的知名新闻,一则是2019年 Rambler 公司(也是 Igor 开发 Nginx 时所服务的公司)起诉 Igor 及 F5 公司,声称他们侵犯了 Rambler 的知识产权。该事件引发 IT 界强烈争议而后变成“协商解决”而暂停。另一则是前段时间俄罗斯出兵乌克兰,F5 宣布从俄罗斯撤出业务并停止接纳俄罗斯对 Nginx 开源贡献。

Nginx 目前已超过 Apache 成为占有率最高的 web 服务器软件,市场占有率超过30%,相对老牌的 IIS 和 Apache 发展速度很快。

nginx market share

Nginx 可以做静态站点 HTTP/HTTPS 服务、反向代理、负载均衡。关于反向代理(Reverse Proxy)解释如下图示:我们在访问互联网时可以设置代理(Proxy),这样客户端对互联网的请求和数据接收是通过这个代理转发的。而所谓反向代理则是来转发互联网上用户对服务器的请求,Nginx 则提供了灵活的配置和高效的转发能力。

proxy-vs-reverse-proxy

安装及配置

通过包管理工具很容易安装 Nginx, 如 Ubuntu: sudo apt install nginx 或 Mac: brew install nginx. 安装好后启动 Nginx 服务,即可以通过服务器 IP 访问 Nginx 服务。

Nginx 配置文件结构

打开 Nginx 安装目录可以看到 Nginx 的配置文件 nginx.conf ,一般在 /etc/nginx 路径下。Nginx 配置脚本中 # 开头为注释,其他为配置指令(Nginx 术语为 directive)。

Nginx 配置文件主要分成三块(Nginx 术语叫 context):全局块(main context)、events 块、http 块。events 块 和 http 块都被包含在 {} 中,没有没包含在 {} 中的配置指令就是全局块的内容。

全局块中主要是一些 Nginx 服务器的全局配置指令,如 log 日志存放位置、Nginx PID 文件路径、Nginx 运行 worker 进程数等。如上例中从配置文件开头到 events 块之间的内容为全局块(大部分被注释)。

events 块中配置影响 Nginx 服务器与用户的网络连接性能。如上例中 worker_connections 1024 表示一个 worker process 最大的连接数为1024,注意这个数字不能超过系统支持打开的最大文件数,也不能超过单个进程支持打开的最大文件数。

查看 Linux 下打开文件数限制:cat /proc/sys/fs/file-nr 。修改文件 /etc/sysctl.conf

查看 Linux 下单进程打开文件数限制:ulimit -n 。 修改文件:/etc/security/limits.conf

搭建博客服务器主要需要修改 http 块中的配置指令。

http 块配置

http 块中还可以包含 server 块,除此之外是 http 块的全局配置,包含连接超时时间、cache设置、传输文件压缩配置等。

上例中 include servers/* 表示可以将 servers 目录下的配置文件都包含进来,如果有多个服务配置,可以将这些配置分布在不同配置文件中,便于管理。

Server 块的典型配置如:

listen 指令表示服务监听的IP 和端口, default_server 表明这个 server 块是默认的服务。

例如 listen 127.0.0.1 表示只监听来自 127.0.0.1 这个 IP 并请求80端口的请求(不指定端口则默认为 80);而 listen 8080 表示监听来自所有 IP 并请求 8080 端口的请求。

第二行的 listen [::]:80 表示支持 IPv6,监听来自于 IPv6 的连接。

server_name 指令配置虚拟主机的名称,可以有多个名称并列,如:

root 指令配置请求寻找资源的根目录;该指令可以在 http、server 或 location 块中设置,一般在 server 和 location 块中设置。

error_page 指令设置自定义错误页面来代替 Nginx 默认提供的错误界面,比如例子中的error_page 404 /404.html 表示用根目录的 404.html 页面来作为 404 页面。

location 块配置

配置最为灵活的是 location 块,它表示了 Nginx 对于不同 URI 请求的特定处理配置,按 URI 的规则匹配来处理。语法规则如下:

location 中的 uri 有两种,一种是字符串前缀,一种是正则表达式。上述语法中 [] 方括号中为修饰可选项,其中 =^~ 使用字符串前缀,~~* 使用正则表达式。如果不加该可修饰, Nginx 会将配置 uri 当做字符串前缀与请求 URI 进行匹配。

在定义了一组 location 时,Nginx 的匹配过程如下:

Nginx 首先检查使用前缀字符串定义的 location。在这些 location 中,具有最长匹配前缀的 location 被选中并被记住。然后检查正则表达式,按照它们在配置文件中出现的顺序。正则表达式的搜索在第一次匹配时终止,并使用相应的 location。如果没有找到匹配的正则表达式,那么就使用先前记忆的最长匹配前缀的 location。

Nginx 对 location 的匹配规则优先级如下:

  • 精确匹配 **= :**请求的 URI 与 location 块中配置的 uri 完全一致,如果匹配则立刻停止向下搜索并使用该 location 处理。注意该匹配会忽略 URL 中的 querystring (即 ? 及之后的部分)
  • 前缀匹配 **^~ :**如果最长匹配前缀找到的是这个 location,那么就使用该 location 并立刻停止后续的正则搜索。
  • 按配置文件中的顺序进行正则匹配 ~区分大小写~*不区分大小写)。
  • 匹配不带任何修饰的前缀匹配。

SSL 配置

博客网站需要支持 HTTPS 协议的话需要对有 SSL 证书并且在 Nginx 上做 SSL 配置。(如果用的是 GitHub Pages 或 Netlify 等服务就不用这么费事了。)证书可以在云厂商免费申请,或用 Let’s Encrypt 生成,这里就不赘述。证书下载后,可以开始 Nginx SSL 配置。

在配置文件中增加一个 SSL server 块:

可以看出,除了listen 指令和增加了 SSL 指令部分外,其他跟非 SSL 配置是一样的。

listen 443 ssl http2 监听 SSL 默认端口 443,以及支持 HTTP/2 协议。

增加的几行 SSL 配置指令:

ssl_certificatessl_certificate_key 分别指定证书和证书私钥所存放的位置。

ssl_session_cachessl_session_timeout 设置 session 缓存大小和超时时间。

ssl_ciphers 设置选择加密算法套件,其中 !aNULL!MD5 前面的 ! 表明不选用 aNULL 和 MD5 类算法套件,而 HIGH 代表了一组高强度加密算法,可以通过如下命令查看算法清单:

ssl_prefer_server_ciphers on 表明设置协商加密算法时,优先使用服务端的加密套件,而不是客户端浏览器的加密套件。

如果想让用户访问 http 链接也指向 https 时,需要在监听 80 的 server 块配置 rewrite 或 return 301 重定向(return 301 性能更优一些)。

本地调试

本机安装 Nginx 就可以配置静态服务器进行调试,Mac 和 Linux 都比较方便。只是如果要配置 SSL 的话需要用到 mkcert 这个工具来制作本地签名证书。在 Mac 下通过命令 brew install mkcert 安装,然后运行命令 mkcert -install 来创建本地 CA(授权中心),并将该 CA 加入本机可信 CA (需要管理员账号授权)。

接着,就可以生成多域名证书了,该证书会输出到当前目录下。Nginx 调试中可以直接使用此证书。

问题实例

问题描述

访问不存在的页面时返回的不是 404 页面而是 500 错误页面,比如浏览器中输入 https://hutusi.com/hello 则返回 500 错误。

问题原因

查看 Nginx 日志,发现报了这条错误:

大概是 rewrite 进入死循环了。打开配置文件,发现是这么写的:

这里的逻辑:如果找不到页面(if 条件),则重定向到新地址(在原地址后追加 .html)。其中,rewrite 指令的前两个参数分别是原 URI 和替换后的 URI,^(.*)$ $1 都是正则和正则替换语法。最后的参数 last 表示停止处理当前的 rewrite 并开始根据替换后的 URI 搜索新的 location 匹配。

原来这样配置的目的主要是因为博客文章生成的 URL 为 [https://hutusi.com/articles/rms](https://hutusi.com/articles/rms).html 这样,而我不想再访问时加 .html ,希望更简洁的 URL 类似 https://hutusi.com/articles/rms ,因此加了这段 rewrite 配置在匹配不到 URL 时重定向到追加了 .html 的 URL 页面。但当访问到真不存在的 URL 时,根据逻辑将追加 .html ,依然匹配不到,再继续追加,也就导致了死循环错误。

解决方法

找到原因,解决方法就很简单了,不再用 if 条件判断(官网也不建议用 if ),而是改用 location 的正则匹配:

附: Nginx 官方文档