fiddler + mitmdump + python 处理抓包的数据(写入文件或者数据库)
fiddler 可以抓取PC或者APP应用的数据流,支持HTTPS
mitmdump 可以和 pythony编写的脚本配合,拿到数据后写入文件、写入数据库或者下载视频等
fiddler 可以抓取PC或者APP应用的数据流,支持HTTPS
mitmdump 可以和 pythony编写的脚本配合,拿到数据后写入文件、写入数据库或者下载视频等
git@xxxx访问 git@xxxx访问其实就是使用的ssh服务
搭建步骤:以 root 用户执行,服务器地址 192.168.1.100
#创建git用户
adduser git
#切换到git用户
su git
cd
mkdir .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
#创建git仓库
mkdir test.git
cd test.git
git init
#设置git用户的登录密码
passwd
#退出,回到root用户环境
exit
#在客户端创建ssh密匙
ssh-keygen -t rsa
#将对应的公钥添加到服务器git用户ssh认证文件中
ssh-copy-id git@192.168.1.100
#测试能不能访问服务器上的仓库,如果不报错即可访问了
git ls-remote -h git@192.168.1.100:test.git HEAD
#尝试clone仓库到本地
git clone git@192.168.1.100:test.git
应该注意,目前所有这些用户也可以登录服务器并以git用户身份获得 shell 。如果你想限制它,你必须将用户的 shell 更改为git-shell
# 查看现有shell
cat /etc/shells
# 确保在您的系统上安装了git-shell,一般是 /usr/bin/git-shell
which git-shell
# 将上面输出的git-shell的路径添加到/etc/shells最后,保存
sudo -e /etc/shells
#将git用户的登录shell改成git-shell
sudo chsh git -s $(which git-shell)现在192.168.1.100将得到这个结果了,这样就不能远程登录了,但是可以正常使用git命令推送和拉取代码,同时也不能使用ssh-copy-id来复制用户公钥,需要手动去服务器上添加
ssh git@192.168.1.100
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to gitserver closed.此时,用户仍然可以使用 SSH 端口转发来访问 git 服务器能够访问的任何主机。如果您想防止这种情况发生,您可以编辑该authorized_keys文件并将以下选项添加到您要限制的每个公钥之前:
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty结果应如下所示:
cat ~/.ssh/authorized_keys
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJICUvax2T9va5 gsg-keypair
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEwENNMomTboYI+LJieaAY16qiXiH3wuvENhBG...现在 Git 网络命令仍然可以正常工作,但用户将无法获得 shell。正如输出所述,您还可以在git用户的主目录中设置一个目录,git-shell以稍微自定义命令。例如,您可以限制服务器将接受的 Git 命令,或者您可以自定义用户在尝试 SSH 时看到的消息。运行git help shell以获取有关自定义 shell 的更多信息。
实现HTTP访问
apache 实现
让我们来看看一个非常基本的设置。我们将使用 Apache 作为 CGI 服务器进行设置。如果您没有 Apache 设置,您可以在 Linux 机器上使用以下内容进行设置:
sudo apt-get install apache2 apache2-utils
a2enmod cgi alias env这也使得mod_cgi,mod_alias和mod_env模块,这些都需要这正常工作。
将仓库存放的目录(以/srv/git为例)的用户组设置为 www-data以便 Web 服务器可以读取和写入访问存储库,因为运行 CGI 脚本的 Apache 实例(默认情况下)将作为该用户运行:
chgrp -R www-data /srv/git接下来,我们需要向 Apache 配置添加一些内容,以将其git-http-backend作为处理程序运行,以处理进入/gitWeb 服务器路径的任何内容。
SetEnv GIT_PROJECT_ROOT /srv/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/如果您省略GIT_HTTP_EXPORT_ALL环境变量,那么 Git 将只为未经身份验证的客户端提供包含git-daemon-export-ok文件的存储库,就像 Git 守护程序(git-daemon-export-ok)所做的那样。
最后,您将要告诉 Apache 允许请求git-http-backend并以某种方式对写入进行身份验证,可能使用像这样的 Auth 块:
<Files "git-http-backend">
AuthType Basic
AuthName "Git Access"
AuthUserFile /srv/git/.htpasswd
Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
Require valid-user
</Files>这将要求您创建一个.htpasswd包含所有有效用户密码的文件。以下是将“schacon”用户添加到文件的示例:
$ htpasswd -c /srv/git/.htpasswd schacon有很多方法可以让 Apache 对用户进行身份验证,您必须选择并实现其中之一。这只是我们能想到的最简单的例子。您几乎肯定还想通过 SSL 进行设置,以便对所有这些数据进行加密。
我不想在 Apache 配置细节讲太多,因为您很可能使用不同的服务器或有不同的身份验证需求。
这里只是说明 Git 带有一个 CGI 处理程序 git-http-backend,当调用它时将完成所有协商以通过 HTTP 发送和接收数据。
它本身不实现任何身份验证,但可以在调用它的 Web 服务器层轻松控制。
您几乎可以使用任何支持 CGI 的 Web 服务器来执行此操作,因此请选择您最了解的服务器。
有关在 Apache 中配置身份验证的更多信息,请在此处查看 Apache 文档:https://httpd.apache.org/docs/current/howto/auth.html
nginx实现
nginx配置
# 配置以 /git 开始的虚拟目录
server {
listen 80;
server_name git.example.com;
auth_basic "Git Access";
auth_basic_user_file /etc/nginx/.htpasswd_git;
error_log /var/log/nginx-git-error.log;
access_log /var/log/nginx-git-access.log;
client_max_body_size 0;
root /srv/git/;
location ~ /git(/.*) {
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
fastcgi_param GIT_PROJECT_ROOT /srv/git;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $1;
fastcgi_read_timeout 600;
client_max_body_size 100M;
}
}参考 nginx ngx http auth basic module , 用户认证文件格式如下:
/etc/nginx/.htpasswd_git
# comment
name1:password1
name2:password2:comment
name3:password3可以使用 htpasswd 命令创建用户, 如果服务器上没有这个命令的话, 可以输入命令 apt-get install apache2-utils 来安装这个命令, 安装了这个命令之后, 就可以使用它来创建认证用户了, 比如要创建用户 user1, 输入命令如下:
htpasswd /etc/nginx/.htpasswd_git user1支持以下密码类型:
使用 crypt() 函数加密; 可以使用 Apache HTTP Server 发行版中的“htpasswd”实用程序或“openssl passwd”命令生成;
使用基于 MD5 的密码算法 (apr1) 的 Apache 变体进行散列; 可以使用相同的工具生成;
由 RFC 2307 中描述的“{scheme}data”语法(1.0.3+)指定; 当前实现的方案包括 PLAIN(一个示例,不应使用)、SHA(1.3.13)(不应使用纯 SHA-1 散列)和 SSHA(一些软件包使用的加盐 SHA-1 散列,特别是 OpenLDAP 和 Dovecot)。
创建 git 代码库
上面配置的 git 跟目录是 /srv/git , 我们在这个目录下初始化一个空的代码库, 命令如下:
cd /srv/git
git init --bare test.git
将test.git用户和用户组设置为nginx进程可以读写的用户
重启 nginx 并测试
输入命令重启 nginx 并测试 git 服务:
nginx -s reload
git clone https://192.168.1.100/git/test.git问题
来自这个网友遇到的问题:https://stackoverflow.com/questions/58437697/multiple-simultaneous-requests-with-git-http-backend-on-nginx-fastcgi-proxy
未经验证:
从测试来看,如果一次有多个请求,代理将失败(代码为 504)
它为每个新的 http 请求生成一个新的 git-http-backend 实例。编译它(需要安装 go 语言)通过
go build git-http-multi-backend.go并运行它
./git-http-multi-backend -r /Path/To/Repos这将使它监听 :80(端口可以更改)。您现在只需将 nginx 配置更改为类似
location ~ /git(/.*) {
proxy_pass http://localhost:80;
}这不是最优雅的解决方案,因为完全可以通过摆弄 nginx 配置来实现相同的效果。
git-http-multi-backend 工具的作者甚至谈到了它。
您需要增加可以生成的 FCGI_CHILDREN 的最大数量。就我而言,我编辑了 /etc/init.d/fcgiwrap 并将 FCGI_CHILDREN 设置为例如 3。现在,我可以一次检出/克隆/推送 3 个存储库。
哦顺便说一句:虽然编辑这个脚本可能被认为不是一个好习惯。我只是想,将脚本放入 /etc/default/fcgiwrap 并使用FCGI_CHILDREN=3也可以完成这项工作,并且单独保留启动脚本
问题
工作中经常发现一些第三方写的docker容器运行有问题,这时我们会通过docker logs命令观察容器的运行日志。很可惜,有时容器中运行的程序仅从日志很难查明问题。这时我们会通过docker exec在目标容器中执行某些命令以探查问题,有时却发现一些镜像很精简,连基本的sh、bash、netstat等命令都没包含。这时就很尴尬了,诊断问题很困难。
docker-debug工具,这个工具的使用方法也很简单,参考以下命令:
# Suppose the container below is a container which should be checked
docker run -d --name dev -p 8000:80 nginx:latest
# Enter a shell where we can access the above container's namespaces (ipc, pid, network, etc, filesystem)
docker-debug dev bash -ldocker-debug的实现原理
简单说执行docker-debug命令也会使用一个包含了常用诊断命令的镜像启动一个诊断容器,该诊断容器将在目标容器相关的命名空间中运行,这样在这个容器中就可以访问目标容器的ipc, pid, network, etc, filesystem,然后使用docker exec命令在诊断容器运行命令,并将docker exec运行命令的输入输出pipe到docker-debug命令的输入输出上。
另外,还发现类似的工具kube-debug,以后诊断pod中的问题方便多了。
Electron: https://www.electronjs.org/docs
electron-builder:打包工具
项目github地址:
https://github.com/electron/electron
https://github.com/electron/electron-quick-start
Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。
electron 桌面开发工具 与用户操作系统和node的集成方法文档
https://www.electronjs.org/zh/docs/latest/tutorial/examples
一些开发经验:
创建 BrowserWindow 窗口
const {app, BrowserWindow} = require('electron')
let remoteURL, debug
debug = !app.isPackaged
if (debug) {
remoteURL = 'https://www.xxx.com/notifyDeskApp/login.html';
//忽略证书的检测
app.commandLine.appendSwitch('ignore-certificate-errors')
} else {
remoteURL = 'https://www.xxx.com/notifyDeskApp/login.html';
}
let trayIcon = path.join(__dirname, "icon", "notify-logo.ico");
let mainWindow, logined, quit
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 400,
height: 300,
fullscreenable: false,
maximizable: false,
icon: trayIcon,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.setAppDetails({
appIconPath: trayIcon,
})
// and load the index.html of the app.
mainWindow.loadURL(remoteURL)
// mainWindow.loadFile('index.html')
mainWindow.on('minimize',(e)=>{
if (logined) {
mainWindow.hide();
}
})
mainWindow.on('close',(e)=>{
if (logined && !quit) {
e.preventDefault()
mainWindow.hide();
} else {
app.quit()
}
})
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})显示隐藏窗口
mainWindow.hide();
mainWindow.restore()渲染进程与主进程通信
创建窗口的时候配置 preload.js, main.js
mainWindow = new BrowserWindow({
width: 400,
height: 300,
fullscreenable: false,
maximizable: false,
icon: trayIcon,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})窗口渲染页面与preload通过window事件,来传递事件消息
窗口加载的网页中的js事件
//客户端登录事件:字段名称说明是否可选类型默认值detail表示该事件中需要被传递的数据,在 EventListener 获取。可选Anynullbubbles表示该事件是否冒泡。可选Booleanfalsecancelable表示该事件能否被取消。可选Booleanfalse
let eventInit = {bubbles: false, cancelable: false, detail: {token: token, trueName: trueName}}
let loginedEvent = new CustomEvent('logined', eventInit)
window.dispatchEvent(loginedEvent)preload.js
const {ipcRenderer} = require('electron');
window.addEventListener('logined', (e) => {
ipcRenderer.send('logined', e.detail);
})
window.addEventListener('logout', (e) => {
ipcRenderer.send('logout', e.detail);
})
window.addEventListener('open-url', (e) => {
ipcRenderer.send('open-url', e.detail);
})
window.addEventListener('exit', (e) => {
ipcRenderer.send('exit', e.detail);
})main.js
const {app,shell} = require('electron')
ipcMain.on('logined', (e, data) => {
logined = true
mainWindow.hide();
})
ipcMain.on('open-url', (e, data) => {
console.log(data)
shell.openExternal(data.url);
})
ipcMain.on('logout', (e, data) => {
logined = false
mainWindow.restore()
})
ipcMain.on('exit', (e, data) => {
logined = false
quit = true
app.quit()
})托盘
const {app, BrowserWindow, Menu, Tray , ipcMain, shell} = require('electron')
let tray = null
const showMainWindow = (menuItem, browserWindow, event) => {
if (mainWindow) {
mainWindow.restore()
mainWindow.show()
mainWindow.focus()
}
}
const appExit = (menuItem, browserWindow, event) => {
quit = true
app.quit()
}
const openDevTools = (menuItem, browserWindow, event) => {
// Open the DevTools.
if (mainWindow) mainWindow.webContents.openDevTools({ mode: 'detach' })
}
let firstrun = process.argv[1] == '--squirrel-firstrun'
const setAutoOpen = function () {
let autoOpenSet = app.getLoginItemSettings()
let option = {
openAtLogin: !autoOpenSet.openAtLogin, // Boolean 在登录时启动应用
openAsHidden: !autoOpenSet.openAsHidden, // Boolean (可选) mac 表示以隐藏的方式启动应用。~~~~
}
if (!debug) app.setLoginItemSettings(option)
tray.displayBalloon({iconType: 'info', title: '操作提示', content: '开机自启动: ' + (option.openAtLogin ? '已开启' : '已关闭')})
}
app.whenReady().then(() => {
//托盘
tray = new Tray(trayIcon)
const contextMenu = Menu.buildFromTemplate([
{ label: '显示主窗口', type: 'normal', click: showMainWindow },
{ label: '开机自启动', type: 'normal', click: setAutoOpen, visible: !debug },
{ label: '调试窗口', type: 'normal', click: openDevTools, visible: debug },
{ label: '退出客户端', type: 'normal', click: appExit },
])
tray.setToolTip(app.name)
tray.setContextMenu(contextMenu)
})开机自启动
app.setLoginItemSettings({
openAtLogin: true, // Boolean 在登录时启动应用
openAsHidden: true, // Boolean (可选) mac 表示以隐藏的方式启动应用。~~~~
})开发与正式环境判断: 打包后 app.isPackaged 为 true
debug = !app.isPackaged使用系统默认的浏览器打开一个网页,而不是客户端新开一个窗口
const {shell} = require('electron')
shell.openExternal(data.url);只允许开一个程序
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
return app.quit()
}修改桌面通知时的程序标题
app.setAppUserModelId('myapp name')electron-builder:配置参考 (electron-vue, package.json)
{
...
"build": { // electron-builder配置
"productName":"xxxx",//项目名 这也是生成的exe文件的前缀名
"appId": "xxxxx",//包名
"copyright":"xxxx",//版权 信息
"compression": "store", // "store" | "normal"| "maximum" 打包压缩情况(store 相对较快),store 39749kb, maximum 39186kb
"directories": {
"output": "build" // 输出文件夹
},
"asar": false, // asar打包
"extraResources": { // 拷贝dll等静态文件到指定位置
"from": "./app-update.yml",
"to": "./b.txt"
},
"win": {
"icon": "xxx/icon.ico"//图标路径,
"extraResources": { // 拷贝dll等静态文件到指定位置(用于某个系统配置)
"from": "./app-update.yml",
"to": "./b.txt"
}
},
"nsis": {
"oneClick": false, // 一键安装
"guid": "xxxx", //注册表名字,不推荐修改
"perMachine": true, // 是否开启安装时权限限制(此电脑或当前用户)
"allowElevation": true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
"allowToChangeInstallationDirectory": true, // 允许修改安装目录
"installerIcon": "./build/icons/aaa.ico", // 安装图标
"uninstallerIcon": "./build/icons/bbb.ico", //卸载图标
"installerHeaderIcon": "./build/icons/aaa.ico", // 安装时头部图标
"createDesktopShortcut": true, // 创建桌面图标
"createStartMenuShortcut": true, // 创建开始菜单图标
"shortcutName": "xxxx" // 图标名称
}
}
...
} https://github.com/joewalnes/websocketd
这个工具可以把普通命令行命令转成ws协议,web客户端可以通过websocket连接,互换数据;
当有连接过来的时候,会启动进程执行指定的命令,如果命令结束或者连接断开,则连接关闭,进程结束;
连接后,将客户端send过来的数据,作为STDIN标准输入,传入进程,进程的标准输出STDOUT会作为message消息发送给客户端(\n结束作为一条消息);
启动服务:
cat startNotify.sh
#!/usr/bin/env bash
websocketd --port=1234 ./demp.sh
./startNotify.sh
#或者后台运行
nohup ./startNotify.sh > /dev/null 2>&1 &一个发什么回什么的服务端脚本代码大概这样子:demp.sh
#! /pathto/php
<?hp
while (!feof(STDIN)) {
$line = fgets(STDIN);
echo $line;
}
?>建立websocket连接,web网页
<script>
var ws = new WebSocket('ws://127.0.0.1:1234')
ws.onopen = function () {
console.log('ws connected')
ws.onclose = function () {
console.log('ws closed');
}
ws.onmessage = function (res) { console.log(res.data) }
var count = 0;
setInterval(function () {
ws.send(count++)
}, 2000)
}
ws.onerror = function (e) {console.log(e)}
</script>map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream notify_ws {
server 127.0.0.1:1234; # appserver_ip:ws_port
}
server
{
location / {
proxy_pass http://notify_ws;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}关键在于这两行:
最重要的就是在反向代理的配置中增加了如下两行,其它的部分和普通的HTTP反向代理没有任何差别。
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;这里面的关键部分在于HTTP的请求中多了如下头部:
Upgrade: websocket
Connection: Upgrade这两个字段表示请求服务器升级协议为WebSocket。服务器处理完请求后,响应如下报文:
# 状态码为101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade告诉客户端已成功切换协议,升级为Websocket协议。握手成功之后,服务器端和客户端便角色对等,就像普通的Socket一样,能够双向通信。 不再进行HTTP的交互,而是开始WebSocket的数据帧协议实现数据交换。
这里使用map指令可以将变量组合成为新的变量,会根据客户端传来的连接中是否带有Upgrade头来决定是否给源站传递Connection头, 这样做的方法比直接全部传递upgrade更加优雅。
默认情况下,连接将会在无数据传输60秒后关闭,proxy_read_timeout参数可以延长这个时间。源站通过定期发送ping帧以保持连接并确认连接是否还在使用。
两个超时参数
proxy_read_timeout语法 proxy_read_timeout time 默认值 60s 上下文 http server location 说明 该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来获得请求的响应。 这个时间不是获得整个response的时间,而是两次reading操作的时间。
proxy_send_timeout语法 proxy_send_timeout time 默认值 60s 上下文 http server location 说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。 如果超时后,upstream没有收到新的数据,nginx会关闭连接
多次代理转发
工作中遇见过一种情况,就是某个域名在移动网络下面访问不了,这样的话我需要通过一个前段代理服务器做转发,这样就涉及到两次代理。
比如访问的websocket服务URL为:
wss://test.enzhico.net这个在腾讯云公网IP上面,所有网络都能访问。另外一个域名board.xncoding.com解析到电信网络,部署在网关中心,这个域名腾讯云可以访问到。
在腾讯云主机上面:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name test.enzhico.net;
location / {
proxy_pass http://board.xncoding.com;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
#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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/test.enzhico.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.enzhico.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}上面唯一要注意的是忙,把proxy_set_header Host $host;这一行注释掉了。
而在网关中心主机上面:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server localhost:8282; # appserver_ip:ws_port
}
server {
listen 80;
server_name board.xncoding.com;
location / {
proxy_pass http://websocket;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}只需要最外层使用wss协议,里面的交互都使用ws协议,所以监听80端口即可。
参考文章:
https://www.xncoding.com/2018/03/12/fullstack/nginx-websocket.html
https://www.hi-linux.com/posts/42176.html