分类
linux

在 Fedora 34 上启动 VNC DISPLAY

大家可以先阅读 使用 Node.js 驱动 FFmpeg 在 Linux + vncserver 下完成视频录制 了解产品目标和技术选型。

前两天在系统更新里看到 Fedora 34 发布,作为更新党,我当然迫不及待就升级了。升级过程蛮顺利的,升级后,系统里的“在线账户”也能正常走 VPN 了,感觉还蛮好的。

然后,前两天需要调试录视频的程序,发现新系统的 tigerVNC 有一个巨大的变化:不再支持用 vncserver 命令创建虚拟显示器,必须用 systemctl start service,目的是方便绑定系统启动,因为很多服务器的运维需要自动化。

不过这可苦了我。我是系统运维菜鸡,基本只能照抄文章,搞了半天也没搞好。不过感谢开源,在 GitHub issue 里讨论的只言片语让我知道了其实 vncserver 是个脚本,它调用的其实是 Xvnc 这个命令。

那就好办了,我开始按图索骥,寻找 vncserverXvnc 之间的关联。最终找到解决方法如下:

  1. 修改 /etc/X11/Xwrapper.config,加入 allowed_users=anybody。这样才能直接使用 Xvnc 创建虚拟显示器,不然会报告只有 console 用户才能创建的错误。
  2. 使用 vncpasswd 命令创建密码文件,创建后的密码文件位于 ~/.vnc/passwd
  3. 然后用 Xvnc :5 -geometry 1280x720 -PasswordFile ~/.vnc/passwd 创建显示器,跟之前的命令很类似,不过需要 -PasswordFile 选项指定密码
  4. 使用 VNC viewer 登录 VNC,输入密码。(我不知道这一步是否必须)
  5. 可以继续使用 DISPLAY=:5

不过问题并没有完美解决,虽然我的 puppeteer JS 能跑,FFmpeg 也能录。但是 DISPLAY=:5 firefox https://cn.bing.com 只会在当前屏幕打开窗口,不知道为什么。留待以后解决吧。

最后吐槽下,这种稳定版里换大版本的行为真的要不得,开源团队也不能滥用自己的地位。


参考阅读

分类
linux

Linux 命令行科学上网

前些天因为工作需要,装了 Fedora 33 开发 Showman 的视频录制功能。准备顺势双机工作一段时间,自然也就需要给新系统配置好科学上网。这里简单记录一下过程,方便日后回查。

0. 更新系统

第一部当然是更新系统,保证系统组件均为最新版,这样可以规避大多数问题。

sudo dnf update

1. 使用 pip 安装 shadowsocks 客户端

Fedora 33 自带 python 3.9,所以直接使用 pip 安装 shadowsocks 客户端即可:

sudo pip install shadowsocks

这里可以用 sudo 也可以不用,差别就在于,sudo 之后会将执行脚本安装到 /usr/local/bin;而不带 sudo 则会安装到 ~/.local/bin。两者的执行环境不一样。我无意间使用了后者,所以后面也会按照后者来记录。

2. 配置客户端

接下来编辑配置文件,如果是图形界面,建议使用 IDE,纯命令行的话用 vim 也可以。配置文件一般放在 /etc/shadowsocks.json。内容大概如下,顾名思义,我就不一一解释了:

{
  "server":"server-ip",
  "server_port":8000,
  "local_address": "127.0.0.1",
  "local_port":1080,
  "password":"your-password",
  "timeout":600,
  "method":"aes-256-cfb"
}

与前面 Ubuntu 20.04 科学上网 一样,本文不打算介绍服务器的制备——其实我也不建议大家自己制备服务器,除非你本来就有一些资源或者需求。不然的话,以我的经验,比较出名的迷你 VPS(类似 Vultr,DO,$5/月甚至 $2.5/月),IP 大部分都在规则库里,流量大一点,比如看个视频,不出半个小时 IP 就被封了,然后一个月后解封,基本没法用。

如果你是 macOS 或者 iPhone,或者其它可以用 anyconnect 的系统,可以考虑直接买现成的,比如链接里这个

3. 配置系统代理

然后启动服务:

sslocal -c /etc/shadowsocks.json -d start
  • -c 用来指定配置文件的地址
  • -d 表示启动服务

这里可能会遇到几个问题(也是上次我放弃命令行转投 qt5 客户端的原因)。我们来逐个解决它们:

3.1 openssl 错误

执行后报错:

$ sslocal -c /etc/shadowsocks.json -d start
INFO: loading config from /etc/shadowsocks.json
 2021-05-05 15:17:00 INFO     loading libcrypto from /root/anaconda3/lib/libcrypto.so.1.1
 Traceback (most recent call last):
   File "/root/anaconda3/bin/sslocal", line 8, in <module>
     sys.exit(main())
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/local.py", line 39, in main
     config = shell.get_config(True)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/shell.py", line 262, in get_config
     check_config(config, is_local)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/shell.py", line 124, in check_config
     encrypt.try_cipher(config['password'], config['method'])
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 44, in try_cipher
     Encryptor(key, method)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 82, in __init__
     self.cipher = self.get_cipher(key, method, 1,
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 109, in get_cipher
     return m[2](method, key, iv, op)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py", line 76, in __init__
     load_openssl()
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py", line 52, in load_openssl
     libcrypto.EVP_CIPHER_CTX_cleanup.argtypes = (c_void_p,)
   File "/root/anaconda3/lib/python3.9/ctypes/__init__.py", line 395, in __getattr__
     func = self.__getitem__(name)
   File "/root/anaconda3/lib/python3.9/ctypes/__init__.py", line 400, in __getitem__
     func = self._FuncPtr((name_or_ordinal, self))
 AttributeError: /root/anaconda3/lib/python3.9/lib-dynload/../../libcrypto.so.1.1: undefined symbol: EVP_CIPHER_CTX_cleanup

其中文件、行号可能有所不同,不过错误内容大多一致。

这是因为 OpenSSL 升级至 1.1.0 以上后,内部 API 有一些变化,废弃了 EVP_CIPHER_CTX_cleanup() 函数而引入了 EVE_CIPHER_CTX_reset(),shadowsocks 客户端处于无人维护的状态,没有适配这些变化。

好在修复方案并不复杂,我们只需要修改文件 ~/.local/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py,将里面的 cleanup 都替换成 reset 即可。

3.2 permission denied /var/run/shadowsocks.pid

前面写过,因为我安装的时候没使用 sudo,所以把客户端装在当前用户的目录里。于是面临一个矛盾:

  1. 直接使用当前用户启动客户端,会报告标题里的错误
  2. 使用 root 即 sudo 启动客户端,会报告库有错误(即 3.1),因为我修改的是当前用户的本地库

这里有两个解决方案,一是手动创建 pid,然后修改权限:

sudo touch /var/run/shadowsocks.pid
sudo chmod 777 /var/run/shadowsocks.pid

这个方法重启后会失效,还得再跑一遍。所以我比较推荐另一种做法:使用 sudo -u $user -i 的方式,sudo 的同时仍然使用当前用户的环境(这个方案实测失败了,还要再研究下):

sudo -u meathill -i sslocal -c /etc/shadowsocks.pid -d start

4. 加入自动启动

上一步测试成功之后就可以把这段代码加入 /etc/rc.local,以便实现开机自动启动。

5. 其它步骤

接下来,需要配置 pac 文件、文件服务和系统代理,可以完全参考 Ubuntu 20.04 科学上网 一文。

其中下载 gfwlist.txt 时,如果访问不到 https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt,可以试着修改 /etc/hosts,加入下一行:

199.232.28.133 raw.githubusercontent.com

完成剩余步骤后,配置成功。


在 macOS/iOS 设备上使用科学上网有更简单的方法,扫码可得:

分类
linux

解决 WSL Ubuntu 20.04 下使用 apt 源安装 node.js 的问题

随着 Ubuntu 20.04 发布,各大平台都适配发布了对应版本的系统,Windows WSL 也不例外。如果你是新系统,直接在 Microsoft Store 里搜索并安装 Ubuntu 即可;如果你是老系统,已经装过以前的版本,那么需要先卸载再安装,如果直接安装 Ubuntu 20.04 会有多个不同版本的 Ubuntu 共存。

装完系统后,接着安装其它软件。我现在比较喜欢用包管理工具安装软件,因为容易更新,而我又是更新爱好者。所以按图索骥,找到 node.js 的二进制包安装指引,复制执行:curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - ,结果报错:gpg: can't connect to the agent: IPC connect call failed

经过搜索,得知这是 WSL 版 Ubuntu 20.04 的问题,与 WSL1 有一些不兼容,在 WSL2 上就没这个问题了。解决方案是装一些工具:

sudo add-apt-repository ppa:rafaeldtinoco/lp1871129
sudo apt update
sudo apt install libc6=2.31-0ubuntu8+lp1871129~1 libc6-dev=2.31-0ubuntu8+lp1871129~1 libc-dev-bin=2.31-0ubuntu8+lp1871129~1 -y --allow-downgrades
sudo apt-mark hold libc6

然后问题就解决了。

这个 issue 里还记录了一些别的方案,包括上面方案的修正版,不过我用起来没问题,也就没继续往下看。感兴趣的同学可以研究一下。

分类
linux

解决 Ubuntu 20.04 下无法打开蓝牙的问题

我的 Ubuntu 20.04 启动之后经常丢掉蓝牙。表现是设置里能看到蓝牙,状态是关闭,但是无法打开,每次点击开关过一会儿就恢复了,也没有报错。

因为要连接音箱,没有蓝牙很不方便,就搜索了一下,最后发现下面的解决方案。虽然没理解问题根源,但是解决了就好。

sudo rmmod btusb
sleep 1
sudo modprobe btusb

参考链接:

  1. Bluetooth firmware upload failing after ‘suspend’
  2. Bluetooth used to be enabled, now disabled and won’t enable. Ubuntu 16.04
分类
linux

重置 MariaDB root 密码

以我最常用的 Ubuntu 为例,记录如何重置 MariaDB root 密码。MariaDB 是 MySQL 原作者在 MySQL 闭源之后的再起之作,基本能完全兼容 MySQL。在我的 Ubuntu 上,它的大部分命名都沿用 MySQL。

1. 停掉 mysql 服务

$ service mysql stop

2. 以特殊方式启动 mysql

使用 --skip-grant-tables 可以跳过用户权限检查,让你没有密码也能连接。此时为了避免安全问题,可以加上 --skip-networking,防止有人此时通过网络连接你的数据库。在本地环境下差别不大。

$ sudo mysqld_safe --skip-grant-tables --skip-networking &

这一步可能会启动失败,导致下一步连接时报错:ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ’/var/run/mysqld/mysqld.sock’ (2),此时,可以这样修正:

$ sudo mkdir /var/run/mysqld
$ sudo chown mysql /var/run/mysqld

3. 连接数据库

$ mysql -u root

正常情况下就连上了。

4. 重置密码

mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';

5. 重启 mysql

按照参考文档里介绍的做法,需要

$ sudo kill `cat /var/run/mysqld/mysqld.pid`
# 或
$ sudo kill `/var/run/mariadb/mariadb.pid`

不过我实际操作的时候只要把(2)开启的进程关掉就好了。然后重启 mysql 服务:

$ service mysql restart

6. 完成

尝试一下连接,应该可以成功了:

$ mysql -uroot -p

7. Ghost 连接

虽然命令行连接成功,但是 ghost start 仍然报错,经查,是 Ghost 的数据库连接方式有点问题,修改 config.production.json,加入一行配置即可,大体如下:

{
  "client": "mysql",
  "connection": {
    ....
    "socketPath": "/var/run/mysqld/mysqld.sock",
  }
}
分类
linux

Ubuntu 20.04 科学上网

闲言少叙,直奔主题。

0. 服务器

首先,你得先准备个服务器。本文不讨论如何制备科学上网服务器。

如果你用 Mac 或者 iPhone,想玩 Clubhouse,可以考虑买个现成,比如链接里这个

1. 客户端

接下来,下载客户端。

我用的是 shadowsocks-qt5,先在 https://github.com/shadowsocks/shadowsocks-qt5/releases 这个页面下载打包好的 AppImage 文件。

右键点击文件,在“权限”选项卡里勾选“允许文件作为程序执行”,然后双击运行,配置服务器信息。配置完成,点击“连接”,顺利的话,就会显示连接成功。

在命令行里输入 gnome-session-properties,会启动如下图所示的“启动应用程序首选项”,把刚才下载的 AppImage 路径添加进来,这样每次启动 ss 客户端都会自动启动了。

启动应用程序首选项

2. 生成 pac

安装genpac

pip install genpac

Ubuntu 20.04 默认 python版本是 3,所以可以使用 pip3 替代上面的 pip。

使用在线的 gfwlist

genpac --pac-proxy "SOCKS5 127.0.0.1:1080" --gfwlist-proxy="SOCKS5 127.0.0.1:1080" --gfwlist-url=https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt --output="autoproxy.pac"

使用离线的 gfwlist

如果你的机器没有完成配置,暂时无法访问到 gfwlist,也可以先想办法下载到这个文件,然后离线生成。

genpac --pac-proxy "SOCKS5 127.0.0.1:1080" --gfwlist-proxy="SOCKS5 127.0.0.1:1080" --gfwlist-local=你的路径/gfwlist.txt --output="autoproxy.pac"

3. 配置服务器

Ubuntu 安装时就集成了 Apache2,并且默认也会启动它,所以直接把刚才生成的 pac 文件放在 /var/www/html/ 目录下,就能通过 http://localhost/autoproxy.pac 访问到。

不过我不喜欢用 apache,一般都会用 nginx 或者 openresty 取代之。好在默认情况下,nginx 的 web 服务目录也是 /var/www/html,所以只要卸载 apache 然后重新安装 nginx 即可。另外因为这个服务只为使用 pac 文件,所以可以不用换源。

sudo apt remove apache2
sudo apt update
# 安装 openresty 需要的系统依赖
sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates
# 添加 key
wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
# 添加 openresty 官方源
echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" \
    | sudo tee /etc/apt/sources.list.d/openresty.list
# 在更新一次,然后安装
sudo apt update
sudo apt install openresty
sudo service openresty start

然后访问 http://localhost/autoproxy.pac,如果能打开,就说明配置成功。

4. 启动全局配置

如果,打开“设置”,找到“网络”,打开“网络代理”,选择“自动”,然后填入上面说的 pac 地址即可。

5. 在其它应用里完成配置

比如,打开 Firefox,在“首选项”里找到“网络设置”,然后选择“使用系统代理设置”即可。