调整 Deluge 使用的 libtorrent-rasterbar 版本以实现双栈 IP 汇报

最近一版的 qBittorrent 更新之后,Deluge 所依赖的 libtorrent 变成了 1.1.5(libtorrent-rasterbar9 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1),然而 Deluge 的双栈 IP 汇报是一件很玄学的事情,目前只有 libtorrent-rasterbar8 1.0.11-1~xenial~ppa1.1(也就是目前 Deluge PPA 上面的版本)才能实现对 U2 和 CMCT 的双栈 IP 汇报,因此需要做一些调整。

经过查询一些资料,发现 Deluge 通过 python-libtorrent 这个包实现对于 libtorrent 版本的绑定,该软件包的版本决定了底层使用的 libtorrent 版本。

先看一下 1.1.5 版的 libtorrent 安装后,系统上的软件包情况:

$ dpkg -l|grep libtorrent
ii  libtorrent-rasterbar8                1.0.11.1+git20170907.c074e87885-1ppa1~xenial1                amd64        C++ bittorrent library by Rasterbar Software
ii  libtorrent-rasterbar9                1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1 amd64        C++ bittorrent library by Rasterbar Software
ii  python-libtorrent                    1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1 amd64        Python bindings for libtorrent-rasterbar
ii  qbittorrent                          4.0.1.99~201711271728-6211-f977d12~ubuntu16.04.1             amd64        bittorrent client based on libtorrent-rasterbar with a Qt4 GUI

可以看到,python-libtorrent 和 libtorrent-rasterbar9 一样,使用了 1.1.5 的版本,那么如何降级呢?

经过 apt-cache policy <package name> 命令的查询,我们发现其实是可以安装 1.0.11 版本的 python-libtorrent 的:

$ apt-cache policy python-libtorrent
python-libtorrent:
  Installed: 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1
  Candidate: 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1
  Version table:
 *** 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1 100
        100 /var/lib/dpkg/status
     1.0.11-1~xenial~ppa1.1 500
        500 http://ppa.launchpad.net/deluge-team/ppa/ubuntu xenial/main amd64 Packages
     1.0.7-1build1 500
        500 http://mirrors.online.net/ubuntu xenial/universe amd64 Packages

$ apt-cache policy libtorrent-rasterbar8
libtorrent-rasterbar8:
  Installed: 1.0.11.1+git20170907.c074e87885-1ppa1~xenial1
  Candidate: 1.0.11.1+git20170907.c074e87885-1ppa1~xenial1
  Version table:
 *** 1.0.11.1+git20170907.c074e87885-1ppa1~xenial1 100
        100 /var/lib/dpkg/status
     1.0.11-1~xenial~ppa1.1 500
        500 http://ppa.launchpad.net/deluge-team/ppa/ubuntu xenial/main amd64 Packages
     1.0.7-1build1 500
        500 http://mirrors.online.net/ubuntu xenial/universe amd64 Packages

$ apt-cache policy libtorrent-rasterbar9
libtorrent-rasterbar9:
  Installed: 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1
  Candidate: 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1
  Version table:
 *** 1.1.5+git20171122.a57ad00e15+patched-configure-1ppa1~xenial1 500
        500 http://ppa.launchpad.net/qbittorrent-team/qbittorrent-stable/ubuntu xenial/main amd64 Packages
        100 /var/lib/dpkg/status

从输出结果中可以看出,python-libtorrent 有三个版本,1.1.5 1.0.11 和 1.0.7,我们在这里需要 1.0.11 的版本。同时,为了保证依赖完整,我们需要安装相同版本的 libtorrent-rasterbar8,这个操作可以通过 apt-get install <package name>=<version name> 的命令完成。

之后,还需要做的一件事是方式 apt-get upgrade 的时候更新了我们已经降级的软件包。这个操作通过 apt-mark hold <package name> 完成,在执行了这个命令以后,我们可以看一下效果:

$ dpkg --get-selections|grep libtorrent
libtorrent-rasterbar8				hold
libtorrent-rasterbar9				install
python-libtorrent				hold

可以发现对应的软件包已经被锁定,重启 deluged 之后也成功降级到了 1.0.11 版本。

综上,解决方案如下:

apt-get install libtorrent-rasterbar8=1.0.11-1~xenial~ppa1.1 python-libtorrent=1.0.11-1~xenial~ppa1.1
apt-mark hold libtorrent-rasterbar8 python-libtorrent
dpkg --get-selections|grep libtorrent

.deb 依赖包下载,以防 Deluge PPA 更新导致方法无效:https://down.gloriousdays.pw/Tools/Deluge-libtorrent-1.0.11.tar.xz

Windows OpenCV 环境配置

系统版本

  • Windows 10 1703
  • OpenCV 3.3.1
  • Visual Studio 2017 (v141)

配置过程

  1. 下载 OpenCV 3.3.1 安装包,双击自解压到 D 盘,即放在 D:\OpenCV 目录下。进入该文件夹后,可以看到 sources 和 build 两个文件夹,分别存放着源代码和编译好的文件。设置一个环境变量 OPENCV_DIR(也可以不设置),指向 D:\OpenCV\build
  2. 创建一个新的 C++ 工程,比如叫做 CV_Demo
  3. 右键 CV_Demo 这个 Project,进入 Property Page
  4. 在 C/C++ 中的 General 下的 Additional Include Directories 添加 $(OPENCV_DIR)\include
  5. 在 Linker 中的 General 下的 Additional Library Directories 添加 $(OPENCV_DIR)\x64\vc14\lib
  6. 在 Linker -> Input -> Additional Dependencies 下,Debug 模式添加 opencv_world331d.lib,Release 模式添加 opencv_world331.lib
  7. 将 $(OPENCV_DIR)\x64\vc14\bin 目录下的 opencv_world331d.dll 和 opencv_world331.dll 分别放入 CV_Demo\x64(输出目录) 目录的 Debug 和 Release 目录下,并同时放入 CV_Demo\CV_Demo (源代码文件)目录下

至此配置工作完成,运行一个 Demo 试试吧。

#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        cout << " Usage: display_image ImageToLoadAndDisplay" << endl;
        return -1;
    }
    Mat image;
    image = imread(argv[1], IMREAD_COLOR); // Read the file
    if (image.empty()) // Check for invalid input
    {
        cout << "Could not open or find the image" << std::endl;
        return -1;
    }
    namedWindow("Display window", WINDOW_AUTOSIZE); // Create a window for display.
    imshow("Display window", image); // Show our image inside it.
    waitKey(0); // Wait for a keystroke in the window
    return 0;
}

 

关于 Linux 下 CPU Affinity 的一些发现

超线程是一个相对来说有些争议的技术,在某些任务场景下,可能可以提高系统整体的效率,有些时候则不然,由于任务对同一 CPU 核心资源的争抢,效率反而会下降。因此如何正确地分配任务就是一个需要研究的问题。

通常来说,我们认为在 Windows 系统上,一个物理内核的两个逻辑核心在序号上是连续分配的,比如一个 2C4T 的处理器,Thread 0、1 为同一物理核心,Thread 2、3 为同一物理核心;在 Linux 系统上则是间隔分配,比如同样的 2C4T 处理器,Thread 0、2 为同一物理核心,Thread 1、3 为同一物理核心。但是现在我发现并不是这样。

我们可以执行 for file in /sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list; do echo -n "$file "; cat $file; done |sort -k2 -n 这样一个命令来查看核心的相邻情况。

在我的一台 E3v3 上,结果是这样的:

/sys/devices/system/cpu/cpu0/topology/thread_siblings_list 0-1
/sys/devices/system/cpu/cpu1/topology/thread_siblings_list 0-1
/sys/devices/system/cpu/cpu2/topology/thread_siblings_list 2-3
/sys/devices/system/cpu/cpu3/topology/thread_siblings_list 2-3
/sys/devices/system/cpu/cpu4/topology/thread_siblings_list 4-5
/sys/devices/system/cpu/cpu5/topology/thread_siblings_list 4-5
/sys/devices/system/cpu/cpu6/topology/thread_siblings_list 6-7
/sys/devices/system/cpu/cpu7/topology/thread_siblings_list 6-7

可以发现,分布和 Windows 有些类似。

但是在我的另一台 i3-2130 上,结果却是这样的:

/sys/devices/system/cpu/cpu0/topology/thread_siblings_list 0,2
/sys/devices/system/cpu/cpu2/topology/thread_siblings_list 0,2
/sys/devices/system/cpu/cpu1/topology/thread_siblings_list 1,3
/sys/devices/system/cpu/cpu3/topology/thread_siblings_list 1,3

可以看到是典型的 Linux 分配。

更奇怪的是,这个核心分配并不是稳定的,所以如果有对 CPU 资源要求严格的应用,重启之后需要再次检查逻辑核心的分配,以免效率降低。

为 Linux 添加系统调用

本文实际上是浙江大学操作系统课程实验二的一个记录,所以会有一些很奇怪的操作。

实验目的

添加一个系统调用 mysyscall,获取系统中 Page Fault 的次数。基于 Linux Kernel 4.6 的代码完成。

实验方法

这里需要说明一下的是 include/uapi/asm-generic/unistd.hinclude/linux/syscalls.harch/x86/entry/syscalls/syscall_64.tblarch/x86/entry/syscalls/syscall_32.tbl 的区别。unistd.h 是一个 POSIX 标准的头文件,其中包含了 POSIX 标准的系统调用的函数封装;syscalls.h 是 Linux 系统调用真实的声明文件;syscall_<32/64>.tbl 是对应架构的系统调用列表,这里存在 32 和 64 两个版本是因为 x86 架构有 x86_64 这样的扩展。

因此,如果我们需要在一台 x86_64 架构的 Linux 系统中添加一个系统调用,我们对于以上的文件都需要做出修改。但是需要注意的一点是,他们中的系统调用号不必相同,但是最终在 user mode 中使用该系统调用的时候,使用的应该是对应版本 tbl 中的编号。比如一个 x86_64 架构的 PC,最终调用的编号应该和 syscall_64.tbl 中的编号相同。

接下来我们可以开始添加系统调用了,假设我们系统调用的名字为 mysyscall,实现函数体的原型为 asmlinkage long sys_mysyscall(void);

  1. 在 include/linux/syscalls.h 中写入系统调用函数的声明,注意需要写在最后一行 #endif 之前。比如我们这里就需要加入 asmlinkage long sys_mysyscall(void);
  2. 在 include/uapi/asm-generic/unistd.h 中写入 POSIX 标准通用的系统调用声明,虽然类似于 x86 这样的架构有自己的系统调用表,但是我们应该保持兼容。这里我们需要加入这样的两行:
    #define __NR_mysyscall 292
    __SYSCALL(__NR_mysyscall, sys_mysyscall)
  3. 在 kernel/sys_ni.c 中写入刚才加入的系统调用,这个提供了一个 fallback stub implementation,返回值是 -ENOSYS (Function not implemented.)
    cond_syscall(sys_mysyscall);
  4. 在 arch/x86/entry/syscalls/syscall_64.tbl 中写入刚才添加的系统调用,如果不需要在 x86 和 x86_64 上有不同的表现,则应该将属性定为 common
    340    common     mysyscall    sys_mysyscall
  5. 在 arch/x86/entry/syscalls/syscall_32.tbl 中也加入类似的东西,这是为 i386 架构服务的
    380    i386    mysyscall    sys_mysyscall
  6. 实现 Page Fault 统计
    include/linux/mm.h 文件中声明变量 pfcountextern unsigned long pfcount;
    在进程 task_struct 中增加成员 pf,在 include/linux/sched.h 文件中的 task_struct 结构中添加 pf 字段 unsigned long pf;
    在进程创建过程中将 pf 字段置 0,修改 kernel/fork.c 文件中的 dup_task_struct() 函数:

    static struct task_struct *dup_task_struct(struct task_struct *orig)
    {   …… 
        tsk = alloc_task_struct_node(node); 
        if (!tsk) return NULL;
        ……    
     ++ tsk->pf=0; 
        ……
    }

    arch/x86/mm/fault.c 文件中定义变量 pfcount;并修改 arch/x86/mm/fault.cdo_page_fault() 函数。每次产生缺页中断,do_page_fault() 函数会被调用,pfcount 变量值递增1,记录系统产生缺页次数,current->pf 值递增 1,记录当前进程产生缺页次数:

    …
    ++ unsigned long pfcount;
    __do_page_fault(struct pt_regs *regs, unsigned long error_code)
    {
        …
     ++ pfcount++;
     ++ current->pf++;
        …
    }
  7. sys_mysyscall 的实现
    usr/src/linux-4.6 下建立 mysyscall 文件夹,其中建立三个文件 Makefilemysyscall.cmysyscall.h,分别如下:
    mysyscall.h

    asmlinkage long sys_mysyscall(void);

    mysyscall.c

    #include<linux/kernel.h>
    #include<linux/init.h>
    #include<linux/sched.h>
    #include<linux/syscalls.h>
    #include "mysyscall.h"
    asmlinkage long sys_mysyscall(void)
    {
     printk("Current Page Fault Count: %lu\n", current->pf);
     return 0;
    }

    Makefile

    obj-y:=mysyscall.o
    
  8. 修改主 Makefile 以编译 mysyscall
    找到 usr/src/linux-4.6/Makefile 中这样一行 core -y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/,改为 core -y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ mysyscall/
  9. 编译安装内核
    sudo make bzImage -j $(nproc) && sudo make modules -j $(nproc) && sudo make modules_install && sudo make install && sudo update-grub
  10. 重启
  11. 编写用户态程序,由于我本地是 x86_64 架构,因此使用刚才设定的 340 号系统调用
    #include <stdio.h>
    #include <linux/kernel.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    #define __NR_mysyscall 340
    int main()
    {
      long ret = syscall(__NR_mysyscall);
      printf("Return Value: %ld\n", ret);
      return 0;
    }
    
  12. 在 /var/log/kern.log 中查看输出,或者直接使用 dmesg 查看输出

一些额外的收获

/usr/src/linux-4.6/scripts/checksyscall.sh 是一个很神奇的脚本,它对于所有的代码进行 gcc 预处理之后,判断系统调用是否被正确写入和注册,如果这个测试不能通过,编译成功后也不一定能正常运行该系统调用。

查看 #include 命令调用的真实文件:echo '#include <unistd.h>' | gcc -E -x c -,会得到类似于 # 1 "/usr/include/unistd.h" <some numbers> 这样的输出,意思是后面这些 number 标记的行的代码来自于 /usr/include/unistd.h 

如果要看真实的引用文件,可以这么用:echo '#include <unistd.h>' | gcc -E -x c - | egrep '# [0-9]+ ' | awk '{print $3;}' | sort -u

kern.log 是 Line-Buffered,因此每个 printk 之后需要换行才能在 dmesg 中看到输出

编译内核模块的时候如果发现 arch/x86/Makefile:148: CONFIG_X86_X32 enabled but no binutils support 这样的错误,首先检查一下路径中是否有空格,如果有空格会引发这样的错误

参考资料

Linux Kernel 4.6 代码

https://unix.stackexchange.com/questions/1697/how-can-i-know-which-unistd-h-file-is-loaded

https://www.kernel.org/doc/html/v4.12/process/adding-syscalls.html

http://www.cs.fsu.edu/~cop4610t/lectures/project2/system_calls/system_calls.pdf

https://medium.com/@ssreehari/implementing-a-system-call-in-linux-kernel-4-7-1-6f98250a8c38

https://stackoverflow.com/questions/11237420/error-syscall-function-not-implemented

 

在 Ubuntu 16.04 上编译纯 CPU 挖矿程序

独服的 CPU 闲着也是闲着,小挖怡情,大挖伤身。本文主要基于 NiceHash Miner 可用的挖矿程序,在 Linux 下编译 CPU 可用的版本

Equihash miner for NiceHash

项目源码在这里,这个 miner 的编译稍稍有些麻烦,很多依赖需要自己安装。由于是纯 CPU 挖矿,尽管页面上提到了 CUDA Kit,但是我们并不需要安装这个。

需要的依赖有这些,Boost 1.62+ 和 CMake 3.5+,但是实际操作中,由于 CMake 和 Boost 库存在版本兼容性问题(Boost 1.63 / CMake 3.7+; Boost 1.64 / CMake 3.8+; Boost 1.65 & 1.65.1 / CMake 3.9.3+),因此不能采用简单的 apt 方式安装,而需要自己下载。

Boost 我选择了 1.65.1,具体安装看这里,具体命令如下:

wget https://dl.bintray.com/boostorg/release/1.65.1/source/boost_1_65_1.tar.bz2
tar --bzip2 -xf /path/to/boost_1_65_1.tar.bz2
cd path/to/boost_1_65_1
./bootstrap.sh
./b2 install

然后安装 CMake 3.9.3+,这里我一开始就被坑了,如果不选择合适的 CMake 版本,则编译时无法找到 Boost 库。

wget https://cmake.org/files/v3.9/cmake-3.9.6-Linux-x86_64.sh
chmod +x /path/to/cmake-3.9.6-Linux-x86_64.sh
sudo /path/to/cmake-3.9.6-Linux-x86_64.sh #Set your own install path during the process
sudo ln -s /path/to/cmake-3.9.6-Linux-x86_64/bin/* /usr/local/bin

然后运行 cmake --version 查看版本,应该已经是 3.9.3+ 了

接下来按照 GitHub 页面操作

  1. git clone https://github.com/nicehash/nheqminer.git
  2. 修改根目录下的 CMakeList.txt,修改这样一行: option(USE_CUDA_DJEZO "USE CUDA_DJEZO" ON) 后面的 ON 为 OFF,这是因为我们要纯 CPU 挖矿,不编译 CUDA 版本。
  3. cd nheqminer/cpu_xenoncat/asm_linux/
  4. chmod +x fasm
  5. sh assemble.sh
  6. cd ../../../
  7. mkdir build && cd build
  8. cmake ../nheqminer
  9. make -j $(nproc)

接下来在 build 目录下就会看到编译好的 nheqminer 程序,使用 nheqminer -l equihash.eu.nicehash.com:3357 -u <NH_BTC_ADDRESS>.<worker_name> -t <n_threads> 开始挖矿

CPUMiner-Multi

  1. git clone https://github.com/tpruvot/cpuminer-multi.git
  2. 安装依赖 apt install automake autoconf libcurl4-openssl-dev libjansson-dev libssl-dev
  3. cd cpuminer-multi
  4. ./build.sh
  5. ./cpuminer -a <algo> -o stratum+tcp://<pool_addr> -u <NH_BTC_ADDRESS>.<worker_name> -t <n_threads>

CPUMiner-Multi Help:

Usage: cpuminer-multi [OPTIONS]
Options:
  -a, --algo=ALGO       specify the algorithm to use
                          axiom        Shabal-256 MemoHash
                          bitcore      Timetravel with 10 algos
                          blake        Blake-256 14-rounds (SFR)
                          blakecoin    Blake-256 single sha256 merkle
                          blake2s      Blake2-S (256)
                          bmw          BMW 256
                          c11/flax     C11
                          cryptolight  Cryptonight-light
                          cryptonight  Monero
                          decred       Blake-256 14-rounds 180 bytes
                          dmd-gr       Diamond-Groestl
                          drop         Dropcoin
                          fresh        Fresh
                          groestl      GroestlCoin
                          heavy        Heavy
                          jha          JHA
                          keccak       Keccak
                          luffa        Luffa
                          lyra2re      Lyra2RE
                          lyra2rev2    Lyra2REv2 (Vertcoin)
                          myr-gr       Myriad-Groestl
                          neoscrypt    NeoScrypt(128, 2, 1)
                          nist5        Nist5
                          pluck        Pluck:128 (Supcoin)
                          pentablake   Pentablake
                          quark        Quark
                          qubit        Qubit
                          scrypt       scrypt(1024, 1, 1) (default)
                          scrypt:N     scrypt(N, 1, 1)
                          scrypt-jane:N (with N factor from 4 to 30)
                          shavite3     Shavite3
                          sha256d      SHA-256d
                          sia          Blake2-B
                          sib          X11 + gost (SibCoin)
                          skein        Skein+Sha (Skeincoin)
                          skein2       Double Skein (Woodcoin)
                          s3           S3
                          timetravel   Timetravel (Machinecoin)
                          vanilla      Blake-256 8-rounds
                          x11evo       Permuted x11
                          x11          X11
                          x13          X13
                          x14          X14
                          x15          X15
                          x17          X17
                          xevan        Xevan (BitSend)
                          yescrypt     Yescrypt
                          zr5          ZR5
  -o, --url=URL         URL of mining server
  -O, --userpass=U:P    username:password pair for mining server
  -u, --user=USERNAME   username for mining server
  -p, --pass=PASSWORD   password for mining server
      --cert=FILE       certificate for mining server using SSL
  -x, --proxy=[PROTOCOL://]HOST[:PORT]  connect through a proxy
  -t, --threads=N       number of miner threads (default: number of processors)
  -r, --retries=N       number of times to retry if a network call fails
                          (default: retry indefinitely)
  -R, --retry-pause=N   time to pause between retries, in seconds (default: 30)
      --time-limit=N    maximum time [s] to mine before exiting the program.
  -T, --timeout=N       timeout for long poll and stratum (default: 300 seconds)
  -s, --scantime=N      upper bound on time spent scanning current work when
                          long polling is unavailable, in seconds (default: 5)
      --randomize       Randomize scan range start to reduce duplicates
  -f, --diff-factor     Divide req. difficulty by this factor (std is 1.0)
  -m, --diff-multiplier Multiply difficulty by this factor (std is 1.0)
  -n, --nfactor         neoscrypt N-Factor
      --coinbase-addr=ADDR  payout address for solo mining
      --coinbase-sig=TEXT  data to insert in the coinbase when possible
      --max-log-rate    limit per-core hashrate logs (default: 5s)
      --no-longpoll     disable long polling support
      --no-getwork      disable getwork support
      --no-gbt          disable getblocktemplate support
      --no-stratum      disable X-Stratum support
      --no-extranonce   disable Stratum extranonce support
      --no-redirect     ignore requests to change the URL of the mining server
  -q, --quiet           disable per-thread hashmeter output
      --no-color        disable colored output
  -D, --debug           enable debug output
  -P, --protocol-dump   verbose dump of protocol-level activities
      --hide-diff       Hide submitted block and net difficulty
  -S, --syslog          use system log for output messages
  -B, --background      run the miner in the background
      --benchmark       run in offline benchmark mode
      --cputest         debug hashes from cpu algorithms
      --cpu-affinity    set process affinity to cpu core(s), mask 0x3 for cores 0 and 1
      --cpu-priority    set process priority (default: 0 idle, 2 normal to 5 highest)
  -b, --api-bind        IP/Port for the miner API (default: 127.0.0.1:4048)
      --api-remote      Allow remote control
      --max-temp=N      Only mine if cpu temp is less than specified value (linux)
      --max-rate=N[KMG] Only mine if net hashrate is less than specified value
      --max-diff=N      Only mine if net difficulty is less than specified value
  -c, --config=FILE     load a JSON-format configuration file
  -V, --version         display version information and exit
  -h, --help            display this help text and exit

 

Kimsufi 独服购买的一些套路

作为一个玩盒子玩了快一年的人,Online.net、Kimsufi 这样的便宜独服商家如果都没接触过,实在是说不过去,我也不例外。在盒子价格愈发上升的当下,这两家的价格依旧那么便宜也确实是不可多得的一件事。不过独服不像 VPS,首次购买都存在一个设置费的问题,如果在购买了之后很短的时间内发现同款可以以更低的价格买到,就会非常纠结,究竟是应该选择更低的续费价格且再出一笔设置费,还是考虑到设置费的成本,不再去管那一点点的差价(对,KS-2E 说的就是你)。

不过这篇文章想要讨论的并不是 KS 的独服又出特价了的问题,而是想记录一下购买 Kimsufi 独服的一些可以省钱的小技巧。

抛开法国人可能根本就搞不清自己在卖什么的问题不谈(比如 17 年年初可以用 KS-3C 的价格开出 KS-4C 的高配之类),先来说一说 Kimsufi 的网站账户体系。无论访问 Kimsufi 哪一个 TLD 的域名(.ie / .fr / .com),最终都会导向至 Kimsufi.com 下的一个分支。据我的观察,主要有三套账户体系:

  1. kimsufi.com/en 和 kimsufi.com/fr
  2. kimsufi.com/ca/en 和 kimsufi.com/ca/fr
  3. kimsufi.com/us/en

其中第一个可以通过 kimsufi.ie 跳转得到,使用欧元结算,设置费 9.99 EUR 且存在 20% 的 VAT,虽然可以免掉,但是对于中国大陆用户来说非常不友好,因为需要提交英文的地址和信息证明。

第二个可以通过 kimsufi.ca 跳转得到,使用加拿大元结算,设置费 13.99 CAD,不存在欧盟增值税的问题。但是由于购买需要提供合法的加拿大地址和手机号,因此对于中国大陆用户来说也不是很方便。

第三个可以在利用美国 IP 地址访问 kimsufi.com 时自动跳转得到,使用美元结算,设置费 13.99 USD,不存在增值税的问题。相比之下,虽然有的时候可能价格相对欧洲区贵一点点,但是考虑到 VAT 的问题,反而便宜不少。因此这个区域的账户对于中国用户来说是一个好的选择。

接下来说促销的问题,我们知道 Kimsufi 的服务器经常出现一些促销,比如 KS-2E 和 KS-3C 等等。促销的购买链接一般是这样的:

  • https://www.kimsufi.com/fr/commande/kimsufi.xml?reference=<productID>
  • https://www.kimsufi.com/ca/en/order/kimsufi.xml?reference=<productID>
  • https://www.kimsufi.com/en/order/kimsufi.xml?reference=<productID>
  • https://www.kimsufi.com/ca/fr/commande/kimsufi.xml?reference=<productID>
  • https://www.kimsufi.com/us/en/order/kimsufi.xml?reference=<productID>

根据我的观察,无论 Kimsufi 在哪个区域进行促销,即其他区域的网站不存在这样的促销,所有区域的购买链接都会可用,但是价格会根据 OVH 内部的一套汇率规则将促销区域的价格换算到你所购买的区域的价格。比如欧洲区 6.99 EUR 促销的 KS-2E,使用美区账号购买就会变成 8.39 USD,换算回欧元的话,就是 7 欧多一点点,考虑到 VAT 的问题,仍然相当实惠,因为如果使用欧元区账号购买,同款就需要 8.39 EUR了。

综上所述,如果需要购买 Kimsufi 的便宜独立服务器,还是注册一个美区账号比较好。加上 OVH 的 Paypal 付款无法支持银联通道结算,如果使用欧元结算,通过 VISA / MasterCard 通道结算有时会面临一个货币转换费的问题,因此无论是从价格方面考虑,还是考虑到免税的各种麻烦,都应该选择 Kimsufi 美区账号。

OpenVZ 架构 VPS 配置 IPv6 TunnelBroker

虽然现在 IPv6 尚未完全普及,但是作为一个本地有 IPv6 连接,盒子也是双栈 IP 的用户,双栈 VPS 对我来说也算是一个很有意义的特性。但是很多 Low End VPS 商家售卖的 OpenVZ VPS 并不提供 IPv6 地址,OpenVZ 架构也不像 KVM 一样可以方便地添加 TunnelBroker 实现双栈网络,因此便需要寻找其他的解决方案。

所幸并不是我一个人有这个需求,借助 tb_userspace 这个小工具,可以很快地完成这样的配置工作。记录配置过程如下:

  1. 在 tunnelbroker.net 创建一个新的 Regular Tunnel,取得 Server IPv4 Address 和 Client IPv4 Address 两个配置
  2. 下载 tb_userspace 源代码,编译。此时假设 tb_userspace 存放于 /root目录下
    wget https://down.gloriousdays.pw/Tools/tb_userspace.c
    gcc tb_userspace.c -l pthread -o tb_userspace
  3. 创建自启动脚本 /etc/init.d/ipv6tb
    #! /bin/sh
     
    ### BEGIN INIT INFO
    # Provides:          ipv6
    # Required-Start:    $local_fs $all
    # Required-Stop:     $local_fs $network
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts the ipv6 tunnel 
    # Description:       ipv6 tunnel start-stop-daemon
    ### END INIT INFO
     
    # /etc/init.d/ipv6tb
     
    touch /var/lock/ipv6tb
     
    case "$1" in
      start)
        echo "Starting ipv6tb "
          setsid /root/tb_userspace tb <Server IPv4 Address> <Client IPv4 Address> sit > /dev/null 2>&1 &
          sleep 3s #ugly, but doesn't seem to work at startup otherwise
          ifconfig tb up
          ifconfig tb inet6 add <Client IPv6 Address from your Routed /64> ::XXX/128 #Add as many of these as you need from your routed /64 allocation
          ifconfig tb mtu 1480
          route -A inet6 add ::/0 dev tb
          route -A inet6 del ::/0 dev venet0
        ;;
      stop)
        echo "Stopping ipv6tb"
          ifconfig tb down
          route -A inet6 del ::/0 dev tb
          killall tb_userspace
        ;;
      *)
        echo "Usage: /etc/init.d/ipv6tb {start|stop}"
        exit 1
        ;;
    esac
     
    exit 0
    
    
    chmod 0755 /etc/init.d/ipv6tb
    update-rc.d ipv6tb defaults #May cause problems, explain later
  4. Ubuntu 16.04 (systemd) 的额外配置
    如果是使用 Upstart 的 Ubuntu 版本,使用 update-rc.d 就可以创建相应的启动项,但是在某些 Ubuntu 16.04 上,如 HostDare 的 VPS,update-rc.d 在将 SysVinit 脚本做一个 wrapper 以后产生的 Systemd 自启动脚本并不能正常工作。经过排查,发现这个问题产生于 Systemd 脚本的 Type 问题,ipv6tb 应给以 Forking 方式启动,而不是默认的 Simple 模式,如果按照默认模式启动,就会莫名其妙地卡住。因此,如果在 Ubuntu 16.04 上配置,不应该使用 update-rc.d 方式创建 Systemd Wrapped SysVinit 脚本,而应该自己在 /etc/systemd/system 里写一个脚本。

    [Unit]
    Description=ipv6tb
    After=network-online.target
    
    [Service]
    Type=forking
    ExecStart=/usr/bin/sudo /etc/init.d/ipv6tb start
    ExecStop=/usr/bin/sudo /etc/init.d/ipv6tb stop
    Restart=always
    
    [Install]
    WantedBy=multi-user.target

之后执行 systemctl enable ipv6tb.service 就可以正常使用了。

关于 SSH Key 使用的一些注意事项

SSH 使用 pubkey 认证方式自动登陆的安全性要求其实比想象中严格很多,除此之外配置也有很多讲究,目前遇到的几点简单列举如下:

  • 关于 private key 及其路径的权限
    • /home/<username> 目录为 700
    • /home/<username>/.ssh 目录为 700
    • /home/<username>/.ssh/authorized_keys 为 600
    • /home/<username>/.ssh/<privateKey> 为 600
  • 关于 SSH 的配置文件
    • SSH 登陆全局配置文件:/etc/ssh/ssh_config
    • SSH 单用户配置文件:/home/<username>/.ssh/config
    • 如果用 sudo 命令执行 ssh,相当于对于 ssh 命令使用了 root 或对应用户的环境,应在对应的 home 目录下放置相应的 privateKey 和 config

Online Dedibox IPv6 配置

Online 的 IPv6 配置真是不一般地蛋疼,官方文档上面那个 DHClient6 完全不能用,在 U2 上有人推荐使用 Dibbler,但是在上一台挂掉的盒子上也还是不好用,平均三天会挂掉一次。在最新的一台盒子上尝试放弃 Online 自己的 IPv6 线路,使用 HE 的 TunnelBroker,然而根本没办法加载网络设备,我也是没有任何办法。

现在又找到了一版 DHClient6 配置,记录如下:

将如下内容写入 /etc/network/interfaces

iface eno1 inet6 static
  address <one IPv6 address from your block from Online>
  netmask 56
  accept_ra 1
  pre-up /sbin/dhclient -1 -v -pf /run/dhclient6.eno1.pid -lf /var/lib/dhcp/dhclient6.eno1.leases -cf /etc/dhcp/dhclient6.conf -6 -P eno1

创建 /etc/dhcp/dhclient6.conf

interface "eno1" {
  send dhcp6.client-id <your DUID for the subnet>;
  request;
}

之后运行 systemctl reload-or-restart networking.service

按照我之前的经历,DHClient6 获得的 IPv6 地址只能存活 12 小时,所以我先继续配置,等待 12 小时之后再来更新。

更新:已经将近 24 小时,目前 IPv6 仍然存活,认为配置成功。

从零开始的盒子:Online Dedibox 盒子配置记录

讲真,我也记不得这是我第几次配盒子了,但是这次我的主力盒子 & 杂活独立服务器挂掉还是给我造成了很大的损失。一方面,我损失了所有的盒子配置,包括澄空学园字幕组和 LoliHouse 的公网分流记录和文件,还有一些刷 PT 的环境;另一方面,我损失了虚拟机上的 Windows 压制环境;还有一些特定用途的杂活类服务,比如 Node.js 环境、Python / Anaconca 环境等等。为了以后维护方便,也为了给有同样需求的人一个参考,我在这里记录一下配置的历程。

先说点别的吧,关于这个盒子为什么会突然挂掉。起因是昨天(2017 年 10 月 9 日)下午至晚上,某国的大型网络过滤系统突然发威,在全国范围内干掉了我盒子的 IP 地址,我就很奇怪,我盒子一不做代理、二不放网站,就几个 BT 客户端的 WebUI 跑在上面,怎么就无缘无故给我过滤掉了。发现了 IP 问题之后,我尝试订购了一个 Failover IP 地址作为备用 IP。在配置的时候,由于我想要把这个 IP 作为我的主 IP 而改动了路由表,然后就被上级交换机锁了网络端口,与客服沟通之后,由于问题在短时间内无法解决,进而选择换机,我也丢失了所有数据。

先整理一下大致需求:

  1. Server As a Seedbox
    1. Update Kernel & BBR & BBR_powered
    2. Deluge ( Main BT/PT Client )
    3. Transmission ( Secondary PT Client )
    4. UTserver ( Specialized BT Client for SumiSora_Initial )
    5. Tixati ( Specialized BT Client for SumiSora_Main )
    6. qBittorrent ( Specialized BT Client for LoliHouse )
    7. Jailed SSH User ( For SumiSora_Initial SFTP Upload )
    8. SSHFS (Map Wishosting Stroage KVM Disk, not decided yet; maybe let Tixati work on this disk )
  2. Server As an Encoding Server
    1. VMware WorkStation
    2. gcc6
    3. Windows 7 & Activation
    4. Runtime Library
    5. Python & VapourSynth
    6. BaiduNetDisk
  3. Server As a Computer
    1. Node.js Http Server
    2. Anaconda Environment in Windows VM
    3. IPv6 Configuration
    4. Xfce & VNCserver
    5. Wine
    6. Firefox
  4. Server As a Storage Box
    1. Jailed SSH User ( Website Backup )

接下来开始安装:

  • 系统安装

系统仍然选择了我熟悉的 Ubuntu 16.04 LTS Server,由于我的服务器硬盘是 SoftRaid,在配置的时候还遇到了一些问题。最主要的问题就是 SWAP 分区不能使用 RAID0,如果这么选择安装操作系统就会报错。

  • 预配置及软件源添加
sudo apt-get install python-software-properties software-properties-common
sudo add-apt-repository ppa:transmissionbt/ppa
sudo add-apt-repository ppa:deluge-team/ppa
sudo add-apt-repository ppa:qbittorrent-team/qbittorrent-stable
curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
sudo dpkg --add-architecture i386 
wget -nc https://dl.winehq.org/wine-builds/Release.key 
sudo apt-key add Release.key 
sudo apt-add-repository https://dl.winehq.org/wine-builds/ubuntu/
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
  • 安装一系列软件
sudo apt update
sudo apt install xfce4 vnc4server deluged deluge-web qbittorrent transmission-daemon sshfs nodejs firefox build-essential fonts-noto gtk3-engines-xfce xfce4-goodies xfce4-power-manager
sudo apt-get install --install-recommends winehq-stable
sudo apt-get install gcc-7 g++-7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7
sudo update-alternatives --config gcc
  • Kernel Update & BBR_powered

在 http://kernel.ubuntu.com/~kernel-ppa/mainline/ 上下载 4.11 版本的内核,4.12 存在 VirtIO 方面的 bug,4.13+ 无法适配 BBR_powered 模块,所以采用 4.11.12

wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.12/linux-headers-4.11.12-041112_4.11.12-041112.201707210350_all.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.12/linux-headers-4.11.12-041112-generic_4.11.12-041112.201707210350_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11.12/linux-image-4.11.12-041112-generic_4.11.12-041112.201707210350_amd64.deb
sudo dpkg -i linux*.deb
sudo update-grub
sudo reboot

wget -O ./tcp_tsunami.c https://down.gloriousdays.pw/Tools/tcp_tsunami.c
echo "obj-m:=tcp_tsunami.o" > Makefile
make -C /lib/modules/$(uname -r)/build M=`pwd` modules CC=/usr/bin/gcc
sudo cp tcp_tsunami.ko /lib/modules/$(uname -r)/kernel/drivers/
echo 'tcp_tsunami' | sudo tee -a /etc/modules
sudo depmod
sudo modprobe tcp_tsunami
sudo bash -c "echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf"
sudo bash -c "echo "net.ipv4.tcp_congestion_control=tsunami" >> /etc/sysctl.conf"
sudo sysctl -p
  • IPv6 配置

鉴于 Online 的蛋疼实现,另起一篇在这里

  • BT 客户端配置
sudo systemctl stop transmission-daemon.service
sudo vi /var/lib/transmission-daemon/info/settings.json
#Change the following lines to the content that you want
"rpc-password": "{62b16db87b89a91dd49a5110a7cafc06d20eb4f2wtK6kqPj",
"rpc-username": "transmission",
"rpc-whitelist": "*",
"umask": 2,

一、utserver
这个比较简单

前往utserver的官网: http://www.utorrent.com/downloads/linux 下载编译好的程序
文件名一般是utserver.tar.gz
注意适用的发行版。

目前最新的3.3已经可用。

部署:
sudo tar xvzf utserver.tar.gz -C /opt/

#释放到opt目录

sudo chmod -R 777 /opt/utorrent-server-alpha-v3_3/
#给予目录权限,这里的目录名视情况而定。可以先敲sudo chmod -R 777 /opt/ut 再按下TAB自动补全

sudo ln -s /opt/utorrent-server-alpha-v3_3/utserver /usr/bin/utserver

#链接可执行文件,建立快捷方式。目录名问题同上。
utserver -settingspath /opt/utorrent-server-alpha-v3_3/
#(测试)运行。目录名问题同上。

如果这是没有出错提示,恭喜已经成功了
访问 [server_ip]:8080/gui 登陆webui
用户名 admin, 密码为空
登陆后开始设置

如果提示libssl.so package missing
运行
sudo apt-get install libssl0.9.8:i386
#补全依赖

因为一旦登出,utserver -settingspath /opt/utorrent-server-alpha-v3_3 这个命令终止导致ut停止运行
可以使用tmux或者nohup后台运行
nohup utserver -settingspath /optutorrent-server-alpha-v3_3 >/dev/null 2>&1 &

[Unit]
Description=utserver
After=network-online.target

[Service]
ExecStart=/usr/bin/sudo -u <username> /path/to/utserver/bin -settingspath /path/to/utserver/dir/
ExecStop=kill -9 $(cat /run/utserver.pid)
Restart=always
PIDFile=/run/utserver.pid
TimeoutStopSec=300
RestartSec=3

[Install]
WantedBy=multi-user.target
  • VNCserver 配置

修改 ~/.vnc/xstartup 以启动 Xfce 桌面环境

#!/bin/sh

# Uncomment the following two lines for normal desktop:
# unset SESSION_MANAGER
# exec /etc/X11/xinit/xinitrc

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
#x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
#x-window-manager &
startxfce4 &

修改 /usr/bin/vncserver 中 VNCserver 的配置,这个需要 root 权限

$geometry="1024x768"
$vncPort = 5900 + $displayNumber
$depth = 16 #(may cause problems with Windows VM if set to 24)
  • Jailed SSH User 进一步配置

由于我不想打开 SSH 的 Password Authentication, 但是 LNMP 脚本的备份又需要通过密码认证的 SSH 连接实现,因此寻找了可以打开单个用户的密码认证的方法:

在 /etc/ssh/sshd_config 中写入如下代码块即可

Match User <username1>,<username2>
    PasswordAuthentication yes
Match all  #This line is to end the match block
  • systemd 自启动脚本的设定

参照之前我写的这篇文章和 SSHFS 设置的这篇文章