Nginx支持SNI证书,已经ssl_server_name的使用
整理了一些网上的资料,这里记录一下,供大家参考
什么是SNI?
传统的应用场景中,一台服务器对应一个IP地址,一个域名,使用一张包含了域名信息的证书。随着云计算技术的普及,在云中的虚拟机有了一个IP,对应多个域名,使用多张证书的应用场景,SNI技术应运而生。SNI(Server Name Indication),即实现了一个服务器使用多个域名证书的TLS扩展,支持用户配置多个域名证书。
SNI请求特点
HTTP请求的Host字段在请求的Header中。发起HTTPS请求时,在TLS握手阶段,还无法进行HTTP数据的解析,此时TLS协议的Client Hello字段新增了一个Server Name字段,请求的客户端可以通过这个字段填充请求的Host信息,而服务端在TLS握手阶段就可以选择请求处理的证书,实现SNI的功能。
各种工具对SNI的支持各种工具对SNI的支持
https://en.wikipedia.org/wiki/Server_Name_Indication
![]()
(1)主流的浏览器 可以理解为客户端工具

(2)curl和wget之类的命令行工具 可以理解为客户端工具
![]()
![]()
curl和nginx关于SNI一些细节
已知的问题:curl和jdk'版本过低(客户端不支持SNI)','导致'ssl握手的'SNI'问题
(3)库和编程语言 可以理解为客户端工具

(4)web服务器 可以理解为服务端

默认SNI是'开启的'
Nginx支持的配置
Nginx支持SNI,允许在同一个TLS服务端口下,配置不同的域名,用户通过请求不同的证书域名,可返回相应的upstream响应结果。
本示例配置了一个证书域名为“lwl.test.com”的单向认证代理服务,一个证书域名为“lwl.default.com”的双向认证代理服务,使用相同的443端口,具体配置如下:
# Settings for a TLS enabled server.
upstream lwl.test.com {
server 192.168.58.196;
}
upstream default {
server 192.168.58.195;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test.com;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/lwl.test.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test.com/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;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test.com;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.default.com;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/lwl.default.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.default.com/server.key;
ssl_client_certificate /etc/nginx/ssl_sni/private/ca.crt;
ssl_verify_client on;
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;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://default;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
单向认证测试
基于以上配置,使用域名为“lwl.test.com”的证书进行单向认证的HTTPS访问,请求如下:
# curl https://lwl.test.com:443 --cacert /etc/nginx/ssl_sni/private/ca.crt
返回的响应为:
![]()
同时对当前的HTTPS请求进行抓包,可以看到,请求TLS握手阶段Client Hello请求中,包含了Server Name为lwl.test.com的字段:

双向认证测试
基于以上配置,使用域名为“lwl.default.com”的证书进行双向认证的HTTPS访问,请求如下:
# curl --cert /etc/nginx/ssl_sni/users/client.crt:123456 --key /etc/nginx/ssl_sni/users/client.key 'https://lwl.default.com:443' --cacert /etc/nginx/ssl_sni/private/ca.crt
返回的响应为:
![]()
同时对当前的HTTPS请求进行抓包,可以看到,请求TLS握手阶段Client Hello请求中,包含了Server Name为lwl.default.com的字段:

至此验证了Nginx可同时支持多个TLS证书的功能。
多证书配置
为支持多个SNI证书,一种Nginx配置文件形式为,每个证书配置单独一个server段,此处以两个单向认证证书,一个双向认证证书为例,配置如下:
# Settings for a TLS enabled server.
upstream lwl.test.com {
server 192.168.58.196;
}
upstream lwl.test1.com {
server 192.168.58.194:8081;
}
upstream default {
server 192.168.58.195;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test.com;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/lwl.test.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test.com/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;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test.com;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.test1.com;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/lwl.test1.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.test1.com/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;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://lwl.test1.com;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lwl.default.com;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/lwl.default.com/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/lwl.default.com/server.key;
ssl_client_certificate /etc/nginx/ssl_sni/private/ca.crt;
ssl_verify_client on;
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;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://default;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
可以看到,随着加载证书个数的增加,Nginx配置篇幅增长较大,不利于配置维护。
优化的配置方式
启用了sni的nginx,如下变量会被赋值
$ssl_server_name
默认SNI是'开启的'
检查'nginx server端'是否支持SNI扩展协议:'nginx -V'

在1.7.0版本开始,Nginx支持通过$ssl_server_name 变量获取TLS中的Server Name,我们可以据此结合map映射指令,提升配置的重用度,一种优化后的配置方式如下:
例子1:
# Settings for a TLS enabled server.
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
map $ssl_server_name $ssl_string {
lwl.test.com lwl.test.com;
lwl.test1.com lwl.test1.com;
default lwl.default.com;
}
upstream lwl.test.com {
server 192.168.58.196;
}
upstream lwl.test1.com {
server 192.168.58.194:8081;
}
upstream lwl.default.com {
server 192.168.58.195;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name $ssl_string;
root /usr/share/nginx/html;
ssl_certificate /etc/nginx/ssl_sni/server/$ssl_string/server.crt;
ssl_certificate_key /etc/nginx/ssl_sni/server/$ssl_string/server.key;
include /etc/nginx/default.d/*.conf;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Cookie $http_cookie;
proxy_pass http://$ssl_string;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
例子2:
stream {upstream test {server 127.0.0.1:50001;} map $ssl_server_name $sni_string {test1.www.local test1;test2.www.local test2;test3.www.local test3;default test1;}map $ssl_server_name $sni_string445 {test1.www.local test4451;test2.www.local test4452;test3.www.local test4453;default test4451;}server {listen 444 ssl;ssl_certificate /data/sni/sni_${sni_string}.cer;ssl_certificate_key /data/sni/sni_${sni_string}.key;proxy_pass test;}server {listen 445 ssl;ssl_certificate /data/sni445/sni_${sni_string445}.cer;ssl_certificate_key /data/sni445/sni_${sni_string445}.key;proxy_pass test;}}
注意,如果希望map命令支持host的最长匹配与正则,需要再添加hostnames关键字。
Module ngx_http_map_module
map命令的本质,可以理解为通过旧的变量定义出了一个新的变量。
模拟tcp客户端的方法:
openssl s_client -connect t9:5000 -CAfile ~/Keys/https/root/root.cer -servername test2.www.local
[openssl][nginx] 使用openssl模拟ssl/tls客户端测试nginx stream
模拟http客户端的方法:
curl --cacert ~/Keys/https/root/root.cer -vvvv https://test1.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test2.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test3.tls.local/ curl --cacert ~/Keys/https/root/root.cer -vvvv https://test3.www.local/
结束语
本文通过结合Nginx的 $ssl_server_name 变量与map指令,提供了一种支持多个SNI证书配置的实现方式,提高了配置维护的重用度。
参考
https://www.nginx.org.cn/article/detail/12416
https://www.cnblogs.com/hugetong/p/11727275.htmlhttps://blog.csdn.net/wzj_110/article/details/110149984
相关文章:
Nginx支持SNI证书,已经ssl_server_name的使用
整理了一些网上的资料,这里记录一下,供大家参考 什么是SNI? 传统的应用场景中,一台服务器对应一个IP地址,一个域名,使用一张包含了域名信息的证书。随着云计算技术的普及,在云中的虚拟机有了一…...
Hive【Hive(六)窗口函数】
窗口函数(window functions) 概述 定义 窗口函数能够为每行数据划分 一个窗口,然后对窗口范围内的数据进行计算,最后将计算结果返回给该行数据。 语法 窗口函数的语法主要包括 窗口 和 函数 两个部分。其中窗口用于定义计算范围…...
Met no ‘TRANSLATIONS’ entry in project
这里写自定义目录标题 问题描述:解决方法: 问题描述: 多工程项目,执行完update Translation生成了.ts文件,也用翻译工具翻译完了,执行release时,报错“Met no ‘TRANSLATIONS’ entry in proje…...
Leetcode901-股票价格跨度
一、前言 本题基于leetcode901股票价格趋势这道题,说一下通过java解决的一些方法。并且解释一下笔者写这道题之前的想法和一些自己遇到的错误。需要注意的是,该题最多调用 next 方法 10^4 次,一般出现该提示说明需要注意时间复杂度。 二、解决思路 ①…...
“传统文化宣传片+虚拟人动捕设备”前景如何?
在数字化时代的发展下,动捕设备的加入,让传播传统文化的虚拟人更具生动表现,拉近人们与传统文化的距离,通过虚拟人动作捕捉动画宣传片,引起更多人对传统文化的关注与传承。 *图片源于网络 深圳文博会创意短片《嗨ICIF…...
节假日moc服务数据:解决用户99%的IT问题
Hi~ 伙伴们,这个国庆假期过得怎么样? 节后第一个工作日如期而至, 忙碌是消除倦怠的最佳良药。 回顾8天假日moc工程师的一组服务数据, 处理事件184起,工单23条。 其中,较为典型案例如下: 1、福建某附属医院…...
WOL唤醒配置(以太网、PHY、MAC)
目录 wol 以太网 MAC PHY RMII 通信配置 总结 wol Wake-on-LAN简称WOL,WOL(网络唤醒) 是一种标准网络协议,它的功效在于让已经进入休眠状态或关机状态的计算机,透过局域网(多半为以太网ÿ…...
MySQL复制,约束条件,查询与安全控制
MySQL之复制 复制表 我有一个表 mysql> show tables; ------------------ | Tables_in_school | ------------------ | student | ------------------mysql> select * from student; -------------------------------------------- | id | name | sec |…...
Java ES 滚动查询
滚动查询(Scroll Query)是 Elasticsearch 提供的一种机制,用于处理大量数据的查询。它允许你在多个请求之间保持“游标”,以便在后续请求中获取更多的结果。 以下是滚动查询的基本工作原理: 1 初始查询: 客户端发送一…...
机器学习算法基础--KNN算法分类
文章目录 1.KNN算法原理介绍2.KNN分类决策原则3.KNN度量距离介绍3.1.闵可夫斯基距离3.2.曼哈顿距离3.3.欧式距离 4.KNN分类算法实现5.KNN分类算法效果6.参考文章与致谢 1.KNN算法原理介绍 KNN(K-Nearest Neighbor)工作原理: 在一个存在标签的…...
深入探究 C++ 编程中的资源泄漏问题
目录 1、GDI对象泄漏 1.1、何为GDI资源泄漏? 1.2、使用GDIView工具排查GDI对象泄漏 1.3、有时可能需要结合其他方法去排查 1.4、如何保证没有GDI对象泄漏? 2、进程句柄泄漏 2.1、何为进程句柄泄漏? 2.2、创建线程时的线程句柄泄漏 …...
BLE协议栈1-物理层PHY
从应届生开始做ble开发也差不读四个月的时间了,一直在在做上层的应用,对蓝牙协议栈没有过多的时间去了解,对整体的大方向概念一直是模糊的状态,在开发时也因此遇到了许多问题,趁有空去收集了一下资料来完成了本次专栏&…...
光伏储能直流系统MATLAB仿真(PV光伏阵列+Boost DCDC变换器+负载+双向DCDC变换器+锂离子电池系统)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
C++三大特性——继承(上篇)
文章目录 目录 一、继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 一、继承的概念及定义 1.1继承的概念 继承(inherita…...
docker系列(9) - docker-compose
文章目录 9. compose编排9.1 介绍9.2 安装9.3 compose常用命令9.4 实战Springboot部署9.4.1 准备组件配置文件9.4.1.1 redis的配置文件9.4.1.2 MySQL的配置文件9.4.1.3 SpringBoot打包文件 9.4.2 准备docker-compose.yml9.4.3 启动服务9.4.4 测试验证 9.5 实战ElasticsearchKib…...
Vue中如何进行日历展示与操作
在Vue中创建交互式日历应用 在Web开发中,创建一个交互式的日历应用是一项常见的任务。Vue.js作为一个流行的JavaScript框架,提供了许多便捷的工具和组件来简化日历的开发。本文将介绍如何使用Vue来创建一个简单但功能强大的日历应用,包括展示…...
SpringBoot 返回图片、Excel、音视频等流数据几种处理方式
方式一:直接针对响应对象(response)实现 @RestController @Slf4j @Api(tags = SwaggerConfig.TAG_IMAGE) @RequestMapping(SwaggerConfig.TAG_IMAGE) public class ImageController {@GetMapping(value = "/getImage")@ApiOperation("获取图片-以ImageIO流形…...
【Vue面试题一】、说说你对 Vue 的理解
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官:有使用过vue吗ÿ…...
vue3 axios
npm install axios import axios from axios // 创建axios实例 const request axios.create({baseURL: ,// 所有的请求地址前缀部分(没有后端请求不用写)timeout: 80000, // 请求超时时间(毫秒)withCredentials: true,// 异步请求携带cookie// headers: {// 设置后端需要的传…...
划片机:半导体生产的必备设备
划片机是半导体加工行业中的重要设备,主要用于将晶圆切割成晶片颗粒,为后道工序粘片做好准备。随着国内半导体生产能力的提高,划片机市场的需求也在逐渐增加。 在市场定位上,划片机可以应用于半导体芯片和其他微电子器件的制造过程…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
