CI_Knight

且行善举,莫问前程。

0%

还有一天就国庆了,现在满脑子都在想给祖国庆生。不过这样重大的节日,翻墙总是会出些问题,为了应对这样的问题,应该提前多建几个代理服务器,那我就选了一台 vultr 服务器做备用机,之前都是 vmess 协议,这次打算尝试下 trojan 的安全性。如果你在搬瓦工、digital ocean、vultr等这种云服务商搭建的 vpn,在重大节日时,大概率都会被封端口或者是 IP,而且 vmess 现在应该是可以被准确识别了,我的 vmess 代理每次都可以精准被封端口。

vultr 的美国线路要比 digital ocean 更好,而且有日本可选,新加坡基本抢不到,如果选美国最好使用美西服务器,如果电脑系统是 MacOS,可以安装 BestTrace 软件看下线路,vultr 提供了测试的 IP 地址,在他们官网可以找到。

如果是 vultr 的新用户可以网上搜下优惠码,这样你可以获得 100 美金的试用金,一个月内有效。vultr 可以使用支付宝和加密货币支付,这点还是挺厉害的。

搭建 trojan 服务器

我选的系统是 Debian 11,接下来可以直接跟着步骤操作。vultr 需要在后台设置下安全组,放开 80 和 443 就可以了。使用 trojan 需要一个域名,并且使用ssl加密。如果想了解更多,可以看p4gefau1t trojan的文档。

关闭防火墙

1
2
systemctl disable ufw.service
systemctl stop ufw.service

安装 Nginx

1
2
3
apt install tmux unzip nginx
systemctl enable nginx
systemctl start nginx

下载 trojan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir trojan
cd trojan
wget https://github.com/p4gefau1t/trojan-go/releases/download/v0.10.6/trojan-go-linux-amd64.zip
unzip -o trojan-go-linux-amd64.zip
rm trojan-go-linux-amd64.zip
cat > config.json <<EOF
{
"run_type": "server",
"local_addr": "0.0.0.0",
"local_port": 443,
"remote_addr": "127.0.0.1",
"remote_port": 80,
"password": ["your password"],
"ssl": {
"cert": "/etc/letsencrypt/live/example.com/fullchain.pem",
"key": "/etc/letsencrypt/live/example.com/privkey.pem",
"sni": "example.com"
}
}
EOF

配置文件要把域名和密码修改成自己的。

申请证书

我们使用 certbot 申请证书,也可以使用自己购买的证书。(或者使用acme.sh)

1
2
3
4
5
apt install snapd
snap install core
snap refresh core
snap install --classic certbot
certbot certonly --nginx

运行 trojan

1
2
tmux new -s trojan-server
./trojan-go -config config.json

证书续订

1
certbot renew --dry-run

客户端

我推荐使用ClashX,是一个小猫咪的图标,有 MacOS、Windows、Android 版本,配置可以根据https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/LAZY_RULES/clash.yaml自行修改,配置可以托管在服务器上,多端共用一套配置即可。iOS可以使用shadowrocket,兼容Clash的配置,可以直接添加。

参考

问题和教程都有时效性,我一般写的都很少,很多依赖于版本或者系统,当遇到问题更建议去 Stack Overflow 或者 Github issue 中搜索,也或者直接使用 Google 搜索,肯定很多人乐于写这些。不过我今天还是水了一篇文章。

版本和软件环境

1
2
3
4
System: MacOS 10.15
Python: 3.7.6
gunicorn: 19.9.0
pycoin: 0.90.20190728

问题

我在家里电脑启动一个 gunicorn 服务时,出现 worker 无法的情况,但是并没有任何保存,只有 worker 重启日志,因为没有报错,排查起来就比较麻烦了。我使用的 pipenv 启动的,软件依赖问题可能性很小。当我尝试使用 ipython 运行的时候,则会报错 Abort trap

解决

这时候会发现服务并没有抛错,而我还没办法定位哪里出现的异常,并且吞掉了错误信息。如果使用 pdb 这种工具,定位错误是很费力的。想要快速定位 Abort 位置,可以使用 PYTHONVERBOSE 环境变量。

将 PYTHONVERBOSE 设置为 3 再启动服务,会打印加载模块时的日志,闪退后最后输入的日志,就是我们要定位的地方。通过这种方式我知道是 pycoin 加载 openssl 动态链接库的时候报错了,因为使用了 pycoin 的 ecdsa 模块,并且还是用了 openssl 加速,找不到动态链接库才闪退的。

我们可以将 /usr/local/Cellar/openssl 下的动态链接库拷贝到 /usr/local/lib/ 下,并且再做软连接。

1
2
3
4
5
6
brew install openssl
cd /usr/local/Cellar/[email protected]/1.1.1i/lib
sudo cp libssl.1.1.dylib libcrypto.1.1.dylib /usr/local/lib/
cd /usr/local/lib
sudo ln -s libssl.1.1.dylib libssl.dylib
sudo ln -s libcrypto.1.1.dylib libcrypto.dylib

参考

安装flow-cli

安装 flow-cli,MacOS 需要下载最新版本的二进制文件,brew 只能安装旧版本。具体安装方法见文档 Install the Flow CLI,该文档使用版本是 v0.25.0。

生成key-pair

1
2
3
4
5
$ flow keys generate --sig-algo=ECDSA_secp256k1

Store private key safely and don't share with anyone!
Private Key 11e67f5360e61d7d92eb73e1dc48ffbd71c55c8bdf727520d11ddfa6db63554d
Public Key cd23c71391d33c23c867319258ad6cd082b0066e564e23d3fda3c4e5b9ec841eaaa07d2189965130445a4edda244720628334f6a879d80220b573d9914edcbe2

创建testnet flow地址

访问页面:Flow Testnet Faucet ,创建地址。填入生成的 public key,选择ECDSA_secp256k1签名算法和SHA3_256(和 ETH 哈希算法相同)哈希算法。

创建成功后得到地址:0x25470ac6e0585a62,也可以跳过该步骤,直接使用生成好的地址。

初始化flow配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ mkdir flow-example; cd flow-example
$ flow init --service-priv-key 11e67f5360e61d7d92eb73e1dc48ffbd71c55c8bdf727520d11ddfa6db63554d --service-sig-algo=ECDSA_secp256k1 --service-hash-algo=SHA3_256

Configuration initialized
Service account: 0xf8d6e0586b0a20c7

Start emulator by running: 'flow emulator'
Reset configuration using: 'flow init --reset'

$ cat flow.json
{
"emulators": {
"default": {
"port": 3569,
"serviceAccount": "emulator-account"
}
},
"contracts": {},
"networks": {
"emulator": "127.0.0.1:3569",
"mainnet": "access.mainnet.nodes.onflow.org:9000",
"testnet": "access.devnet.nodes.onflow.org:9000"
},
"accounts": {
"emulator-account": {
"address": "f8d6e0586b0a20c7",
"key": {
"type": "hex",
"index": 0,
"signatureAlgorithm": "ECDSA_secp256k1",
"hashAlgorithm": "SHA3_256",
"privateKey": "11e67f5360e61d7d92eb73e1dc48ffbd71c55c8bdf727520d11ddfa6db63554d"
}
}
},
"deployments": {}
}

我们将配置里的地址 f8d6e0586b0a20c7 修改为 25470ac6e0585a62。

创建交易并签名广播

在构造 flow 的交易时,我们需要先使用 Cadence 语言编写执行脚本,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ cat > tx.cdc <<EOF
import FungibleToken from 0x9a0766d93b6608b7
import FlowToken from 0x7e60df042a9c0868

transaction(amount: UFix64, to: Address) {

// The Vault resource that holds the tokens that are being transferred
let sentVault: @FungibleToken.Vault

prepare(signer: AuthAccount) {

// Get a reference to the signer's stored vault
let vaultRef = signer.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
?? panic("Could not borrow reference to the owner's Vault!")

// Withdraw tokens from the signer's stored vault
self.sentVault <- vaultRef.withdraw(amount: amount)
}

execute {

// Get a reference to the recipient's Receiver
let receiverRef = getAccount(to)
.getCapability(/public/flowTokenReceiver)
.borrow<&{FungibleToken.Receiver}>()
?? panic("Could not borrow receiver reference to the recipient's Vault")

// Deposit the withdrawn tokens in the recipient's receiver
receiverRef.deposit(from: <-self.sentVault)
}
}
EOF

在 testnet 网络上,FlowToken 的合约地址是 0x7e60df042a9c0868。如果使用主网或者是 emulator,需要替换成对应的合约地址,具体查询:Flow Core Contracts

我们 cdc 代码中定义了 transaction 方法,并且包含两个参数 amount 和 to,我们构造交易时,也要传入对应参数。

我们使用 flow-cli 来构造交易,可以将 flow 发送到 0x72aeca95731d54e5(必须是一个真实创建的地址)。

1
2
3
4
5
6
7
8
9
10
$ flow transactions build ./tx.cdc \
--authorizer emulator-account \
--proposer emulator-account \
--payer emulator-account \
--args-json '[{"type": "UFix64", "value": "1.0"}, {"type": "Address", "value": "0x72aeca95731d54e5"}]' \
--network testnet \
--filter payload \
--save built.rlp

result saved to: built.rlp

我们只保存 payload,我们的接下来对 payload 进行签名,生成签名后的哈希。

1
2
3
4
$ flow transactions sign ./built.rlp --signer emulator-account \
--filter payload --save signed.rlp

result saved to: signed.rlp

广播签名后的交易。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
$ flow transactions send-signed --network testnet ./signed.rlp

Sending transaction with ID: 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7

Status ✅ SEALED
ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Payer 25470ac6e0585a62
Authorizers [25470ac6e0585a62]

Proposal Key:
Address 25470ac6e0585a62
Index 0
Sequence 0

No Payload Signatures

Envelope Signature 0: 25470ac6e0585a62
Signatures (minimized, use --include signatures)

Events:
Index 0
Type A.7e60df042a9c0868.FlowToken.TokensWithdrawn
Tx ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Values
- amount (UFix64): 1.00000000
- from (Address?): 0x25470ac6e0585a62

Index 1
Type A.7e60df042a9c0868.FlowToken.TokensDeposited
Tx ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Values
- amount (UFix64): 1.00000000
- to (Address?): 0x72aeca95731d54e5

Index 2
Type A.7e60df042a9c0868.FlowToken.TokensWithdrawn
Tx ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Values
- amount (UFix64): 0.00010000
- from (Address?): 0x25470ac6e0585a62

Index 3
Type A.7e60df042a9c0868.FlowToken.TokensDeposited
Tx ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Values
- amount (UFix64): 0.00010000
- to (Address?): 0x912d5440f7e3769e

Index 4
Type A.912d5440f7e3769e.FlowFees.TokensDeposited
Tx ID 8a979bd7d0278bada8b9cf57611608a5ba258090ecdddaaa83e2e5d04fe53af7
Values
- amount (UFix64): 0.00010000


Code (hidden, use --include code)

Payload (hidden, use --include payload)

广播后如果 Status 为 SEALED 则发送成功。

我的博客一直是通过netlify来构建部署的,有一次升级hexo后,在netlify构建就失败了,并且一直没有解决这个问题。主要是我本地并没有失败过,所以我就考虑使用新的平台了。

vercel

现在已经切换到了vercel,部署更加简单,配置也更方便,也没有遇到过netlify构建异常。我怀疑是netlify的node版本过低,是8.x的版本。vercel能识别项目使用的框架,非常友好。

ipfs+ipns

去中心化是非常好的选择,如果使用的是ipfs,博客要使用相对路径,修改hexo配置中的relative_link就可以实现。当然也可以配置上ipns,ipns是基于dnslink实现,配置一下dnslink的txt记录即可。当你浏览器装了ipfs-companion的插件后,访问你的博客域名,就会自动重定向到ipfs的资源了。除了ipfs.io,现在cloudflare和infura也提供了ipfs的gateway,当然你也可以下载一个ipfs的软件,运行在本地来充当gateway。

后续更新

2021四月我将博客迁移至cloudflare的pages服务上,这是cloudflare刚上不久的服务,目前还是beta阶段,和vercel的配置是一样的,非常简单,vercel比较麻烦的地方是,需要通过命令行设置一下主域名,这样每次自动构建的页面才会部署在自定义域名上。

当然也可以安装ipfs的浏览器插件,直接访问我的博客,ipfs的gateway推荐使用cloudflare-ipfs.com。

最新加速方案

我讲pyenv-proxy部署在了Cloudflare上,json数据存储在了Cloudflare KV,用了Cloudflare workers 作为Web服务,不依靠我个人的服务器,保证服务的稳定。

新的配置如下:

1
export PYTHON_BUILD_MIRROR_URL="https://pyenv.ibeats.top"

workers代码请查看项:pyenv-proxy

参考文章:如何加速Pyenv

如果做网站加速,CDN是有很多种选择的,如果只做国内业务可以选择任意一家CDN都没问题,国外一般选择CloudFront和Cloudflare。Cloudflare在我看来,使用非常方便,傻瓜都可以操作,基本都是一键设置,不过功能相对于CloudFront少很多,毕竟CloudFront是AWS的一个服务。CloudFront优势在于可以和AWS的其他服务相结合,实现特定的需求。所以我更倾向于使用CloudFront,如果是个人静态博客之类的直接使用Cloudflare足矣。

这两个服务,国外加速效果都非常好,国内访问高峰期,有时会慢到让人无法接受,如果公司使用还是要对国内访问进行加速的,国内加速我更推荐使用CloudFront,虽说Cloudflare有很多黑科技,比如argo之类加速功能,但是比起CloudFront逊色不少。

由于国内特色的网络环境,想要解析到国内的服务器,一定要做网站备案,这就导致Cloudflare和CloudFront在国内并没有加速节点。不过Cloudflare有Partner曲线救国的方式,设置起来就比较麻烦了,而且最终还是逃不过备案。

我最终选择的方案是GeoDNS区域解析,因为域名的NS在Cloudflare托管,所以我优先选择使用Cloudflare的Load Balance,可以根据区域进行自定义解析,从使用体验上讲,该服务收费而且中国IP识别准确率也很低,划分区域相对简单,是根据大陆板块划分,没有根据国家划分区域,所以只好放弃Cloudflare。在一番对比后,国内的DNSPod,AliyunDNS准确率都很高,最后我还是选择了AWS的route53服务。

服务器可以考虑使用Alibaba Cloud的OSS服务,香港的OSS对于国内访问速度还是非常快的,而且比较稳定。将中国的解析执行OSS就可以了。当然这只是前端页面加速,如果是其他业务,也可以使用HAProxy或者Nginx做转发,就可以实现更多特殊的需求了。