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

推荐订阅源

The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
T
Threatpost
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
PCI Perspectives
PCI Perspectives
T
The Exploit Database - CXSecurity.com
Y
Y Combinator Blog
雷峰网
雷峰网
爱范儿
爱范儿
The Hacker News
The Hacker News
Last Week in AI
Last Week in AI
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
S
Securelist
宝玉的分享
宝玉的分享
L
LangChain Blog
O
OpenAI News
AI
AI
P
Privacy International News Feed
L
LINUX DO - 最新话题
D
DataBreaches.Net
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
M
MIT News - Artificial intelligence
Security Archives - TechRepublic
Security Archives - TechRepublic
月光博客
月光博客
博客园 - 【当耐特】
T
Tailwind CSS Blog
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
Jina AI
Jina AI
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
Webroot Blog
Webroot Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Blog — PlanetScale
Blog — PlanetScale
MyScale Blog
MyScale Blog
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog

胡涂说

当心流量别被 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 纪元 凡所有相,皆是虚妄 马斯克的故事与模式 纳瓦尔的智慧 当魔法消失时 人生无论怎么度过都像是浪费 我们都是新穷人 代码、法律和自由软件 乾隆的性格 当下我们还需要启蒙吗? 云门胡饼赵州茶 上海周末骑行:从浦东到外白渡桥 如何选择图书译本? No.13: 周刊的周刊 读书日,推荐些童话和小说 学习邓小平的智慧 给博客换了套新评论系统 我所理解的存在主义 心经说了什么 觉悟之道就是活在当下 巨人的笔记 从零到百亿美金之路 人生如逆旅,我亦是行人 和自己非暴力沟通 听斯蒂芬·金谈写作 行不尽,行不尽,一路青山 周刊第12期:第一次十字军东征 周刊第11期:玄奘之路 周刊第十期:敦煌 周刊第九期:卡片盒笔记法 爸爸是最聪明的 Ruby 编程语言入门 影响人类命运的是什么? 周刊第八期:如何应对公开错误 周刊第七期:如何学习 周刊第六期 周刊第五期 只买书:一个失败的微信小程序产品 改变世界的一次代码提交 如何成为一名黑客 通往开源之路 空山不见人 如何做好演讲 “人生在世,永远也不该演戏作假” 周刊第四期 大卫四岁读的书 宇宙就是一个蛋 周刊第三期 周刊第二期 周刊开刊 阅读开源代码小技巧 重学C语言 英国随记 变成神的动物 人类伟大的时刻 最著名的黑客 《巨婴国》读后 若为自由故 买房记 答案在风中飘 陪产记 自由的代价 谈一谈英语学习 读《霍乱时期的爱情》 简洁 嵌套的梦 四月莎士比亚 七律三首 从明天起,做一个Scrum Master 不能承受的生命之轻 我是丽莎呀 爱美丽、黑暗王子和豌豆公主 诗歌与烟台
自建博客 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 官方文档