0%

运行环境

某S905机顶盒 + TF卡 + Manjaro ARM 21.10

示例说明

假设我们有一个marly.com的域名,且已经使用cloudflare进行解析。在家里的电视盒子上运行了一个http服务:http://localhost:3000,登录linux系统的用户为marly,我们想在外网通过https://world.marly.com访问这个服务,还要有正规证书。通过Cloudflare Tunnel可以方便实现。

如果有公网IP,上通过端口转发 + 调用API自动更新A记录 + Let's Encrypt也可以实现。

  1. 端口转发。本地路由器配置。
  2. 调用API自动更新A记录。GitHub上找到一个看起来不错的项目:NewFuture DDNS。支持DNSPOD,阿里 DNS,DNS.COM,DNSPOD 国际版,CloudFlare,HE.net(不支持自动创建记录),华为云。
  3. 签发Let's Encrypt证书 + 续期。使用ACME即可。

此外还发现ehang-io/nps,不过没完整折腾过。

安装cloudflared

可以直接下载官方预编译的二进制执行文件或者安装包,地址 https://github.com/cloudflare/cloudflared/releases/ ,或者使用yay根据当前最新源码编译安装:

$ yay -s 

如果半天没进度,请检查网络状况。

使用yay安装的cloudflared包含三部分:

/usr/bin/cloudflared /etc/cloudflared /usr/share/man/man1/cloudflared.1.gz

日志文件为/var/log/cloudflared.log,默认文件权限640。cloudflared以普通用户权限运行所以没法读写这个日志文件,可以手动把它改成666:

$ sudo chmod 666 /var/log/cloudflared.log

登录授权

$ cloudflared tunnel login

复制终端上的网址,在浏览器中打开,选择marly.com。认证完成后,cloudflared会生成~/.cloudflared/cert.pem

tunnel创建

$ cloudflared tunnel create hello

上述命令产生如下后果:

  • 根据提供的name,cloudflared会生成一个UUID,与name唯一对应;
  • ~/.cloudflared/中,cloudflared会生成.json文件;

最后使用$ cloudflared tunnel list查看tunnel是否创建成功。

DNS记录生成

连接到应用

$ cloudflared tunnel route dns hello world.marly.com

此步骤在cloudflare后台创建了world.marly.com的CNAME。

连接到网络

$ cloudflared tunnel route ip add <IP/CIDR> <UUID or NAME>

可以使用

$ cloudflared tunnel route ip show

查看是否路由成功。

配置文件创建

cloudflared的配置文件为config.yml,遵循Linux传统,全局文件路径/etc/cloudflared/config.yml,用户文件路径~/.cloudflared/config.yml

全局文件默认内容:

---
logfile: /var/log/cloudflared.log
proxy-dns: true
proxy-dns-address: 127.0.0.1
proxy-dns-port: 5300
proxy-dns-upstream:
        - https://1.1.1.1/dns-query
        - https://1.0.0.1/dns-query

~/.cloudflared/中,创建config.yml文件:

连接到应用

url: http://localhost:8000
tunnel:
credentials-file: /root/.cloudflared/.json

根据自身情况修改,比如应用端口,UUID,以及credentials-file位置。

连接到网络

tunnel:
credentials-file: /root/.cloudflared/.json

tunnel运行

$ cloudflared tunnel run <UUID or NAME>

如果存在多个配置文件(比如同时运行了多条tunnel),建议通过--config指定路径:

$ cloudflared tunnel --config path/config.yaml run

最好使用绝对路径。

检查tunnel状况

列出所有

$ cloudflared tunnel list

检查单个

$ cloudflared tunnel info <UUID or NAME>

运行

调试

cloudflared tunnel run --url http://localhost:3000 hello

作为服务运行

首先准备好config.yml文件:

tunnel: hello
credentials-file: /home/marly/.cloudflared/fe63bc80-7123-65a4-e516-e125b06f0a12.json

ingress:
  - hostname: world.marly.com
    service: http://localhost:3000
  - service: http_status:404

然后将该文件移动到/etc/cloudflare目录下,原有的文件提前改名或删除。

安装服务:sudo cloudflared service install 。cloudflare文档说明此步骤会自动将~/.cloudflared/config.yml复制到/etc/cloudflared中,但实际测试找不到配置文件,故手动复制。

启动服务:

sudo systemctl enable cloudflared
sudo systemctl start cloudflared

前言

Rocket.Chat是一个开源,可定制的交流平台,支持docker和snap。本文介绍在Manjaro ARM的安装方式。

安装

首先安装snap:

sudo pacman -Sy snapd
sudo snap install rocketchat-server

然后在浏览器中,访问服务器的3000端口就行了。注意3000端口常用(比如mdbook就会默认占用),注意不要冲突。

完成安装后,系统会自动配置好相应服务,默认开机启动,不需要额外配置:

systemctl status snap.rocketchat-server.rocketchat-server.service
● snap.rocketchat-server.rocketchat-server.service - Service for snap application rocketchat-server.rocketchat-server
     Loaded: loaded (/etc/systemd/system/snap.rocketchat-server.rocketchat-server.service; enabled; vendor preset: disabled)
     Active: active (running) since Thu 2021-10-28 15:41:03 CST; 2min 58s ago
   Main PID: 443 (startRocketChat)
      Tasks: 25 (limit: 664)
     Memory: 544.6M
        CPU: 2min 10.298s
     CGroup: /system.slice/snap.rocketchat-server.rocketchat-server.service
             ├─ 443 /bin/bash /snap/rocketchat-server/1460/bin/startRocketChat
             └─1140 node /snap/rocketchat-server/1460/main.js

Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |      MongoDB Version: 3.6.21            |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |       MongoDB Engine: wiredTiger        |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |             Platform: linux             |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |         Process Port: 3000              |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |             Site URL: http://localhost  |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |     ReplicaSet OpLog: Enabled           |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |          Commit Hash: 5e9f4bc424        |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |        Commit Branch: HEAD              |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ |                                         |
Oct 28 15:43:41 marly-aml rocketchat-server.rocketchat-server[1140]: ➔ +-----------------------------------------+

服务启动比较慢,如果systemctl status snap.rocketchat-server.rocketchat-server.service提示ERROR: ld.so: object '/usr/lib/libgtk3-nocsd.so.0' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.,等待3分钟即可。

性能

参考官方文档,4核1G内存的树莓派2或者3配合32G存储卡,能够满足大约50个用户同时使用。对于S905盒子而言毫无压力。

前言

2021年9月15日,人民银行、网信办、最高人民法院、最高人民检察院、工业和信息化部、公安部、市场监管总局、银保监会、证监会、外汇局联合印发《关于进一步防范和处置虚拟货币交易炒作风险的通知》(银发〔2021〕237号),明确虚拟货币相关业务活动属于非法金融活动。不过掌握虚拟货币的基本概念,以及对其工具具备认知仍具备正面意义。本文介绍了在Manjaro ARM平台运行hummingbot过程,仅供学习用途。

在Docker中运行

下载一键脚本

wget https://raw.githubusercontent.com/CoinAlpha/hummingbot/development/installation/docker-commands/create.sh
wget https://raw.githubusercontent.com/CoinAlpha/hummingbot/development/installation/docker-commands/start.sh
wget https://raw.githubusercontent.com/CoinAlpha/hummingbot/development/installation/docker-commands/update.sh

给脚本添加可执行权限

chmod a+x *.sh

创建hummingbot实例

./create.sh

第一步提示hummingbot镜像版本,对于ARM平台当然需要使用ARM标签。hummingbot更新比较频繁,可以到 https://hub.docker.com/r/coinalpha/hummingbot/tags 查看。

常用docker命令

列出container:docker container ps

查看container实时状态:dockerc container stats

启动container:docker start hummingbot-instance

连接到container:docker attatch hummingbot-instance

断开container:Ctrl + P 然后 Ctrl + Q (container在后台继续运行)

至成稿时,最新版本为version-0.43.1-arm_beta

小结

刚创建的hummingbot-instance约占用374MB内存以及不低于20%的CPU,CPU有时还会满载,1G内存的S905盒子跑起来略吃力。如果用Manjaro ARM Minimal搭建最小化运行环境可能会略微改善。笔者没有交易所账号,没有进行更深入测试。

源码安装

源码安装比较麻烦,不过可以实现:

源码拉取

https://github.com/coinalpha/hummingbot

python包安装

官方在树莓派上的教程有些过时了。杂糅下教程中引用的和setup/requirements-arm.txt包,共需要这些依赖:

0x-contract-wrappers 0x-order-utils aioconsole aiohttp aiokafka aioresponses attrdict binance cachetools coverage cython diff-cover eth_account eth_bloom ethsnarks-loopring flake8 idna-ssl jwt mypy_extensions nose numpy objgraph pandas pre-commit prompt_toolkit psutil pyinstall pyjwt pyperclip python-binance python-telegram-bot rsa ruamel.yaml signalr-client-aio simplejson sqlalchemy telegram tzlocal ujson web3 websockets

解决粘贴问题,再加上QtPy

另外值得指出,hummingbot依赖sqlalchemy提供的RowProxy。但是在sqlalchemy1.4中,RowProxy被移除了,所以这个包需要用旧版本。

pip官方源在国内下载很慢,故使用-i选项指定清华镜像。

pip install 0x-contract-wrappers 0x-order-utils aioconsole aiohttp aiokafka aioresponses attrdict binance cachetools coverage cython diff-cover eth_account eth_bloom ethsnarks-loopring flake8 idna-ssl jwt mypy_extensions nose numpy objgraph pandas pre-commit prompt_toolkit psutil pyinstall pyjwt pyperclip python-binance python-telegram-bot rsa ruamel.yaml signalr-client-aio simplejson sqlalchemy telegram tzlocal ujson web3 websockets QtPy -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install --user SQLAlchemy==1.3.6  -i https://pypi.tuna.tsinghua.edu.cn/simple

这样python依赖包就安装好了。

Miniforge3安装

wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-aarch64.sh
chmod u+x Miniforge3-Linux-aarch64.sh 
./Miniforge3-Linux-aarch64.sh 

装好后,重新登录系统以使conda命令生效。

hummingbot编译

cd hummingbot
./clean && ./compile

hummingbot运行

hummingbot源码根目录下,执行bin/hummingbot.py。首次运行会进行一些初始化配置,按提示操作即可。

小结

用源码折腾很麻烦,CPU照样满载,docker至少方便一些。

Manjaro ARM官方制作维护了许多开箱即用的镜像,不过同时提供了打包工具,可以用来自行制作镜像包或启动TF卡/U盘。

Manjaro提供了2个工具,manjaro-arm-tools和manjaro-arm-installer。manjaro-arm-tools可生成镜像包,目前仅支持Manjaro。manjaro-arm-installer用于直接制作启动盘,可运行在任意发行版。也可以通过创建loop设备方式,将镜像写入磁盘,方便分发使用。

本例中,在deepin上配置使用manjaro-arm-installer。

下载manjaro-arm-installer

manjaro-arm-installer就是一个bash脚本,下载地址: https://gitlab.manjaro.org/manjaro-arm/applications/manjaro-arm-installer/-/tags 选择最新的即可。

安装依赖

该脚本依赖:

"git" "parted" "systemd-nspawn" "wget" "dialog" "bsdtar" "openssl" "awk" "btrfs" "mkfs.vfat" "mkfs.btrfs" "cryptsetup"

大部分依赖系统已预装,或者直接按包名安装即可,注意在deepin中,systemd-nspawnsystemd-container提供。

另外qemu-user-static也要安装。装好后,进入/usr/lib/binfmt.d。这个目录下针对不同架构有许多文件,我们的盒子是aarch64架构,所以将qemu-aarch64-static.conf复制一份,改名为qemu-static.conf

执行脚本

按提示进行选择机型、版本、设置用户名密码、时区等操作即可。建议全程出国上网,直连下载rootfs很慢(约170.11M)。完成后,对应TF卡/U盘存在fat与ext4两分区,用过Armbian的应该很熟悉下步配置了。

硬件

R3300-M一台,TF卡一个(运行Manjaro ARM),拆机硬盘DIY的移动硬盘一个。电源用12V 2A的,1A的带硬盘不够。

安装

sudo pacman -Sy transmission-cli

配置文件

sudo vim /var/lib/transmission/.config/transmission-daemon/settings.json

以下为常用配置,设置下载队列大小,下载路径,缓存等。对于一个headless下载机而言能够远程访问很重要,所以建议把局域网地址添加到rpc-whitelist中。

"cache-size-mb": 50,
"download-dir": "/mnt/transmission",
"download-queue-size": 50,
"download-dir": "/mnt/transmission",
"rpc-whitelist": "192.168.1.*,127.0.0.1,::1",

启动服务

sudo systemctl enable transmission
sudo systemctl start transmission

transmission-cli贴心地提供了系统服务,启用即可。

运行smb服务

下篇讲解。

需要开机自动执行的脚本

#!/bin/bash
# rustdocs.sh
# 别忘记给它可执行权限
/home/marly/.cargo/bin/mdbook serve -n 0.0.0.0 -p 3000 /home/marly/Documents/rust/trpl-zh-cn&
/home/marly/.cargo/bin/mdbook serve -n 0.0.0.0 -p 4000 /home/marly/Documents/rust/rust-by-example-cn&

第一行如果末尾不加”&”,第二句命令就不会执行。

另外脚本启动发生在marly登录bash之前,所以类似.bash_profile中自定义的$PATH无效,需要使用绝对路径。

systemd服务

[Unit]
Description=Start rust doc service on boot
Requires=network-online.target
Documentation=man:rustc

[Service]
User=marly
Type=forking
ExecStart=/home/marly/.local/bin/rustdocs.sh

[Install]
WantedBy=multi-user.target

把它命名为 rustdoc-start.service 即可,必须以.service结尾。

启动服务

将上述service文件放置在/etc/systemd/system/usr/lib/systemd/system/中,然后执行sudo systemctl enable rustdoc-start.service。完毕后重启设备观察效果,如无意外mdbook服务会自动启动。

注意sudo systemctl enable rustdoc-start.service的细节。此步骤在/etc/systemd/system/multi-user.target.wants创建了指向rustdoc-start.service的同名符号链接。

分析

上面的User,Type,ExecStart,WantedBy是重点。User=marly即以用户marly身份执行,ExecStart为所执行命令,本例中即刚才编写的脚本路径。WantedBy决定了服务启动时机,multi-user.target对应的系统状态大致为: (参考自 Why do most systemd examples contain WantedBy=multi-user.target?)

multi-user.target normally defines a system state where all network services are started up and the system will accept logins, but a local GUI is not started. This is the typical default system state for server systems, which might be rack-mounted headless systems in a remote server room.

所有网络服务已启动,系统已经做好接受登录的准备,但是GUI还未启动。对于无头服务器而言,这是默认的系统状态。

本例需要对外提供网络服务,所以WantedBy=multi-user.target是合适的。

最后是Type,有simple, exec, forking, oneshot, dbus, notify, idle几种类型。借用下金步国先生的翻译

如果设为 forking ,那么表示 ExecStart= 进程将会在启动过程中使用 fork() 系统调用。 也就是当所有通信渠道都已建好、启动亦已成功之后,父进程将会退出,而子进程将作为主服务进程继续运行。 这是传统UNIX守护进程的经典做法。 在这种情况下,systemd 会认为在父进程退出之后,该服务就已经启动完成。 如果使用了此种类型,那么建议同时设置 PIDFile= 选项,以帮助 systemd 准确可靠的定位该服务的主进程。 systemd 将会在父进程退出之后 立即开始启动后继单元。

个人理解,执行rustdocs.sh本身创建了一个进程,其中的两条mdbook命令又创建了2个子进程。只有2个子进程存续,我们的rust doc服务才能访问。所以oneshot,simple等都不行。

简单验证一下猜想:

$ ps x | grep rust
    403 ?        Sl     0:05 /home/marly/.cargo/bin/mdbook serve -n 0.0.0.0 -p 3000 /home/marly/Documents/rust/trpl-zh-cn
    404 ?        Sl     0:05 /home/marly/.cargo/bin/mdbook serve -n 0.0.0.0 -p 4000 /home/marly/Documents/rust/rust-by-example-cn
  63046 pts/0    S+     0:00 grep rust

验证成功。再顺便看看进程的owner:

$ stat -c '%U' /proc/403 /proc/404
marly
marly

符合预期。

Manjaro ARM软件仓库里可用内核有三个分支:mainline,aml,vim,都有对应的headers。

mainline

更新最快,理论上被投入的开发维护资源更多。如果用mainline kernel一切正常,就选它好了。

aml

可能对Amlogic SOC有加成?我没发现。

vim

可能对vim板子有加成?

用刷入ATV底包的R3300-M盒子测试,三者都能正常启动运行,但是只有vim内核poweroff与reboot正常,故切换到vim内核。

sudo pacman -Sy linux-vim linux-vim-headers

编译WIFI驱动小小修改一下:

git clone https://github.com/jwrdegoede/rtl8189ES_linux.git
cd ~/rtl8189ES_linux/
make -j4 ARCH=arm64 KSRC=/usr/lib/modules/$(uname -r)/build
sudo cp 8189es.ko /usr/lib/modules/$(uname -r)/kernel/drivers/net/wireless/realtek/
sudo depmod -a
sudo modprobe 8189es

直接指定架构为arm64进行编译即可。

首先推荐两个教程:
*. Rust 程序设计语言(第二版 & 2018 edition) 简体中文版
*. 通过例子学 Rust

以上教程均可在线阅读,不过也可下载到本地阅读。以通过例子学 Rust为例:

$ git clone https://github.com/rust-lang-cn/rust-by-example-cn
$ cd rust-by-example-cn
$ cargo install mdbook
$ mdbook build
$ mdbook serve

在arm设备上远程操作,建议新建screen以免意外连接丢失重新来过。另外我需要从其他设备访问文档页面,默认的mdbook server只允许localhost访问,需要略微修改:

mdbook serve -n 0.0.0.0

这样局域网其他设备就可以在浏览器中通过3000端口阅读文档了。如果需要更换端口号,可以通过-p自行指定。

安装

sudo pacman -Sy rust

换国内源

参考自解决Rust – update crates.io过慢的问题

vim ~/.cargo/config

添加以下内容:

# 放到 `$HOME/.cargo/config` 文件中
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"

# 替换成你偏好的镜像源
replace-with = 'sjtu'
#replace-with = 'ustc'

# 清华大学
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

# 中国科学技术大学
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

# 上海交通大学
[source.sjtu]
registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index"

# rustcc社区
[source.rustcc]
registry = "git://crates.rustcc.cn/crates.io-index"

查看文档

使用cargo doc生成的文档为网页形式,可以用python建立服务器然后在浏览器中查看。

# 首先进入doc目录
python -m http.server 8000

然后在浏览器中访问即可。python服务器默认端口为8000,无特别要求可省略。

Manjaro Sway默认的bash提示符看起来类似oh-my-zsh比较美观,简单分析后发现使用了silver

图示

A cross-shell customizable powerline-like prompt heavily inspired by Agnoster. The faster rust port of bronze.

silver是一个跨平台、方便配置的类powerline提示符,从bronze移植而来。bronze是用go开发的,目前已经停止维护了,其git页面上显示用rust写的silver比它快50%,其配置文件通用所以老用户迁移很容易。bronze大量参考了Agnoster这个zsh主题。

目前silver支持 Powershell, Bash, Zsh, fish, Ion 和Elvish。

silver的图标由nerd字体提供。这个字体囊括了常用图标库,比如Font Awesome就包含其中。
diagram

Manjaro Sway中,silver.toml位于~/.config/silver,可根据自身喜好修改。

[[left]]
name = "status"
color.background = "black"
color.foreground = "white"

[[left]]
name = "user"
color.background = "yellow"
color.foreground = "black"

[[left]]
name = "dir"
color.background = "blue"
color.foreground = "black"

[[left]]
name = "git"
color.background = "green"
color.foreground = "black"

[[left]]
name = "cmdtime"
color.background = "magenta"
color.foreground = "black"

需要指出,在bash中,cmdtime不可用,故不会显示。