CI_Knight

且行善举,莫问前程。

0%

博客总是有一些奇怪的排版,尤其是中引文混用的时候,就像下面这样。

一般文字排版都是CSS的text-align属性控制的,当调整text-align属性时,文字会相应的使用不同的对齐方式。但上面这种是因为英文单词截断方式导致的,纯汉字或者纯英文一行不会发生这样的问题,而且换行位置正好是有连接符的,这就让我猜想应该是英文字符截断有关。直接通过chrome调试,更改连接符位置,果然会重新换到连接符的位置换行。那这时候就应该调整word-break了。

但纯的调整text-align不能达到美化的效果,会导致每行行数不一。所以调整word-break到break-all就可以了,具体的也可以根据不同浏览器适配来调整。

因为网站大多是自适应排版,除非固定post-body的宽度,才能做到比较好看的排版。也或者hexo有自动截断英文单词并且添加连接符的插件,这种插件当然我没有找到,如果有人知道可以告诉我。现在的排版已经好很多了,不会再出现非常难看的超宽字距了,况且也不能和专业排版软件比。

还有一天就国庆了,现在满脑子都在想给祖国庆生。不过这样重大的节日,翻墙总是会出些问题,为了应对这样的问题,应该提前多建几个代理服务器,那我就选了一台 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 申请证书,也可以使用自己购买的证书。

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