作者归档:admin

在物理机上全新安装 Ubuntu 的一些坑

起因是这样的,老板表示都搞 Research 了,日常使用就用 Ubuntu 吧……然后就在一台 Dell Optiplex 5060 上装起了 Ubuntu。

这台机器本身没有 SSD,IT 搬过来的时候系统就装在一块 500G/7200rpm 的海门酷鱼上(ST500LM034)。9102 年了,我用 SSD 装系统都用了 7 年了,没有 SSD 的机器完全没法用,遂购入一块 NVMe SSD 插在了 M.2 接口上,然后插入 xubuntu 安装 U 盘开始重装。

这时候问题来了,尽管在 BIOS 里能看到,但是 Ubuntu 死活检测不到那块 NVMe。经多处查询,发现可以尝试在 BIOS 中把默认的 SATA 模式改成 AHCI,而不是 RAID,改过来以后,就没问题了。此处要吐槽一下 Dell 知识库,里面写的完全是反的,表示应该把 AHCI 模式改成 RAID,我信你就有鬼了。

安装流程很快完成以后,又出现了另外一个问题,xubuntu 18.04.3 已经默认使用了 HWE Kernel,在尝试安装 openssh-server 的时候,表示有部分依赖无法满足。之前遇到这个问题的时候,尝试过 aptitude,给出的方案之一是降级大量的软件包,但是这样之后把系统的包搞得一团糟,apt 已经完全无法正常使用。考虑到默认使用的是 HWE kernel,在 aptitude 降级的时候也出现过卸载带 hwe 后缀的软件包,安装不带 hwe 后缀的软件包的操作,因此怀疑是软件源的问题。

于是在这里生成新的软件源列表,注意勾选 main restricted universe multiverse、security updates 和 backports 这些,生成链接之后,复制到 /etc/apt/sources.list 中。在 apt udpate 之后,发现整个系统终于能正常工作了。现在看来,ubuntu 18.04 使用 HWE Kernel 的版本在默认的软件源列表上是有坑的,似乎是 bionic-updates 没有被包含在其中,造成软件包版本混乱的问题。

在解决了这些问题之后,似乎至少能正常使用了。

iKoula 独服在 netplan.io 下配置 IPv6

netplan.io 实在是太烂了

假设 IPv4 地址是 AAA.BBB.CCC.DDD,修改 /etc/netplan/01-netcfg.yaml

# Network configuration file
# Auto generated by Ikoula

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
      addresses: 
        - AAA.BBB.CCC.DDD/24
        - "2a00:c70:1:AAA:BBB:CCC:DDD:1/96"
      gateway4: AAA.BBB.CCC.1
      gateway6: 2a00:c70:1:AAA:BBB:CCC::1
      nameservers:
        addresses: [213.246.36.14,213.246.33.144,80.93.83.11]

之后 netplan try 验证格式并回车应用,或者直接 netplan apply

WordPress 迁移

从……大概一年多以前?Offline 要涨价开始,我就说要抛弃他家 Scaleway,转到 Hetzner Cloud 上来,然而因为懒……所以就一直没弄。今天突发奇想就弄了一下。

WordPress 迁移的方法有很多,可以考虑底层的方法把网站目录、数据库和 nginx 配置文件连锅端,也可以用一些插件辅助完成这个事情。出于懒……我个人选择了插件。

在这个迁移中使用的是 All-in-One WP Migration 插件,其作者声称可以直接打包把站点导出,包含所有的文章、主题以及插件信息。为了测试该插件能否正常工作,我首先使用了另一个二级域名并安装 WordPress 作为测试平台,很顺利地完成了导入以后,就开始了主域名的迁移工作。

由于我的环境是 Oneinstack 的 LNMP 一件包,其 vhost 管理并没有提供相应的更改域名功能,在阅读了代码之后,发现其功能似乎是 stateless 的,也就是说包括 vhost 列表的查询以及 Let’s encrypt 证书管理在内都通过读取对应应用程序的配置文件完成,而非本地再对已有的域名进行配置文件的保存。这样的设计为我之后要干的事情提供了极大的方便,即手动更改本地域名地址之后,只要不变动文件夹结构,就不会影响该脚本的后续使用。

迁移这个简单的 WordPress 站点(没什么特殊配置,都在 WP 框架内完成,因此使用迁移插件即可),需要做的有这样几件事:

  • 导出原站点
  • 在新 VPS 上建立 vhost,并申请 Let’s encrypt 证书
  • 安装 WordPress
  • 导入原站点

需要注意的一点是,如果需要在 vhost 中更改域名,一定要在安装 WordPress 之前完成,因为 WordPress 似乎根据安装时保存在 MySQL 数据库中的网址自行进行 301 跳转,即使更改了 nginx 中的网址,Wordpress 仍然会在后续访问中跳转会原来的地址,进而会导致 https 证书地址不匹配的问题。

这个问题最开始是在完成了使用测试域名的导入以后,想更换为原来的主域名时发生的。在使用 acme.sh 生成证书并安装,且完成 nginx config 中的证书路径修改之后:

acme.sh --issue -d <domain> --webroot <web_root_dir>
acme-sh --install-cert -d <domain> --key-file /usr/local/nginx/conf/ssl/<domain>.key --fullchain-file /usr/local/nginx/conf/ssl/<domain>.crt --reloadcmd  "service nginx force-reload"

在访问原网址时仍然会跳转到之前使用的测试网址,这让我百思不得其解。在删除网站根目录下的所有文件,重新生成证书以及 vhost 配置文件等方法均无果之后,我使用了使用 curl -I 查看调试信息:

# curl -I https://blog.gloriousdays.pw
HTTP/2 301
server: nginx
date: Sun, 25 Aug 2019 16:36:56 GMT
content-type: text/html; charset=UTF-8
location: https://blog2.gloriousdays.pw/
x-redirect-by: WordPress
strict-transport-security: max-age=15768000

可以看到似乎是由 WordPress 完成的 301 跳转。与之相对的正常访问和 nginx 完成的 301 跳转是这样:

# curl -I https://blog.gloriousdays.pw
HTTP/2 200
server: nginx
date: Sun, 25 Aug 2019 17:46:59 GMT
content-type: text/html; charset=UTF-8
content-length: 41183
vary: Accept-Encoding
vary: Accept-Encoding, Cookie
cache-control: max-age=3, must-revalidate
last-modified: Sun, 25 Aug 2019 17:34:44 GMT
strict-transport-security: max-age=15768000

# curl -I http://blog.gloriousdays.pw
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 25 Aug 2019 17:47:03 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: https://blog.gloriousdays.pw/
Strict-Transport-Security: max-age=15768000

这样似乎就定位了问题所在,Wordpress 在某个地方存储了网站的地址,并且依照其进行跳转。后来想到,在进行网站测试导入时,已经完成了 WordPress 安装并连接了数据库,在之前删除网站目录文件重新放入 WordPress 安装包的时候也没有进行清除,或许那个数据库才是问题所在。于是果断进入 mysql 命令行 drop database,并重新进行安装和导入站点流程,这时候网站就已经正常工作了。

总结一下的话,就是在安装 WordPress 之后一定不要更改 nginx 对应的域名,说实话这也很奇怪,301 跳转这个功能委托给 nginx 完成就好,WP 何必多此一举呢。

修改 Linux 默认 locale 使得非 ASCII 字符在 ssh 下可以正常显示

一般来说,如果没有进行过特殊配置的话(比如说我们用 debootstrap 安装的系统),其默认 locale 会是 POSIX,我们使用 locale 命令可以看到这个情况。

# locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

C 是系统默认的 locale,而 POSIX 是 C 的别名,因此这里看到的情况就是默认的 C Locale。它所指定的属性和行为由 ISO C 标准所指定。当我们新安装完一个系统时,默认的 locale 就是 C 或 POSIX。我们这里说的 C 其实就是 ASCII 编码。

但是我们同样也知道,标准的 ASCII 字符集中是不包含中文、日文等字符的,因此如果 POSIX 作为系统默认的 locale,那么会遇到在 SSH 下无法正确显示这些字符的问题,会直接按字节解析为 ASCII 转义字符,因此要想更正这个情况只有修改系统默认的 locale。

通过 locale -a 可以查看当前系统可用的所有 locale:

# locale -a
C
C.UTF-8
POSIX
en_US.utf8

显然,en_US.utf8 是一个好选择。

下面贴过来一段对上文中提及的 LC_* 环境变量的接释:

  • LANG
    LANG的优先级是最低的,它是所有 LC_* 变量的默认值。下方所有以 LC_ 开头变量(不包括LC_ALL)中,如果存在没有设置变量值的变量,那么系统将会使用 LANG 的变量值来给这个变量进行赋值。如果变量有值,则保持不变,不受影响。可以看到,我们上面示例中的输出中的 LC_*变量的值其实就是 LANG 变量决定的
  • LC_CTYPE
    用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等,这个变量是最重要的。
  • LC_NUMERIC
    用于格式化非货币的数字显示。
  • LC_TIME
    用于格式化时间和日期。
  • LC_COLLATE
    用于比较和排序。
  • LC_MONETORY
    用于格式化货币单位。
  • LC_MESSAGES
    用于控制程序输出时所使用的语言,主要是提示信息,错误信息,状态信息, 标题,标签, 按钮和菜单等。
  • LC_PAPER
    默认纸张尺寸大小
  • LC_NAME
    姓名书写方式
  • LC_ADDRESS
    地址书写方式
  • LC_TELEPHONE
    电话号码书写方式
  • LC_MEASUREMENT
    度量衡表达方式
  • LC_IDENTIFICATION
    locale对自身包含信息的概述
  • LC_ALL
    它不是环境变量,它是一个宏,可通过该变量的设置覆盖所有的 LC_* 变量。这个变量设置之后,可以废除 LC_* 的设置值,使得这些变量的设置值与 LC_ALL 的值一致,注意,LANG 变量不受影响。在这里,这个宏操作就是用 LC_ALL 的值去覆盖 LC_* 的变量值

从描述中可以看出,优先级级别:LC_ALL > LC_* > LANG

注意:定义这么多变量在某些情况下是很有用的,例如,当我需要一个能够输入中文的英文环境,我可以把 LC_CTYPE 设定成 zh_CN.GB18030,而其他所有的项都是 en_US.UTF-8。

如果我们要修改这个默认的变量,可以在自己的 ~/.bashrc 中进行 export,比如我加入了这两行:

export LANG=en_US.utf8
export LC_CTYPE=en_US.utf8

之后重新登录一下就可以正常显示 Unicode 字符了。

Ubuntu 18.04 配置 Online IPv6

Ubuntu 的 netplan.io 实在是太烂了

Online 的 IPv6,之前写过一篇,是通过 /etc/network/interfaces 文件中的 pre-up 字段运行 dhclient 宣告 DUID,然而在 Ubuntu 18.04 中,ifupdown 换成了 netplan.io,原来的方法就不能用了。此外,dhclient 在每次运行的时候会清空当前 iface 上的 IPv6 地址,这个也给 netplan 造成了麻烦。在折腾之后有了一种解决办法:

  • 在 netplan 配置文件中写入静态 IPv6 地址(同 /etc/network/interfaces)
  • 使用 systemd 运行 dhclient
  • 在运行 dhclient 之后再次执行 netplan apply

需要写入如下文件:

/etc/dhcp/dhclient6.conf

interface "<iface>" {
  send dhcp6.client-id <DUID>;
  request;
}

/etc/systemd/system/dhclient.service

[Unit]
Description=dhclient for sending DUID IPv6
Wants=network.target
Before=network.target

[Service]
Type=forking
ExecStart=/sbin/dhclient -cf /etc/dhcp/dhclient6.conf -6 -P -v <iface>

[Install]
WantedBy=multi-user.target

/etc/systemd/system/dhclient-netplan.service

[Unit]
Description=redo netplan apply after dhclient
Wants=dhclient.service
After=dhclient.service
Before=network.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/netplan apply

[Install]
WantedBy=dhclient.service

该文件在 dhclient.service 改变状态之后执行,注意该 oneshot 不能使用 RemainAfterExit=True,不然在 restart dhclient 以后,不能再次执行 netplan apply。

/etc/netplan/01-netcfg.yaml

# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    <iface>:
      dhcp4: yes
      dhcp6: no
      accept-ra: yes
      addresses:
      - <IPv6>/56

即可。

参考资料:

https://documentation.online.net/en/dedicated-server/network/network-configuration-with-netplan
https://documentation.online.net/en/dedicated-server/network/ipv6/prefix
https://askubuntu.com/questions/1031853/how-to-set-up-ipv6-with-netplan-on-ubuntu-18-04?rq=1
https://lafibre.info/scaleway/configurer-une-ipv6-online-net-sur-ubuntu-18-04/
https://unix.stackexchange.com/questions/219940/getting-a-service-started-automatically-when-another-gets-started

Online Dedibox IPv6 配置

Ubuntu 18.04 配置 HE Tunnelbroker

Ubuntu 18.04 配置 HE Tunnelbroker

我无比怀念 Ubuntu 还在用 ifupdown 的年代,netplan.io 什么垃圾玩意。

起因是这样的,看阿里云打折,所以买了一个轻量 HK 来玩。阿里云的机器嘛,拿到手第一件事肯定是跑脚本重装系统,然后就默认装了最新的 Ubuntu 18.04。接下来发现,这机器没有 IPv6,于是就打算配置一下 HE Tunnelbroker,这时候问题就出现了,18.04 默认已经没有 ifupdown 而改用 netplan.io,HE 也没有提供 netplan 的样例配置。考虑到用新不用旧的原则(类比 systemd 和 Ubuntu upstart/update-rc.d),于是想折腾一下 netplan。

netplan 官网上宣称,它可以配置 6in4 Tunnel,还在官方示例(https://netplan.io/examples)最下面给出了对应的语法,然而在最新的 Ubuntu 内置版本上,tunnels 这个关键字根本不识别。查询 bug 发现在 https://bugs.launchpad.net/netplan/+bug/1799487 这里有人提到 netplan 无法使用 6in4 tunnel 的问题,也提出了一个使用 systemd-networkd 的解决方案。netplan 的 tunnel 支持根据这个 bug report 的说法,已经在一月初 commit,可能还没合并到软件包的版本里面吧。

阿里云的镜像,默认的网络配置是在 /etc/netplan/01-netcfg.yaml 中,默认是 DHCPv4 的方式获取内网 IP。我们先通过这里看到 v4 interface 的名称,比如 ens3。之后创建如下文件:

/etc/systemd/network/he-ipv6.netdev

[NetDev]
Name=he-ipv6
Kind=sit
MTUBytes=1480

[Tunnel]
Local=<local IPv4 address> # should be the internal IPv4 address on Aliyun instead of the public IPv4 address
Remote=<tunnel server IPv4 address>
TTL=64

/etc/systemd/network/he-ipv6.network

[Match]
Name=he-ipv6

[Network]
Address=<Client IPv6 Address>/64
Gateway=<Server IPv6 Address>

/etc/systemd/network/10-netplan-<iface name>.network.d/tunnel.conf
e.g. /etc/systemd/network/10-netplan-ens3.network.d/tunnel.conf

[Network]
Tunnel=he-ipv6

表示在默认的 v4 interface 上创建 tunnel。之后 systemctl restart systemd-networkd 即可

或者也可以使用 ip 命令在一个 systemd service 中完成添加:

[Unit]
Description=he.net IPv6 tunnel
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ip tunnel add he-ipv6 mode sit remote <server IPv4 address> local <client IPv4 address> ttl 255
ExecStart=/sbin/ip link set he-ipv6 up mtu 1480
ExecStart=/sbin/ip addr add <client IPv6 address> dev he-ipv6
ExecStart=/sbin/ip -6 route add ::/0 dev he-ipv6
ExecStop=/sbin/ip -6 route del ::/0 dev he-ipv6
ExecStop=/sbin/ip link set he-ipv6 down
ExecStop=/sbin/ip tunnel del he-ipv6

[Install]
WantedBy=multi-user.target

 

关于 qb 有可能遇到 ICE default IO error handler doing an exit() 的问题

在一些性能比较弱的机器上,比如 N2800,运行 qb 时可能会报错 ICE default IO error handler doing an exit()。

说实话这是一个比较莫名其妙的错误,ICE 是一个 X client 之间通信的协议,可能是 Qt 在后台有什么操作吧。StackOverflow 上对于这个错误的解决方法是删除 ~/.ICEauthority 文件,然后就好了。我猜可能是 qb 启动如果卡太久 GUI 出不来的话会把这个文件搞坏,然后再启动的时候读取这个文件就炸了,删除这个文件以后 Qt 可能会报一个 warning,authentication failure 之类的,这个不影响运行,而且 qb 也不会炸了。

这个文件在每次启动桌面时会自动生成,因此已加入 qb 自动重启脚本中的错误检测豪华套餐。

关于 VSCode 在 VNC 下可能无法正常使用的问题

code –verbose 后报错:

[20447:0201/143519.959342:ERROR:browser_main_parts.cc(139)] X IO error received (X server probably went away)

这个似乎是一个 Electron 里面的 bug,一个可行的解决方案为:

# make a copy of the relevant library
mkdir ~/lib
cp /usr/lib/x86_64-linux-gnu/libxcb.so.1 ~/lib
sed -i 's/BIG-REQUESTS/_IG-REQUESTS/' ~/lib/libxcb.so.1
# set the dynamic loader path to put your library first before executing VS Code
LD_LIBRARY_PATH=$HOME/lib code

即修改一下 libxcb.so.1 之后再执行

对于 .desktop 文件启动的 VSCode(桌面的菜单项),将上述修改的 .so 文件复制到比如 /opt/code_lib 下,将 /usr/share/applications/code.desktop 中的 Exec 项修改为:

Exec=sh -c "env LD_LIBRARY_PATH\=/opt/code_lib /usr/share/code/code" %U

即可

关于在 VNC 中可能无法使用 Tab 键的问题

仅作为记录,似乎这是个 Ubuntu 16.04 的 bug,在 18.04 中已经被修正

在 ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml 中找到这样一行:

<property name="&lt;Super&gt;Tab" type="string" value="switch_window_key"/>

<property name=”&lt;Super&gt;Tab” type=”string” value=”switch_window_key”/>

改成

<property name="&lt;Super&gt;Tab" type="empty"/>

<property name=”&lt;Super&gt;Tab” type=”empty”/>

就行了