-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 45.3 KB
/
content.json
1
{"meta":{"title":"Baiyezi","subtitle":"Everything happens for a reason.","description":"Baiyezi.com是一个分享程序开发和运维知识的技术博客","author":662,"url":"https://baiyezi.com","root":"/"},"pages":[{"title":"","date":"2022-05-17T08:25:40.012Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"404.html","permalink":"https://baiyezi.com/404.html","excerpt":"","text":""},{"title":"About","date":"2022-05-17T08:25:40.016Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"about/index.html","permalink":"https://baiyezi.com/about/index.html","excerpt":"","text":"About"},{"title":"Categories","date":"2022-05-17T08:25:40.016Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"categories/index.html","permalink":"https://baiyezi.com/categories/index.html","excerpt":"","text":""},{"title":"我的朋友们","date":"2022-05-17T08:25:40.016Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"friends/index.html","permalink":"https://baiyezi.com/friends/index.html","excerpt":"这里写友链上方的内容。","text":"这里写友链上方的内容。 这里可以写友链页面下方的文字备注,例如自己的友链规范、示例等。"},{"title":"Tags","date":"2022-05-17T08:25:40.016Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"tags/index.html","permalink":"https://baiyezi.com/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"仅用两行代码实现笛卡尔积,高效解决商品类型组合问题","slug":"cartesian-product","date":"2020-09-01T22:01:11.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2020/09/01/cartesian-product/","link":"","permalink":"https://baiyezi.com/2020/09/01/cartesian-product/","excerpt":"","text":"笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尔积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。 使用场景在程序设计领域笛卡尔乘积多用于多个属性组合描述某事物,例如在线购物时通过颜色、容量、重量来选择一部手机: 12345const source = [ ['红', '黄', '蓝'], ['64G', '128G', '256G'], ['30kg', '100kg', '5kg'],] 我们可以通过该数组组合得到 红-128G-100kg 这样一台手机,该数组可以组合出 27 种不同的配置,那么这个组合的过程我们就可以用笛卡尔乘积来处理。 思路解析首先申明笛卡尔乘积函数,用于将两个一维数组进行组合: 1const cartesianProduct = (prev, next) => prev.reduce((result, p) => [...result, ...next.map(n => p + n)], []) 然后遍历数据源,将数组种的前两个元素带入到上面的函数得出一个新的数组,再把得到的数组与第三个元素带入,以此迭代得到最终的结果: 1source.reduce((result, item, i) => (i > 0 ? cartesianProduct(result, item) : result), source[0]) 得益于 javascript 对数组操作的便利性,我们可以写出比大多数语言都要少量的代码 完整代码12345678910const source = [ ['红', '黄', '蓝'], ['64G', '128G', '256G'], ['4C', '8C', '16C'],]const cartesianProduct = (prev, next) => prev.reduce((result, p) => [...result, ...next.map(n => p + n)], [])const r = source.reduce((result, item, i) => (i > 0 ? cartesianProduct(result, item) : result), source[0])console.log(r) 运行效果 结果二维数组版 更新于 2022-03-04 1const cartesianProduct = s => s.reduce((p, c, i) => i > 0 ? p.reduce((r, p) => r.concat(c.map(n => [p].flat().concat(n))), []) : c.map(n => [n]), []) 效果12345678910// index.jsconst cartesianProduct = s => s.reduce((p, c, i) => i > 0 ? p.reduce((r, p) => r.concat(c.map(n => [p].flat().concat(n))), []) : c.map(n => [n]), [])console.log(cartesianProduct([ ['粉', '黄', '蓝'], ['64G', '128G', '256G'], ['4C', '8C', '16C'],]))console.log('-----分割线------')console.log(cartesianProduct([['粉', '黄', '蓝']])) 12345678910111213141516171819$ node index.js[ [ '粉', '64G', '4C' ], [ '粉', '64G', '8C' ], [ '粉', '64G', '16C' ], [ '粉', '128G', '4C' ], [ '粉', '128G', '8C' ], [ '粉', '128G', '16C' ], [ '粉', '256G', '4C' ], [ '粉', '256G', '8C' ], [ '粉', '256G', '16C' ], [ '黄', '64G', '4C' ], [ '黄', '64G', '8C' ], [ '黄', '64G', '16C' ], [ '黄', '128G', '4C' ], [ '黄', '128G', '8C' ], [ '黄', '128G', '16C' ], [ '黄', '256G', '4C' ], [ '黄', '256G', '8C' ], [ '黄', '256G', '16C' ], [ '蓝', '64G', '4C' ], [ '蓝', '64G', '8C' ], [ '蓝', '64G', '16C' ], [ '蓝', '128G', '4C' ], [ '蓝', '128G', '8C' ], [ '蓝', '128G', '16C' ], [ '蓝', '256G', '4C' ], [ '蓝', '256G', '8C' ], [ '蓝', '256G', '16C' ]]-----分割线------[ [ '粉' ], [ '黄' ], [ '蓝' ] ]","categories":[{"name":"code","slug":"code","permalink":"https://baiyezi.com/categories/code/"}],"tags":[{"name":"code snippet","slug":"code-snippet","permalink":"https://baiyezi.com/tags/code-snippet/"}]},{"title":"Linux 系统下使用 iptables 进行流量限制","slug":"iptables-bandwidth-usage-throttle","date":"2020-01-06T13:06:03.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2020/01/06/iptables-bandwidth-usage-throttle/","link":"","permalink":"https://baiyezi.com/2020/01/06/iptables-bandwidth-usage-throttle/","excerpt":"日常在售的大口子 VPS 套餐很多都有流量限制,预付费的还好,流量用完之后就会有类似停机的保护策略,可后付费就有点危险了,以阿里云国际版新手套餐 2.0 为例,网友笑称当流量包用完之后可以一夜跑掉一套房。 所以我们使用 Linux 系统下的一大杀器 iptables 来限制我们的流量开销,当流量达到阈值时就不再相应请求,以此来避免一夜回到解放前的尴尬局面。","text":"日常在售的大口子 VPS 套餐很多都有流量限制,预付费的还好,流量用完之后就会有类似停机的保护策略,可后付费就有点危险了,以阿里云国际版新手套餐 2.0 为例,网友笑称当流量包用完之后可以一夜跑掉一套房。 所以我们使用 Linux 系统下的一大杀器 iptables 来限制我们的流量开销,当流量达到阈值时就不再相应请求,以此来避免一夜回到解放前的尴尬局面。 iptables 命令回顾我们先来回顾一下 iptables 的基础知识 iptables 结构: 12345678Table { Chain { Rule { (match, match, ...) target } }} iptables 规则语法: 123$ iptables <指定链和操作-chain> <指定匹配规则-match> <指定匹配后的操作-target>// 示例:$ iptables -A OUTPUT -m tcp -dport 80 -j ACCEPT 基础版规则编写根据 iptables 的使用方法,我们可以很轻易的写出一个限制流量的规则 12$ iptables -A OUTPUT -p tcp -m quota --quota 1024000 -j ACCEPT$ iptables -A OUTPUT -p tcp -j DROP 规则解释 -A OUTPUT 代表在 OUTPUT 链中添加一条规则,OUTPUT 是 iptables 规则中的一个链(Chain),代表流出的流量包,总共有三个(INPUT, FORWARD, OUTPUT),区分不同场景的规则; -p tcp 是iptables的协议参数 --protocol,匹配规则的一部分; -m quota --quota 1024000 是该条规则的另一匹配规则(match),匹配通过则执行后面指定的操作(target)。这里用 quota 做匹配,限制1M流量(1024000 Bytes); -j ACCEPT 指定匹配成功后的执行操作,ACCEPT 代表接受,DROP 代表丢弃包; 这两条规则合起来: 第一条指定:对于流出的tcp协议包,如果流量没有超过限制,则允许通过。 当第一条规则匹配失败,即流量超过后,顺序第二条规则生效。第二条规则指定:拒绝所有的tcp协议流出包。 两者合起来,流量限制内通过,流量超出后拒绝,达到控制流量的目的。 另,针对tcp端口匹配有两种:–sport, –dport,其区别是包的连接两段的方向 --sport,source port,指定连接的来源段 --dport,destination port,指定链接的目的端 完整版基础版中 iptables 规则限制了我们的流量为 1M,超出 1M 后我们的服务器就 GG 了,这显然不是我们想要的效果。 我们需要的是以月为单位进行流量控制,单月超标之后禁止流量流出,下月重新计算。 123456789101112# 删除链:throttle1tiptables -F throttle1tiptables -F OUTPUTiptables -P OUTPUT ACCEPT# 创建链:throttle1tiptables -N throttle1t# 1020054732800 = 1024 * 1024 * 1024 * 950 = 950GBiptables -A throttle1t -m quota --quota 1020054732800 -j RETURNiptables -A throttle1t -j DROPiptables -A OUTPUT -o eth0+ -j throttle1t 在配合 crontab 每月 1 号 0 点 0 分定时重置计数器即可 10 0 1 * * /sbin/iptables -Z throttle1t 这样我们就可安心的使用流量了~","categories":[{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"}],"tags":[{"name":"linux","slug":"linux","permalink":"https://baiyezi.com/tags/linux/"},{"name":"iptables","slug":"iptables","permalink":"https://baiyezi.com/tags/iptables/"},{"name":"firewall","slug":"firewall","permalink":"https://baiyezi.com/tags/firewall/"}]},{"title":"利用微软 RPA 自动同步 OneDrive 内容到 Google Drive","slug":"googledrive-to-onedrive","date":"2019-11-13T20:46:08.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2019/11/13/googledrive-to-onedrive/","link":"","permalink":"https://baiyezi.com/2019/11/13/googledrive-to-onedrive/","excerpt":"","text":"为什么现在随处可见的 OneDirve 1T/5T/25T 以及 GoogleDrive 无限空间的账号,当这些巨头用各种渠道让用户免费获取大容量存储空间的同时我们自己心里也要明白:我们才是别人种下的韭菜,所以在收割与反收割的博弈当中我们需要给自己留好退路。 永远不要把鸡蛋放在同一个篮子中,当你手里有一大堆大容量网盘的时候,让他们保持同步是对数据最大的保护。 目前主流的方案是使用 rclone 之类的同步程序进行跨平台同步数据,亦或是使用一些云服务商提供的数据迁移服务,本文不讨论优劣,只提供另外一条可选路径。 怎么做 登录微软RPA 在顶部的搜索框中搜索 Google Drive 根据账号类型选择 OneDrive for Business 或是 OneDrive (本文使用 OneDrive for Business) 分别点击 OneDrive 和 Google Drive 的登录按钮进行授权 完成之后点击“继续”,这样我们就基于“OneDrive for Business 文件到 Google Drive 文件”模板创建了我们自己的流 配置流,监听 OneDrive 根目录的文件创建,并在 Google Drive 的相同路径创建相同的文件由于 OneDrive 创建文件时给出的路径包含了类似/drives/xxxxxxxxxxxxxxxxxxxxxxx/root:这样的用户目录,所以我们要使用函数处理掉这些路径 1replace(replace(replace(decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']),substring(decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']), 0, lastIndexOf(decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']), 'root:')),''),'root:',''), decodeBase64(triggerOutputs()['headers/x-ms-file-name-encoded']), '') 格式化之后是这样,整体思路就是移除/drives/xxxxxxxxxxxxxxxxxxxxxxx/root:以及路径中的文件名,产生真实的用户网盘路径 1234567891011121314151617replace( replace( replace( decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']), substring( decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']), 0, lastIndexOf(decodeBase64(triggerOutputs()['headers/x-ms-file-path-encoded']), 'root:'), ), '', ), 'root:', '', ), decodeBase64(triggerOutputs()['headers/x-ms-file-name-encoded']), '',) 配置好了之后可以点击“测试”按钮进行测试,测试过程中能看到 OneDrive 端的相应信息,包含 header 和 body 两部分,header中存放了文件名、路径的信息,body中存放了文件内容、内容类型等信息 使用过程中随时可以在 我的流 > 运行状态 中查看运行日志,每一条都可以点击查看到详情,详情如 7 所描述","categories":[{"name":"tools","slug":"tools","permalink":"https://baiyezi.com/categories/tools/"}],"tags":[{"name":"googledrive","slug":"googledrive","permalink":"https://baiyezi.com/tags/googledrive/"},{"name":"onedrive","slug":"onedrive","permalink":"https://baiyezi.com/tags/onedrive/"}]},{"title":"拐弯抹角使用Google搜索技术资料","slug":"create-v2-server","date":"2019-01-02T15:22:01.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2019/01/02/create-v2-server/","link":"","permalink":"https://baiyezi.com/2019/01/02/create-v2-server/","excerpt":"","text":"自家用潦草笔记,只列大纲,不列过程。 目标: WebSocket+TLS -> nginx -> V2Ray 所需物资: 在网 vps 域名 nginx acme.sh V2Ray 安装V2Ray1bash <(curl -L -s https://install.direct/go.sh) Nginx直接用官方 Packages安装 acme.sh参照中文文档,4 步搞定:安装 acme.sh -> 生成证书 -> 安装证书 -> 配置自更新 配置V2Ray1234567891011121314151617181920212223242526272829{ "inbounds": [ { "listen": "127.0.0.1", "port": 11111, // 监听的端口 "protocol": "vmess", "settings": { "clients": [ { "id": "", // uuid "alterId": 64 } ] }, "streamSettings": { "network": "ws", "wsSettings": { "path": "/path" // websocket 地址 } } } ], "outbounds": [ { "protocol": "freedom", "settings": {} } ]} Nginx12345678910111213141516171819202122server { listen 443 ssl; ssl_certificate your.cer.path; # 证书 .cer 路径 ssl_certificate_key your.key.path; # 证书 .key 路径 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; server_name yourdomain; # 域名 root your-web-root; location /yourpath { # websocket 地址 proxy_redirect off; proxy_pass http://127.0.0.1:your-port; # 监听的端口 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \"upgrade\"; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}","categories":[{"name":"tools","slug":"tools","permalink":"https://baiyezi.com/categories/tools/"}],"tags":[{"name":"ladder","slug":"ladder","permalink":"https://baiyezi.com/tags/ladder/"}]},{"title":"在 Ubuntu/Debian/Arch 中使用 UFW","slug":"ufw","date":"2018-05-02T16:22:13.000Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"2018/05/02/ufw/","link":"","permalink":"https://baiyezi.com/2018/05/02/ufw/","excerpt":"UFW,即简单防火墙(uncomplicated firewall),是一个 Arch Linux、Debian 或 Ubuntu 中管理防火墙规则的前端。","text":"UFW,即简单防火墙(uncomplicated firewall),是一个 Arch Linux、Debian 或 Ubuntu 中管理防火墙规则的前端。 安装 UFWUFW 默认包含在 Ubuntu 中,但在 Arch 和 Debian 中需要安装。 Debian 将自动启用 UFW 的 systemd 单元,并使其在重新启动时启动,但 Arch 不会。 这与告诉 UFW 启用防火墙规则不同,因为使用 systemd 或者 upstart 启用 UFW 仅仅是告知 init 系统打开 UFW 守护程序。 默认情况下,UFW 的规则集为空,因此即使守护程序正在运行,也不会强制执行任何防火墙规则。 强制执行防火墙规则集的部分在下面。 Arch Linux123456# 安装sudo pacman -S ufw# 启动sudo systemctl start ufw# 开机自启sudo systemctl enable ufw Debian12# Debian 将自动启用 systemdsudo apt-get install ufw 使用 UFW 管理防火墙规则 警告: 除非明确设置允许规则,否则配置默认 deny 或 reject 规则会锁定服务器。确保在应用默认 deny 或 reject 规则之前,已按照下面的部分配置了 SSH 和其他关键服务的允许规则。 添加规则可以有两种方式添加规则:用端口号或者服务名表示。 例如:要允许 SSH 的 22 端口的传入和传出连接,可以运行: 123sudo ufw allow ssh# orsudo ufw allow 22 为了更好地调整规则,也可以允许基于 TCP 或者 UDP 的包。下面例子会允许 80 端口的 TCP 包: 123sudo ufw allow 80/tcp# orsudo ufw allow http/tcp 这个会允许 1725 端口上的 UDP 包: 1sudo ufw allow 1725/udp 高级规则除了基于端口的允许或阻止,UFW 还允许您按照 IP 地址、子网和 IP 地址/子网/端口的组合来允许/阻止。 允许从一个 IP 地址连接: 1sudo ufw allow from 123.45.67.89 允许特定子网的连接: 1sudo ufw allow from 123.45.67.89/24 允许特定 IP/ 端口的组合: 1sudo ufw allow from 123.45.67.89 to any port 22 proto tcp proto tcp 可以删除或者根据需求改成 proto udp,所有例子的 allow 都可以根据需要变成 deny。 删除规则要删除一条规则,在规则的前面加上 delete。如果希望不再允许 HTTP 流量,可以运行: 1sudo ufw delete allow 80 编辑 UFW 的配置文件虽然可以通过命令行添加简单的规则,但仍有可能需要添加或删除更高级或特定的规则。 在运行通过终端输入的规则之前,UFW 将运行一个文件 before.rules,它允许回环接口、ping 和 DHCP 等服务。要添加或改变这些规则,编辑 /etc/ufw/before.rules 这个文件。 同一目录中的 before6.rules 文件用于 IPv6 。 还存在一个 after.rule 和 after6.rule 文件,用于添加在 UFW 运行通过命令行输入的规则之后需要添加的任何规则。 还有一个配置文件位于 /etc/default/ufw。 从此处可以禁用或启用 IPv6,可以设置默认规则,并可以设置 UFW 以管理内置防火墙链。 UFW 状态可以在任何时候使用命令:sudo ufw status 查看 UFW 的状态。这会显示所有规则列表,以及 UFW 是否处于激活状态: 123456789Status: activeTo Action From-- ------ ----22 ALLOW Anywhere80/tcp ALLOW Anywhere443 ALLOW Anywhere22 (v6) ALLOW Anywhere (v6)80/tcp (v6) ALLOW Anywhere (v6)443 (v6) ALLOW Anywhere (v6) 启用防火墙随着选择规则完成,初始运行 ufw status 可能会输出 Status: inactive。 启用 UFW 并强制执行防火墙规则: 1sudo ufw enable 禁用 UFW 规则: 1sudo ufw disable 日志记录可以用下面的命令启动日志记录: 1sudo ufw logging on 可以通过运行 sudo ufw logging low|medium|high 设计日志级别,可以选择 low、 medium 或者 high。默认级别是 low。 常规日志类似于下面这样,位于 /var/logs/ufw: 1Sep 16 15:08:14 <hostname> kernel: [UFW BLOCK] IN=eth0 OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:00:00 SRC=123.45.67.89 DST=987.65.43.21 LEN=40 TOS=0x00 PREC=0x00 TTL=249 ID=8475 PROTO=TCP SPT=48247 DPT=22 WINDOW=1024 RES=0x00 SYN URGP=0 前面的值列出了服务器的日期、时间、主机名。剩下的重要信息包括: [UFW BLOCK]:这是记录事件的描述开始的位置。在此例中,它表示阻止了连接。 IN:如果它包含一个值,那么代表该事件是传入事件 OUT:如果它包含一个值,那么代表事件是传出事件 MAC:目的地和源 MAC 地址的组合 SRC:包源的 IP DST:包目的地的 IP LEN:数据包长度 TTL:数据包 TTL,或称为 time to live。 在找到目的地之前,它将在路由器之间跳跃,直到它过期。 PROTO:数据包的协议 SPT:包的源端口 DPT:包的目标端口 WINDOW:发送方可以接收的数据包的大小 SYN URGP:指示是否需要三次握手。 0 表示不需要。","categories":[{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"}],"tags":[{"name":"firewall","slug":"firewall","permalink":"https://baiyezi.com/tags/firewall/"},{"name":"ubuntu","slug":"ubuntu","permalink":"https://baiyezi.com/tags/ubuntu/"},{"name":"debian","slug":"debian","permalink":"https://baiyezi.com/tags/debian/"},{"name":"arch","slug":"arch","permalink":"https://baiyezi.com/tags/arch/"},{"name":"ufw","slug":"ufw","permalink":"https://baiyezi.com/tags/ufw/"}]},{"title":"Nginx 配置文件中如何正确的将变量用于 URL","slug":"nginx-resolver","date":"2017-04-26T19:00:53.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2017/04/26/nginx-resolver/","link":"","permalink":"https://baiyezi.com/2017/04/26/nginx-resolver/","excerpt":"","text":"在 Nginx 配置文件中使用变量来存放一个http地址时,如果这个地址是域名而不是IP,如下所示: 1234567set $server_domain \"http://yourdomain:8080\";location ^~ /api { proxy_pass $server_domain; rewrite ^/api/?(.*)$ \"/$1\" break; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;} 这个配置中的代理是会出错的,错误信息是 1no resolver defined to resolve yourdomain 但是如果我们不申明变量 $server_domain,而是直接设置 proxy_pass 123456location ^~ /api { proxy_pass http://yourdomain:8080; rewrite ^/api/?(.*)$ \"/$1\" break; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;} 这时候代理就会生效,毫无问题 原因是 Nginx 0.6.18以后的版本中启用了一个resolver指令,在使用变量来构造某个server地址的时候一定要用resolver指令来指定DNS服务器的地址,所以解决这个问题的方法很简单:在nginx的配置文件中的http{}部分添加一行DNS地址即可 1resolver 8.8.8.8; 此外,如果有ipv6环境的机器,还可以加上ipv6=off指令,避免一些奇葩原因导致的no resolver defined to resolve错误。 1resolver 8.8.8.8 ipv6=off;","categories":[{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"}],"tags":[{"name":"nginx","slug":"nginx","permalink":"https://baiyezi.com/tags/nginx/"}]},{"title":"为多个 Github 仓库配置配置不同的 SSH Key","slug":"mutli-ssh-keys-for-github","date":"2017-04-03T13:11:43.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2017/04/03/mutli-ssh-keys-for-github/","link":"","permalink":"https://baiyezi.com/2017/04/03/mutli-ssh-keys-for-github/","excerpt":"同一个电脑上多个账号访问 Github 仓库可以使用 ssh config 搞定,不过为了区分不同的账号需要修改主机名; 这里分享一个方便的方法,在已经克隆到代码的情况下,修改本地项目的 git 配置文件,为项目配置独立的 ssh key;","text":"同一个电脑上多个账号访问 Github 仓库可以使用 ssh config 搞定,不过为了区分不同的账号需要修改主机名; 这里分享一个方便的方法,在已经克隆到代码的情况下,修改本地项目的 git 配置文件,为项目配置独立的 ssh key; 1234567891011121314151617# ./.git/config[user] email = …… name = ……[core] repositoryformatversion = 0 filemode = false bare = false logallrefupdates = true ignorecase = true sshCommand = ssh -i ~/.ssh/your_key_file_name -F /dev/null # 就是这句了[remote "origin"] url = …… fetch = ……[branch "master"] remote = origin merge = refs/heads/master","categories":[{"name":"code","slug":"code","permalink":"https://baiyezi.com/categories/code/"}],"tags":[{"name":"ssh","slug":"ssh","permalink":"https://baiyezi.com/tags/ssh/"},{"name":"git","slug":"git","permalink":"https://baiyezi.com/tags/git/"},{"name":"github","slug":"github","permalink":"https://baiyezi.com/tags/github/"}]},{"title":"Linux Systemctl 指令","slug":"systemctl-helper","date":"2017-03-02T23:56:03.000Z","updated":"2022-05-17T08:25:40.016Z","comments":true,"path":"2017/03/02/systemctl-helper/","link":"","permalink":"https://baiyezi.com/2017/03/02/systemctl-helper/","excerpt":"","text":"Systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。 Systemd 包含众多指令,本文重点介绍常用的 systemctl 指令。 一、守护进程曾经 Linux 的启动一直是采用的 init 进程,使用如下指令来启动服务: 123$ sudo /etc/init.d/apache2 start# 或者$ service apache2 start 这种方法有两个缺点: 启动时间长 init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。 启动脚本复杂 init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。 二、Systemd为了解决上述两个问题,诞生了 Systemd。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。 根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要 守护整个系统。 使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。 Systemd 并不是一个指令,而是一组指令,涉及到系统管理的各个方面。 接下来就是本文主要介绍的 systemctl 指令。 三、systemctl1234567891011121314151617181920212223242526272829303132333435363738# 查看服务列表systemctl list-units --type=service # 列出所有已经安装的 服务及状态(可为人所读, 内容简略、清晰)systemctl list-unit-files# 列出正在运行的服务状态(基本不为人所读,内容复杂、全面)systemctl# 以树形列出正在运行的进程,它可以递归显示控制组内容systemd-cgls# 启动服务systemctl start name.service# 停止服务systemctl stop name.service# 重启服务systemctl restart name.service# 查看服务状态systemctl status name.service# 开机自启systemctl enable name.service# 取消开机自启systemctl disable name.service# 查看是否开机自启systemctl is-enabled postfix.service# 查看已启动的服务列表systemctl list-unit-files | grep enabled# 查看启动失败的服务列表systemctl --failed 使用指令 systemctl is-enabled postfix.service 得到的值可以是enable、disable或static,这里的 static 它是指对应的 Unit 文件中没有定义[Install]区域,因此无法配置为开机启动服务。 启用服务就是在当前“runlevel”的配置文件目录 /etc/systemd/system/multi-user.target.wants 里建立 /usr/lib/systemd/system 里面对应服务配置文件的软链接,禁用服务就是删除此软链接,添加服务就是添加软连接。","categories":[{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"}],"tags":[{"name":"linux","slug":"linux","permalink":"https://baiyezi.com/tags/linux/"},{"name":"systemd","slug":"systemd","permalink":"https://baiyezi.com/tags/systemd/"},{"name":"systemctl","slug":"systemctl","permalink":"https://baiyezi.com/tags/systemctl/"}]},{"title":"Nginx 正确设置 default_server 避免恶意解析和IP访问","slug":"nginx-default-server","date":"2016-09-16T00:05:07.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2016/09/16/nginx-default-server/","link":"","permalink":"https://baiyezi.com/2016/09/16/nginx-default-server/","excerpt":"Nginx 默认 Server默认情况下 nginx 的 default_server 指令可以处理没有匹配到 server_name 的请求,如果没有显式定义 default_server,则 nginx 会选取第一个定义的 server 作为 default_server。","text":"Nginx 默认 Server默认情况下 nginx 的 default_server 指令可以处理没有匹配到 server_name 的请求,如果没有显式定义 default_server,则 nginx 会选取第一个定义的 server 作为 default_server。 默认 Server 存在的问题这样的规则会导致两个问题: 当有任何域名解析到我们的服务器,我们的 default_server 都会处理它,如果我们没有设置 default_server 则我们的第一个 server 会处理这些域名,无论这些 server 是否绑定 server_name; 如果我们没有绑定 IP 到 server,当使用 IP 访问我们的服务器时,也会被 default_server 处理; 这两个问题会带来什么样的灾难,大家都明白,这里就不再赘述了; 如何规避默认 Server 带来的问题取消 80 端口的 default_server解决默认 Server 最简单的办法就是取消默认 Server 就行了; 但是 nginx 中我们无法取消,因为不显示申明,也会默认第一个 Server 作为隐式申明 既然不能取消,那我们就只能修改默认 Server 的表现行为了; 我们可以通过如下配置,让 default_server 直接返回 444 状态; 12345server { listen 80 default_server; server_name _; return 444;} 444 No Response Nginx上HTTP服务器扩展。服务器不向客户端返回任何信息,并关闭连接(有助于阻止恶意软件)。 取消 443 端口的 default_server由于 443 需要 ssl 证书,所以还需要再 80 的配置上增加关于 ssl 的配置; 123456789server { listen 443 default_server; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; # 证书配置 ssl_certificate_key /etc/nginx/ssl/nginx.key; # 证书配置 return 444;} 上述配置中的证书配置可以采用任意证书,因为我们本就不会处理匹配的请求,所以不需要正确的证书来获取浏览器的信任,但是 nginx 的 443 端口 server 又必须配置 ssl 证书,所以这里我们自己生成一个证书就可以了,不建议使用自有的真实证书,这会暴露域名; 生成证书: 1openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt HTTP 自动跳转到 HTTPS有时候我们需要使用 default_server 为我们带来便利,例如:实际网站的 server 中仅配置 443 端口,80 端口的请求统一跳转到对应的 443 服务; 12345server { listen 80 default_server; server_name _; return 301 https://$host$request_uri;} 那么这时候,未受理的域名和ip访问均会跳转到 443 端口,我们只需要对 443 的默认 Server 输出 HTTP Status 444 就行了; 123456789server { listen 443 default_server; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; return 444;} 完整配置不自动强制 HTTPS1234567891011121314server { listen 80 default_server; server_name _; return 444;}server { listen 443 default_server; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; return 444;} 需要 HTTP 自动跳转到 HTTPS1234567891011121314server { listen 80 default_server; server_name _; return 301 https://$host$request_uri;}server { listen 443 default_server; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; return 444;}","categories":[{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"}],"tags":[{"name":"nginx","slug":"nginx","permalink":"https://baiyezi.com/tags/nginx/"}]},{"title":"如何通过 Github gists 学习优秀的代码片段","slug":"create-ss-server","date":"2016-06-20T22:17:30.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2016/06/20/create-ss-server/","link":"","permalink":"https://baiyezi.com/2016/06/20/create-ss-server/","excerpt":"","text":"由于 Github gists 在国内无法正常访问,所以本文旨在快速学习Linux搭建 shadowsocks 服务(以下简称ss),并利用 bbr 和 kcp 进行加速,然后在 windows/ios 设备上访问 Github gists 来学习优秀的代码片段。 注意:本文基于你对 linux 操作系统有简单的认知和理解,所以本文并不适合纯小白 以下是需要用到的资源 一台可访国际互联网的服务器 ss 服务端一键安装脚本:ss-fly kcptun 服务端:kcptun(非必须) kcptun 客户端:kcptun(非必须) ss windows 客户端:shadowsocks-windows ss ios 客户端:potatso lite 一、 获取服务器选购一台廉价的海外服务器就足够了,本文使用 vultr 提供的 vps,目前最便宜的是$3.5一个月。使用下面的推广链接可获得$50首冲赠送。 推广链接:https://www.vultr.com/?ref=8030646-4F 注意:推广活动是限时的,如果点击过去发现无效,就表示活动过期了。 二、 安装ss服务端服务端的安装方式有很多,本文选用 @flyzy2005 编写的 ss-fly 一键安装脚本。 第一步:clone代码到本地1git clone https://github.com/flyzy2005/ss-fly 第二步:运行安装脚本1ss-fly/ss-fly.sh -i yourpassword 8080 其中yourpassword是 ss 连接密码,8080是端口号。 等待安装完成即可,安装完成之后服务会自动运行,并会开机自启。 如果需要修改密码或者端口,只需要重新运行一次安装脚本,或者直接修改/etc/shadowsocks.json这个配置文件。 相关操作 123456/etc/init.d/ss-fly start # 启动/etc/init.d/ss-fly stop # 停止/etc/init.d/ss-fly restart # 重启/etc/init.d/ss-fly status # 查看状态ss-fly/ss-fly.sh -sslink # 查看连接vi /etc/shadowsocks.json # 修改配置 第三步:验证服务状态这一步并不是必须的,而是为了检查 ss 服务是否在正常运行,并能被外部网络访问 在服务器上执行1netstat -lntup 检查输出结果是否有一个被 python 监听的8080端口,如果有就说明 ss 服务已经启动。 在本地执行1telnet yourserverip 8080 其中yourserverip是你的服务器 ip,如果连接成功,就表示 ss 服务已经能被外部网络访问。 如果没有telnet这个命令,可以在控制面板 > 程序和功能 > 启用或关闭 Windows 功能中勾选Telnet Client并安装。 如果telnet连接失败,可以检查以下几个方面: 服务器防火墙是否开放8080端口(ss-fly 在安装过程中会自动配置防火墙开放8080); 服务器提供商的防火墙策略是否开放8080(vultr 默认无防火墙); 你所在的网络是否允许访问8080,由于一些企业的防火墙策略只允许访问常用端口,所以本文使用的是8080这种比较常用的端口; 三、 安装SS客户端ss 客户端也有很多,本文选用 shadowsocks-windows,使用方法非常简单,填写好服务器地址``服务器端口``密码就可以正常使用了,记得更新PAC配置。 到这里,ss 服务端和 windows 客户端就已经安装完成了,已经可以正常的网上冲浪了。 如果你觉得冲浪的速度有点差强人意,那么你可以继续进行下面的步骤。 四、 开启BBR加速bbr 是 @google 开源的一套内核加速算法,可以让你搭建的 shadowsocks 速度上一个台阶。 本文使用的ss-fly一键安装脚本已经集成了bbr的一键安装,所以我们只需要在服务器上运行以下脚本就可以开启bbr加速了。 1ss-fly/ss-fly.sh -bbr 注意:安装完成之后需要重启系统才能生效。 检测bbr加速是否开启,可以输入以下脚本: 1sysctl net.ipv4.tcp_available_congestion_control 如果返回类似以下这种后面含有bbr的内容,则说明已经成功开启了。 1net.ipv4.tcp_available_congestion_control = bbr cubic reno 到这里,你不但完成了 ss 服务端和 windows 客户端的安装,还对服务端的 ss 进行了 bbr 加速。 这基本能满足大多数冲浪需求了,但如果你像本文一样,购买的是非常廉价而且又远在美利坚的 vps,每到晚上速度就会慢得让人接受不了,那么你可以继续下面的步骤。 五、 使用KCPTUN进行加速kcptun 是由 @xtaci 基于 kcp 协议的golang实现。KCP是一个快速可靠协议,能以比 TCP 浪费 10%-20% 的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。 注意:使用kcptun会增加流量的开支 但是对于本文中使用的 vultr vps 最低配,也就是 500G/month 的流量限制,完全能够负担。 下载最新版的kcptun打开 https://github.com/xtaci/kcptun/releases 在服务器上下载最新版的kcptun服务端kcptun-linux-amd64-20xxxxxx.tar.gz 12# 本文使用的 v20190418wget https://github.com/xtaci/kcptun/releases/download/v20190418/kcptun-linux-amd64-20190418.tar.gz 解压之后启动服务 12./server_linux_amd64 -t "yourssip:8080" -l ":8081" -mode fast3 -nocomp -sockbuf 16777217 -dscp 46 --key yourpassword# 这里是直接在当前服务器会话运行的,你可以使用 nohup 让它在后台运行,也可以注册成 systemd 服务让它以服务的形式启动 其中yourssip是你的 ss 服务器 ip,在本文中 ss 和 kcptun 部署在同一服务器,所以这里直接填写服务器的 ip 地址,8080是你的 ss 端口,8081是你准备让kcptun监听的端口,yourpassword是你的kcptun密码。 你任然可以使用netstat -lntup来查看8081端口的监听情况,以便确认kcptun是否启动成功 这样,kcptun 服务端就已经部署好了 接下来下载最新版的 windows 客户端kcptun-windows-amd64-20xxxxxx.tar.gz,解压之后会发现里面包含 windows 服务端和客户端文件,由于我们的服务端已经部署在 linux 上,所以我们只需要名为client_windows_amd64.exe的客户端文件。 我们用cmd运行以下脚本 1client_windows_amd64.exe -r "KCP_SERVER_IP:8081" -l ":1000" -mode fast3 -nocomp -sockbuf 16777217 -dscp 46 --key yourpassword 其中KCP_SERVER_IP是你的kcptun所在服务器的 ip,8081是你的kcptun监听的端口,:1000是你的kcptun客户端准备监听的本地端口,yourpassword是你的kcptun密码。 这样我们的kcptun客户端就已经成功连接到了我们的kcptun服务端,接下来我们只需要修改一下我们的shadowsocks-windows客户端的配置,让shadowsocks-windows不把数据发送到 ss 服务器,而是把数据发送到本地的kcptun,就能实现我们的kcptun加速了。 1# ss客户端 -> kcptun客户端 -> kcptun服务端 -> ss服务端 shadowsocks-windows 配置修改 将服务器地址改为127.0.0.1,将服务器端口改为1000,确认之后就可以享受kcptun加速带来的稳定和快乐了。 六、整合shadowsocks-windows和kcptun客户端到上一步的时候,由于我们在客户端每次都要开启两个程序(kcptun客户端、ss客户端),所以在使用上显得并不那么优雅。好在shadowsocks-windows提供了插件的支持,我们可以把kcptun以插件的形式加载到shadowsocks-windows,使得我们只需要启动shadowsocks-windows就可以愉快的冲浪。 复制client_windows_amd64.exe到shadowsocks-windows目录; 修改shadowsocks-windows配置,将服务器地址改为ss服务器地址,将服务器端口改为8081(服务端kcptun监听的端口),插件程序填写client_windows_amd64.exe,插件参数填写以下内容12-r %SS_REMOTE_HOST%:%SS_REMOTE_PORT% -l %SS_LOCAL_HOST%:%SS_LOCAL_PORT% --mode fast3 --nocomp --sockbuf 16777217 --dscp 46 --key kcptunpassword# kcptunpassword 是你的 kcptun 密码 确认之后就可以享受kcptun加速带来的稳定和快乐了。 七、 IOS客户端国区已经没有好用的 ss 客户端了,本文使用的 potatso lite 也需要在美区才能下载,关于如何切换美区,或者注册美区账号,以下提供简要的说明,避免大家踩坑根本没有人会浏览到我的博客,哪儿来的大家。 需要能访问真正互联网的网络,推荐使用 nuts 的 ios 版; 不要用 wifi 代理,用代理无法访问 appstore; 需要一个美国身份的生成器,不要乱填,乱填无法通过验证,推荐使用 fake name generator","categories":[{"name":"tools","slug":"tools","permalink":"https://baiyezi.com/categories/tools/"}],"tags":[{"name":"ladder","slug":"ladder","permalink":"https://baiyezi.com/tags/ladder/"}]},{"title":"令人惊叹的代码片段","slug":"awesome-code-snippet","date":"2016-01-12T23:31:46.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2016/01/12/awesome-code-snippet/","link":"","permalink":"https://baiyezi.com/2016/01/12/awesome-code-snippet/","excerpt":"常年混迹 Github 以及各种社区,总能在其他开发者的代码中找到一些不可思议的代码片段,它们有的优雅高效,有的晦涩难懂,更有甚者让人大跌眼镜,今天就和大家分享一波「令人惊叹的代码片段」。","text":"常年混迹 Github 以及各种社区,总能在其他开发者的代码中找到一些不可思议的代码片段,它们有的优雅高效,有的晦涩难懂,更有甚者让人大跌眼镜,今天就和大家分享一波「令人惊叹的代码片段」。 一、单行写一个评分组件利用数组提供的 slice 函数对字符串(即字符数组)进行截取,简单到不可思议,让人大呼 “我怎么没想到”。 1'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate); 演示: 123456789101112131415let rate = 1;'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate);// \"★☆☆☆☆\"rate = 2;'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate);// \"★★☆☆☆\"rate = 3;'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate);// \"★★★☆☆\"rate = 4;'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate);// \"★★★★☆\"rate = 5;'★★★★★☆☆☆☆☆'.slice(5 - rate, 10 - rate);// \"★★★★★\" 二、两句代码实现笛卡尔积12345678910const source = [ ['红', '黄', '蓝'], ['64G', '128G', '256G'], ['30kg', '100kg', '5kg'],]const cartesianProduct = (prev, next) => prev.reduce((result, p) => [...result, ...next.map(n => p + n)], [])const r = source.reduce((result, item, i) => (i > 0 ? cartesianProduct(result, item) : result), source[0])console.log(r) 查看代码解析>> 运行结果:","categories":[{"name":"code","slug":"code","permalink":"https://baiyezi.com/categories/code/"}],"tags":[{"name":"code snippet","slug":"code-snippet","permalink":"https://baiyezi.com/tags/code-snippet/"}]},{"title":"令人惊叹的正则表达式实例","slug":"awesome-regexp","date":"2016-01-03T11:01:03.000Z","updated":"2022-05-17T08:25:40.012Z","comments":true,"path":"2016/01/03/awesome-regexp/","link":"","permalink":"https://baiyezi.com/2016/01/03/awesome-regexp/","excerpt":"正则表达式在处理文本方面具有天然优势,但受限于它的可读性和可编程性,我们总会在写出一长串正则表达式后怀疑它是否能如期表现,进而对它进行一系列测试和校验。 本着 DRY 原则,我把曾经用过或学习过的一些优秀的正则表达式整理汇总,记录自己的同时也分享给大家,希望能帮到各位望着正则表达式头皮发麻的同学们。 我相信,总有一款会让你喊出“卧槽”。","text":"正则表达式在处理文本方面具有天然优势,但受限于它的可读性和可编程性,我们总会在写出一长串正则表达式后怀疑它是否能如期表现,进而对它进行一系列测试和校验。 本着 DRY 原则,我把曾经用过或学习过的一些优秀的正则表达式整理汇总,记录自己的同时也分享给大家,希望能帮到各位望着正则表达式头皮发麻的同学们。 我相信,总有一款会让你喊出“卧槽”。 一、正则表达式为数字添加千分符1/\\B(?=(\\d{3})+\\b)/; 查找一个“非单词边界” [1]后面伴随着“3 的倍数个数字” [2]后面伴随着一个“单词边界” 把查找到的“非单词边界”替换成千分符即可 12'32132112345123136.123'.replace(/\\B(?=(\\d{3})+\\b)/g, ',');('32,132,112,345,123,136.123'); 缺陷:小数位同样会被处理 12'32132112345123136.123123123123'.replace(/\\B(?=(\\d{3})+\\b)/g, ',');('32,132,112,345,123,136.123,123,123,123');","categories":[{"name":"code","slug":"code","permalink":"https://baiyezi.com/categories/code/"}],"tags":[{"name":"regexp","slug":"regexp","permalink":"https://baiyezi.com/tags/regexp/"}]}],"categories":[{"name":"code","slug":"code","permalink":"https://baiyezi.com/categories/code/"},{"name":"ops","slug":"ops","permalink":"https://baiyezi.com/categories/ops/"},{"name":"tools","slug":"tools","permalink":"https://baiyezi.com/categories/tools/"}],"tags":[{"name":"code snippet","slug":"code-snippet","permalink":"https://baiyezi.com/tags/code-snippet/"},{"name":"linux","slug":"linux","permalink":"https://baiyezi.com/tags/linux/"},{"name":"iptables","slug":"iptables","permalink":"https://baiyezi.com/tags/iptables/"},{"name":"firewall","slug":"firewall","permalink":"https://baiyezi.com/tags/firewall/"},{"name":"googledrive","slug":"googledrive","permalink":"https://baiyezi.com/tags/googledrive/"},{"name":"onedrive","slug":"onedrive","permalink":"https://baiyezi.com/tags/onedrive/"},{"name":"ladder","slug":"ladder","permalink":"https://baiyezi.com/tags/ladder/"},{"name":"ubuntu","slug":"ubuntu","permalink":"https://baiyezi.com/tags/ubuntu/"},{"name":"debian","slug":"debian","permalink":"https://baiyezi.com/tags/debian/"},{"name":"arch","slug":"arch","permalink":"https://baiyezi.com/tags/arch/"},{"name":"ufw","slug":"ufw","permalink":"https://baiyezi.com/tags/ufw/"},{"name":"nginx","slug":"nginx","permalink":"https://baiyezi.com/tags/nginx/"},{"name":"ssh","slug":"ssh","permalink":"https://baiyezi.com/tags/ssh/"},{"name":"git","slug":"git","permalink":"https://baiyezi.com/tags/git/"},{"name":"github","slug":"github","permalink":"https://baiyezi.com/tags/github/"},{"name":"systemd","slug":"systemd","permalink":"https://baiyezi.com/tags/systemd/"},{"name":"systemctl","slug":"systemctl","permalink":"https://baiyezi.com/tags/systemctl/"},{"name":"regexp","slug":"regexp","permalink":"https://baiyezi.com/tags/regexp/"}]}