blog

My blog at www.shimmy1996.com

git clone git://git.shimmy1996.com/blog.git

2017.org (50075B)

    1 #+HUGO_BASE_DIR: ../
    2 #+HUGO_SECTION: ./posts
    3 #+OPTIONS: author:nil
    4 
    5 * DONE My Server Setups and Whatnot
    6 :PROPERTIES:
    7 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :date 2017-09-25 :slug my-server-setups-and-whatnot
    8 :END:
    9 
   10 ** DONE en
   11 :PROPERTIES:
   12 :EXPORT_TITLE: My Server Setups and Whatnot
   13 :EXPORT_FILE_NAME: 2017-09-25-my-server-setups-and-whatnot.en.md
   14 :END:
   15 
   16 *** Why move the blog? And to where?
   17 After putting up with the clunky WordPress blog (and Bluehost's 2003-looking admin panel for that matter) for three years, I finally decided to ditch everything I currently have and restart my blog in a more civilized manner. There was a couple of things that I was not happy about my old WordPress setup, namely:
   18 
   19 - Clunky and eats up my server storage.
   20 - Not as easy way to back up with tools I know.
   21 - Does not come with a command line interface, which is becoming my preferred way of doing almost anything.
   22 - Lacking some basic features I wanted, i.e. multilingual support. As powerful as WordPress may be in the right hands, I do not want to invest too much effort in learning CSS/js/php nor do I want to use some plugin from some sketchy WordPress plugin marketplace.
   23 - These theme and plugin marketplaces creeps me out in the same way as ubuntu software center.
   24 - WordPress has a lot of features I do not actually need, i.e. user permission system, which is an overkill for my personal blog site.
   25 
   26 Picking an alternative blogging system was not too hard once I am aware of my needs: a fast and minimalist static site generator implemented in a language I know (or I found valuable to learn) with out-of-the-box multilingual support, a.k.a. =hugo=.
   27 
   28 As for hosting services, I considered github pages and netlify to be fast and easy solutions but I want something more substantial for a personal blog, like a VPS. Besides, github pages not supporting https for custom domains is a deal breaker for me. I filtered down the list of VPS hosting providers with Arch Linux support and I ended up with DigitalOcean. Since I wanted to completely sever my connection with Bluehost, I also moved my domain name host to Google Domains.
   29 
   30 *** Install Arch Linux
   31 Do note that Arch Linux is probably not the best suited server Linux distro. Use a non-rolling distro if stability is a concern. I use it only because I also run it on all my other computers. Backup the droplet often if you decided to go down this route: it hasn't happened to me yet but I've heard people complaining about Arch breaking too often.
   32 
   33 **** Installation
   34 Apparently my information on DigitalOcean supporting Arch Linux is outdated, as they stopped supporting it a while back. Thankfully, it is still not to hard to bring Arch Linux to a droplet (this is how DigitalOcean refer to a server) due to the awesome project [[https://github.com/gh2o/digitalocean-debian-to-arch][digitalocean-debian-to-arch]]. All I needed to to was [[https://www.digitalocean.com/community/tutorials/how-to-create-your-first-digitalocean-droplet][set up a droplet]], =ssh= into the server, and follow the instructions:
   35 
   36 #+BEGIN_SRC sh
   37 # wget https://raw.githubusercontent.com/gh2o/digitalocean-debian-to-arch/debian9/install.sh -O install.sh
   38 # bash install.sh
   39 #+END_SRC
   40 
   41 **** Low Level Setup
   42 Once the script finishes running, I have an Arch Linux system running on my droplet with internet access. Most of the additional setups needed can be found in [[https://wiki.archlinux.org/index.php/Installation_guide][Arch Wiki]]. Since I am by no means a great tutorial writer, I suggest referring to Arch Wiki for detailed steps. The recorded commands here are just for book-keeping purposes and is by no means the best way to do things.
   43 
   44 ***** System Clock
   45 Sync system clock and set time zone.
   46 #+BEGIN_SRC sh
   47 # timedatectl set-ntp true
   48 # timedatectl settimezone <Region>/<City>
   49 #+END_SRC
   50 
   51 ***** Base Packages
   52 Install/update base packages.
   53 #+BEGIN_SRC sh
   54 # pacman -S base base-devel
   55 #+END_SRC
   56 
   57 ***** Fstab
   58 Generate =fstab=.
   59 #+BEGIN_SRC sh
   60 # genfstab -U / >> /etc/fstab
   61 #+END_SRC
   62 
   63 ***** Set Locale
   64 Uncomment =en_US.UTF-8 UTF-8= in =/etc/locale.conf= then generate locale with:
   65 #+BEGIN_SRC sh
   66 locale-gen
   67 #+END_SRC
   68 
   69 Set =LANG=en_US.UTF-8= in =/etc/locale.conf=.
   70 
   71 ***** Hostname
   72 Edit =/etc/hosts= and add hostname of droplet:
   73 #+BEGIN_SRC sh
   74 127.0.1.1    <hostname>.localdomain <hostname>
   75 #+END_SRC
   76 
   77 ***** Boot Loader and Initramfs
   78 Optimizations for intel processors:
   79 #+BEGIN_SRC sh
   80 # pacman -S intel-ucode
   81 # grub-mkconfig -o /boot/grub/grub.cfg
   82 #+END_SRC
   83 
   84 Add =crc32= modules to initramfs, as otherwise the droplet fails to boot. Edit =/etc/mkinitcpio.conf= :
   85 #+BEGIN_SRC sh
   86 MODULES= "crc32 libcrc32c crc32c_generic crc32c-intel crc32-pclmul"
   87 #+END_SRC
   88 Regenerate the initramfs image.
   89 #+BEGIN_SRC sh
   90 # mkinitcpio -p linux
   91 #+END_SRC
   92 
   93 ***** Root Password
   94 You know the drill.
   95 #+BEGIN_SRC sh
   96 # passwd
   97 #+END_SRC
   98 
   99 **** User Setups
  100 Here are some additional settings to make Arch Linux more useable.
  101 
  102 ***** Creature User
  103 Obviously it is not a good idea to use root account:
  104 #+BEGIN_SRC sh
  105 # useradd -m -G wheel -s /bin/bash <username>
  106 # passwd <username>
  107 #+END_SRC
  108 
  109 ***** Add User to Sudoer
  110 Edit =/etc/sudoers= and add:
  111 #+BEGIN_SRC sh
  112 <username> ALL=(ALL) ALL
  113 #+END_SRC
  114 
  115 ***** Login As User
  116 We will finish the rest of the configuration using the user account.
  117 #+BEGIN_SRC sh
  118 # su <username>
  119 #+END_SRC
  120 
  121 ***** Package Manager
  122 I used to use =packer= as wrapper around AUR and =pacman=. However, after learning about [[https://wiki.archlinux.org/index.php/AUR_helpers#Comparison_table][inherent insecurity]] in their package building processes, I switched to a more secure AUR helper =trizen= (=pacaur= is another choice, and fun fact: there is a reddit bot that tells you to switch to =pacaur= every time =yaourt= is mentioned in a post): =trizen= prompts user to inspect =PKGBUILD=, =*.install= and other scripts before sourcing them and =trizen= is written in Perl instead of Bash. To install =trizen=, first install dependencies via =pacman= according to its [[https://aur.archlinux.org/packages/trizen/][AUR Page]], then clone its [[https://github.com/trizen/trizen][git repo]] to a local directory. Navigate to the directory containing =PKGBUILD= and run
  123 #+BEGIN_SRC sh
  124 $ makepkg
  125 #+END_SRC
  126 to make package and
  127 #+BEGIN_SRC sh
  128 $ pacman -U trizen-*.pkg.tzr.xz
  129 #+END_SRC
  130 to install =trizen=.
  131 
  132 ***** Useful Packages
  133 Once package manager is in place, install packages to your heart's content! Some of my bread-and-butter packages include =emacs= (I installed the cli-only version, =emacs-nox=), =tmux= (terminal multiplexor, very useful), =zsh=, =vim= (for quick edits), and etc.
  134 
  135 *** Security Related Stuff
  136 Now that a usable Arch Linux installation is in place, I would employ some security measures before hosting my website on it.
  137 
  138 **** Secure Login via =ssh=
  139 On local machine, generate your ssh keypair:
  140 #+BEGIN_SRC sh
  141 $ ssh-keygen -t rsa
  142 #+END_SRC
  143 
  144 Send your ssh keys to server:
  145 #+BEGIN_SRC sh
  146 $ ssh-copy-id <username>@<server>
  147 #+END_SRC
  148 
  149 Now, on server, make the following edits to =/etc/ssh/sshd_config= :
  150 #+BEGIN_SRC sh
  151 PermitRootLogin no
  152 ChallengeResponseAuthentication no
  153 PasswordAuthentication no
  154 UsePAM no
  155 AllowUsers <username>
  156 #+END_SRC
  157 These changes will disable root login, disable password login and only allow specified user to login via ssh.
  158 
  159 It is advisible to also change the default port (22) used for ssh connection, in the same file, specify port by (please remember this port selection):
  160 #+BEGIN_SRC sh
  161 port <non-std-port>
  162 #+END_SRC
  163 
  164 For these changes to take effect, restart =ssh= daemon:
  165 #+BEGIN_SRC sh
  166 $ sudo systemctl restart sshd.service
  167 #+END_SRC
  168 
  169 Keep this =ssh= session intact and attempt to start another =ssh= connection in local machine to see if the changes have taken effect (the original session is needed in case things are not working):
  170 #+BEGIN_SRC sh
  171 $ ssh -p <non-std-port> <username>@<server>
  172 #+END_SRC
  173 
  174 **** Firewall Settings
  175 I use =ufw= as my firewall and it is very easy to setup. Install =ufw= with =trizen= and enable the desired ports:
  176 #+BEGIN_SRC sh
  177 $ trizen -S ufw
  178 $ sudo ufw allow <port>/<protocol>
  179 #+END_SRC
  180 
  181 For instance, to allow =ssh= communication, allow =22/tcp= or =ssh= (if you used a non-standard port, allow =<non-std-port>/tcp=). Some other useful ports are:
  182 
  183 | Port      | Usage                               |
  184 |-----------+-------------------------------------|
  185 | =80/tcp=  | =http=                              |
  186 | =443/tcp= | =https=                             |
  187 | =143=     | imap access                         |
  188 | =993=     | imap over =ssl=                     |
  189 | =25=      | receive incoming mail               |
  190 | =587=     | smtp access (with or without =ssl=) |
  191 
  192 To review the added ports and enable them:
  193 #+BEGIN_SRC sh
  194 $ sudo ufw show added
  195 $ sudo ufw enable
  196 #+END_SRC
  197 
  198 Auto start up:
  199 #+BEGIN_SRC sh
  200 $ sudo systemctl enable ufw.service
  201 #+END_SRC
  202 
  203 **** Sync Server Time
  204 Sync server time with =ntp= :
  205 #+BEGIN_SRC sh
  206 $ trizen -S ntp
  207 $ sudo systemctl enable ntpd.service
  208 #+END_SRC
  209 
  210 Check time server status with:
  211 #+BEGIN_SRC sh
  212 $ ntpq -p
  213 #+END_SRC
  214 
  215 **** Setting up PTR Record
  216 It turns out that DigitalOcean handles this automatically, all I needed to do is set the droplet name to a Fully Qualified Domain Name (FQDN), in this case =shimmy1996.com=. I then checked if the record is in place with:
  217 #+BEGIN_SRC sh
  218 $ dig -x <ip_address>
  219 #+END_SRC
  220 
  221 *** Firing up the Server
  222 Next step would be actually preparing the server for serving contents.
  223 
  224 **** Create Web Directory
  225 Create a directory for serving web contents, a common choice would be:
  226 #+BEGIN_SRC sh
  227 $ mkdir ~/public_html
  228 #+END_SRC
  229 Make sure to give this directory (including the user =home= folder) appropriate permission with =chmod= (=755= would normally work). Populate the directory with a simple =index.html= for testing if you want.
  230 
  231 **** Instal =nginx=
  232 Install =nginx= with =trizen=, and edit =/etc/nginx/nginx.conf= to set up =http= server (the one set to =listen 80 default_server=):
  233 #+BEGIN_SRC sh
  234 server_name www.<domainname> <domainname>
  235 root /path/to/public_html
  236 #+END_SRC
  237 For the =server_name= line add as many as you want. You may want to put your mail server address on it as well so that you can generate a single ssl certificate for everything. After these changes are made, (re)start and enable =nginx=:
  238 #+BEGIN_SRC sh
  239 $ sudo systemctl restart nginx.service
  240 $ sudo systemctl enable nginx.service
  241 #+END_SRC
  242 
  243 **** DNS Setup
  244 The next step is to set up DNS records for our server. There are three types of records that need to be set up initially, =NS=, =A=, and =CNAME=. I also included some other useful records:
  245 
  246 | Type    | Hostname              | Value                         | Usage                                                    |
  247 |---------+-----------------------+-------------------------------+----------------------------------------------------------|
  248 | =NS=    | @                     | nameserver address            | specifiec name server to use                             |
  249 | =A=     | @                     | supplied IPv4 address         | redirects host name to IPv4 address                      |
  250 | =CNAME= | www (can be anything) | @                             | sets =www.<hostname>= as an alias                        |
  251 | =MX=    | @                     | mail server address           | specifiec mail server to use                             |
  252 | =CAA=   | @                     | authorizor of SSL certificate | prevents other authority from certifying SSL certificate |
  253 
  254 In my case, though I use Google Domains to host my domain, I still use DigitalOcean's name server. So I needed to setup these records on DigitalOcean and =NS= records on Google Domains.
  255 
  256 After this step, you website should be accessible via your domain name, although it may take a few hours for the DNS record to populate.
  257 
  258 **** SSL Certificate
  259 [[https://letsencrypt.org][Let's Encrypt]] is a great project and [[https://certbot.eff.org/][=certbot=]] is an awesome tool for SSL certificate generation. Kudos to the nice folks at EFF and Linux Foundation. I simply followed the instructions on [[https://certbot.eff.org/#arch-nginx][EFF site]]:
  260 
  261 #+BEGIN_SRC sh
  262 $ sudo pacman -S certbot-nginx
  263 $ sudo certbot --nginx
  264 #+END_SRC
  265 
  266 To provide some extra credibility to the certificate, I added an =CAA= record in my DNS settings with issue authority granted for =letsencrypt.org=. For now Let's Encrypt does not support wildcard certificate but will be [[https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html][January 2018]], and this is why I added a bunch of subdomains into my =nginx.config= (so that the certificate covers these subdomains as well).
  267 
  268 *** What Now?
  269 After a couple hours (mostly waiting for DNS records to populate), and my website is online again. With a VPS at my disposal, I also host my personal email now and I might organize my random notes pieced from various websites into a post as well. I am still trying to figure out an efficient workflow for writing multilingual post with =org-mode= in =hugo= and once I am convinced I have found an acceptable solution, I will also post it.
  270 
  271 ** DONE zh
  272 :PROPERTIES:
  273 :EXPORT_TITLE: 新站点架设过程
  274 :EXPORT_FILE_NAME: 2017-09-25-my-server-setups-and-whatnot.zh.md
  275 :END:
  276 
  277 *** 为何要重新建站?新站建在哪里?
  278 在忍受了笨重的 Wordpress 三年后(以及 Bluehost 充满2003年设计感的管理面板),我终于决定放弃旧站另起炉灶。我对 Wordpress 博客主要有这些不满:
  279 
  280 - 体积庞大,占用很多不必要的服务器空间。
  281 - 没法使用我熟悉的工具来方便地备份。
  282 - 没有良好的命令行界面,而命令行正在成为我做任何事情的首选工具。
  283 - 缺少一些我所需要的基本功能,比如多语言支持。在部分人手里 WordPress 或许极为强大,但是我不想投入时间学习 CSS/js/php ,也不想从那些源头不明的 WordPress 插件商店里下载任何东西。
  284 - 这些 WordPress 主题/插件商店让我想起 Ubuntu 软件中心。
  285 - WordPress 有很多我用不到的功能,比如用户系统。这用在个人博客上显然是杀鸡用牛刀。
  286 
  287 在我确定了自己的需求后,我很容易地就找到了替代品:一个用我所知道的编程语言(或者我愿意学习的编程语言)所实现的快而小巧并带有原生多语言支持的静态站点生成器,那就是 =hugo= 。
  288 
  289 至于站点托管服务,我本来考虑使用 github pages 或 netlify 这种简单快速的解决办法,但是考虑到是个人站点,还是 VPS 这种功能强大一些的选择比较合适。而且 github pages 不支持自定义域名的 https ,这对我来说无法接受。我列出了所有比较出名的 VPS 服务提供商,筛出支持 Arch Linux 的部分,最后选择了 DigitalOcean 。由于我想要完全切断和 Bluehost 的联系,我把自己的域名也转移到了 Google Domains 。
  290 
  291 *** 安装 Arch Linux
  292 注意 Arch Linux 其实并不适合用作服务器操作系统。如果一切以系统稳定性为优先,那么选择一个非滚动更新的 Linux 发行版比较合适。我在服务器上用 Arch Linux 主要是因为我在我的所有其他电脑上也都运行 Arch Linux。如果你选择使用 Arch Linux 作为服务器操作系统,最好勤于备份:虽然我还没遇到这种情况,但是常有人抱怨 Arch Linux 很容易被玩坏。
  293 
  294 **** 安装系统
  295 显然我得到的关于 DigitalOcean 支持 Arch Linux 的情报已经过时了,他们已经停止支持 Arch Linux 有一阵子了。好在有 [[https://github.com/gh2o/digitalocean-debian-to-arch][digitalocean-debian-to-arch]] ,使得在水滴( droplet , DigitalOcean 对每个服务器的称呼)上安装 Arch Linux 并不困难。我只需要 [[https://www.digitalocean.com/community/tutorials/how-to-create-your-first-digitalocean-droplet][新建一个 droplet]] ,通过 =ssh= 登录服务器,并执行:
  296 
  297 #+BEGIN_SRC sh
  298 # wget https://raw.githubusercontent.com/gh2o/digitalocean-debian-to-arch/debian9/install.sh -O install.sh
  299 # bash install.sh
  300 #+END_SRC
  301 
  302 **** 系统设置
  303 上述安装完成后,我的 droplet 上就有了带有网络的 Arch Linux 。绝大部分的额外设置都可以在 [[https://wiki.archlinux.org/index.php/Installation_guide][Arch Wiki]] 找到。我并没有想把这篇日志写成完整的教程,所以细节部分最好参考 Arch Wiki。记录在这篇日志里的指令只是做个人记录之用。
  304 
  305 ***** 系统时钟
  306 同步系统时钟并设置时区。
  307 #+BEGIN_SRC sh
  308 # timedatectl set-ntp true
  309 # timedatectl settimezone <Region>/<City>
  310 #+END_SRC
  311 
  312 ***** 安装基础软件包
  313 安装/升级 =base= 和 =base-devel= 软件包。
  314 #+BEGIN_SRC sh
  315 # pacman -S base base-devel
  316 #+END_SRC
  317 
  318 ***** Fstab
  319 生成 =fstab= 。
  320 #+BEGIN_SRC sh
  321 # genfstab -U / >> /etc/fstab
  322 #+END_SRC
  323 
  324 ***** 设置系统语言环境
  325 在 =/etc/locale.conf= 里去掉 =en_US.UTF-8 UTF-8= 的注释,然后运行:
  326 #+BEGIN_SRC sh
  327 locale-gen
  328 #+END_SRC
  329 
  330 在 =/etc/locale.conf= 里设置 =LANG=en_US.UTF-8= 。
  331 
  332 ***** 主机名
  333 编辑 =/etc/hosts= 以加入水滴的主机名:
  334 #+BEGIN_SRC sh
  335 127.0.1.1    <hostname>.localdomain <hostname>
  336 #+END_SRC
  337 
  338 ***** 引导加载程序和 Initramfs
  339 针对英特尔处理器的优化:
  340 #+BEGIN_SRC sh
  341 # pacman -S intel-ucode
  342 # grub-mkconfig -o /boot/grub/grub.cfg
  343 #+END_SRC
  344 
  345 在 initramfs 里加入 =crc32= 模组,不然可能导致水滴无法启动。编辑 =/etc/mkinitcpio.conf= :
  346 #+BEGIN_SRC sh
  347 MODULES= "crc32 libcrc32c crc32c_generic crc32c-intel crc32-pclmul"
  348 #+END_SRC
  349 
  350 重新生成 initramfs 镜像。
  351 #+BEGIN_SRC sh
  352 # mkinitcpio -p linux
  353 #+END_SRC
  354 
  355 ***** Root 用户密码
  356 你懂的。
  357 #+BEGIN_SRC sh
  358 # passwd
  359 #+END_SRC
  360 
  361 **** 用户设置
  362 这是一些让 Arch Linux 使用起来更加友好的设置。
  363 
  364 ***** 创建用户帐号
  365 显然只使用 root 帐号不是什么好主意:
  366 #+BEGIN_SRC sh
  367 # useradd -m -G wheel -s /bin/bash <username>
  368 # passwd <username>
  369 #+END_SRC
  370 
  371 ***** 把用户加入 Sudoer
  372 编辑 =/etc/sudoers= 并加入:
  373 #+BEGIN_SRC sh
  374 <username> ALL=(ALL) ALL
  375 #+END_SRC
  376 
  377 ***** 以用户身份登录
  378 剩下的设置都会以用户身份执行:
  379 #+BEGIN_SRC sh
  380 # su <username>
  381 #+END_SRC
  382 
  383 ***** 软件包管理器
  384 我一开始使用 =packer= 来同时使用 =pacman= 和安装 AUR 软件包。但是在我了解到其软件安装过程有 [[https://wiki.archlinux.org/index.php/AUR_helpers#Comparison_table][诸多安全隐患]] 后,我开始改用 =trizen= ( =pacaur= 是另一个较为稳妥的选择,而且在 reddit 上有一个机器人会在所有提到 =yaourt= 的帖子下面安利 =pacaur= ): =trizen= 会提示用户在安装前检查 =PKGBUILD= , =*.install= 以及其他代码,而且 =trizen= 是用 Perl 而不是 Bash 写的。想要安装 =trizen= ,先根据 [[https://aur.archlinux.org/packages/trizen/][AUR 页面]] 通过 =pacman= 安装 =trizen= 所依赖的软件包,然后克隆其 [[https://github.com/trizen/trizen][git 仓库]] 到本地。进入包含 =PKGBUILD= 的文件夹并运行:
  385 #+BEGIN_SRC sh
  386 $ makepkg
  387 #+END_SRC
  388 来编译软件包,
  389 #+BEGIN_SRC sh
  390 $ pacman -U trizen-*.pkg.tzr.xz
  391 #+END_SRC
  392 来安装 =trizen=.
  393 
  394 ***** 常用软件包
  395 在设置完软件包管理器后,就可以大肆安装各种软件了!我的一些必备软件包括 =emacs= (在服务器上我只安装了命令行版本, =emacs-nox=), =tmux= (可以使用同一个命令行窗口来同时运行多个指令,非常有用), =zsh= , =vim= (作快速编辑之用)。
  396 
  397 *** 安全相关
  398 Arch Linux 安装完成之后,我在把网站搬进去之前进行了一些安全方面的设置。
  399 
  400 **** 使用 =ssh= 安全登录
  401 在本地机器上生成 ssh 密匙:
  402 #+BEGIN_SRC sh
  403 $ ssh-keygen -t rsa
  404 #+END_SRC
  405 
  406 把 ssh 密匙发送到服务器:
  407 #+BEGIN_SRC sh
  408 $ ssh-copy-id <username>@<server>
  409 #+END_SRC
  410 
  411 接下来再服务器上编辑 =/etc/ssh/sshd_config= :
  412 #+BEGIN_SRC sh
  413 PermitRootLogin no
  414 ChallengeResponseAuthentication no
  415 PasswordAuthentication no
  416 UsePAM no
  417 AllowUsers <username>
  418 #+END_SRC
  419 这些改动会禁止 root 账户登录,禁止使用密码登录,并只允许特定用户通过 ssh 登录。
  420 
  421 除此之外,把用于 ssh 的端口(默认为22)改掉也是一个很棒的安全措施。继续编辑同一个文件(请记牢所选择的端口):
  422 #+BEGIN_SRC sh
  423 port <non-std-port>
  424 #+END_SRC
  425 
  426 为了让这些改动生效,重启 =ssh= 进程:
  427 #+BEGIN_SRC sh
  428 $ sudo systemctl restart sshd.service
  429 #+END_SRC
  430 
  431 接下来保留目前的 =ssh= 链接不变并在一个新窗口内尝试建立新链接以确认一切正常(保留原有链接以防设置出错):
  432 #+BEGIN_SRC sh
  433 $ ssh -p <non-std-port> <username>@<server>
  434 #+END_SRC
  435 
  436 **** 防火墙设置
  437  =ufw= 作为防火墙非常方便易用。使用 =trizen= 来安装 =ufw= 并开放允许连接的端口:
  438 #+BEGIN_SRC sh
  439 $ trizen -S ufw
  440 $ sudo ufw allow <port>/<protocol>
  441 #+END_SRC
  442 
  443 如果想要允许 =ssh= 链接,开放 =22/tcp= 或 =ssh= (如果你改掉了默认端口,开放 =<non-std-port>/tcp= )。其他一些常用的端口有:
  444 
  445 | Port      | Usage                         |
  446 |-----------+-------------------------------|
  447 | =80/tcp=  | =http=                        |
  448 | =443/tcp= | =https=                       |
  449 | =143=     | imap 通信                     |
  450 | =993=     | imap =ssl= 通信               |
  451 | =25=      | 收取外界来的邮件              |
  452 | =587=     | smtp 通信 (不论有无 =ssl= ) |
  453 
  454 回顾已开放的端口并开启防火墙:
  455 #+BEGIN_SRC sh
  456 $ sudo ufw show added
  457 $ sudo ufw enable
  458 #+END_SRC
  459 
  460 设置自动启动:
  461 #+BEGIN_SRC sh
  462 $ sudo systemctl enable ufw.service
  463 #+END_SRC
  464 
  465 **** 同步服务器时间
  466 使用 =ntp= 同步服务器时间:
  467 #+BEGIN_SRC sh
  468 $ trizen -S ntp
  469 $ sudo systemctl enable ntpd.service
  470 #+END_SRC
  471 
  472 检查时间服务器的状态:
  473 #+BEGIN_SRC sh
  474 $ ntpq -p
  475 #+END_SRC
  476 
  477 **** 设置 PTR 记录
  478 DigitalOcean 会自动设置 PTR 记录,我唯一需要做的就是将水滴的名字改为绝对领域名称( FQDN ,帅气但是八成是机翻的译名取自 [[https://zh.wikipedia.org/wiki/完整網域名稱][Wikipedia]] ),也就是 =shimmy1996.com= 。完成这一设置后,我可以通过以下命令来查看设置是否成功。
  479 #+BEGIN_SRC sh
  480 $ dig -x <ip_address>
  481 #+END_SRC
  482 
  483 *** 正式启动服务器
  484 在完成以上设置后,就可以为服务器托管网站做准备了。
  485 
  486 **** 建立网页文件夹
  487 创建一个网页文件夹来放网页文件,一个比较普遍的选择是:
  488 #+BEGIN_SRC sh
  489 $ mkdir ~/public_html
  490 #+END_SRC
  491 
  492 确认该文件夹(以及用户的 =home= 文件夹)有合适的权限设置。权限设置可以用 =chmod= 修改(一般设成 =755= 就好)。可以在网页文件夹中放一个简单的 =index.html= 来方便测试。
  493 
  494 **** 安装 =nginx=
  495 用 =trizen= 安装 =nginx= ,并编辑 =/etc/nginx/nginx.conf= 来设立 =http= 服务器(带有 =listen 80 default_server= 设置的部分):
  496 #+BEGIN_SRC sh
  497 server_name www.<domainname> <domainname>
  498 root /path/to/public_html
  499 #+END_SRC
  500 
  501 在 =server_name= 这一行可以多列一些网址。如果你想一并架设邮箱服务器的话,一并将邮箱服务器地址列入网址就免去了生成额外的 ssl 证书的麻烦。在这些设置完成后,(重新)开始 =nginx= 并将其设为开机启动:
  502 #+BEGIN_SRC sh
  503 $ sudo systemctl restart nginx.service
  504 $ sudo systemctl enable nginx.service
  505 #+END_SRC
  506 
  507 **** DNS 设置
  508 下一步是为服务器完成 DNS 记录的设置。一开始必须设置的记录有三种: =NS= , =A= ,和 =CNAME= 。我记下了一些比较常用的记录:
  509 
  510 | 记录种类 | 主机名                 | 数值                    | 用法                                |
  511 | =NS=     | @                      | DNS 服务器的地址        | 确认用于解析域名的服务器            |
  512 | =A=      | @                      | 水滴的 IPv4 地址        | 将主机名重定向到 IP 地址            |
  513 | =CNAME=  | www (可以是任何东西) | @                       | 将 =www.<hostname>= 设为主机名的    |
  514 | =MX=     | @                      | 邮箱服务器地址          | 指定邮箱服务器                      |
  515 | =CAA=    | @                      | 标明 SSL 证书的授权机构 | 阻止其他授权机构为本站发行 SSL 证书 |
  516 
  517 我的域名托管在 Google Domains ,但我的网站用的是 DigitalOcean 的 DNS ,所以我需要在 DigitalOcean 上完成设置并在 Google Domains 里加入 =NS= 记录。
  518 
  519 在完成这些设置后,我就可以通过我的域名访问所架设的网站了,不过 DNS 记录通常需要数小时才会完全生效。
  520 
  521 **** SSL 证书
  522 [[https://letsencrypt.org][Let's Encrypt]] 是个非常棒的项目。使用 [[https://certbot.eff.org/][=certbot=]] 这个工具就可以很方便的生成 SSL 证书。这里向 EFF 和 Linux 基金会的人们致以谢意。生成证书只需要运行 [[https://certbot.eff.org/#arch-nginx][EFF 网站]] 上所记载的命令即可:
  523 
  524 #+BEGIN_SRC sh
  525 $ sudo pacman -S certbot-nginx
  526 $ sudo certbot --nginx
  527 #+END_SRC
  528 
  529 为了给证书增加一点可信度,我还在 DNS 记录中加了一条 =CAA= 记录,标明 =letsencrypt.org= 是唯一允许给本站 SSL 证书授权的机构。目前 Let's Encrypt 还不支持通配符证书,不过会在 [[https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html][2018年1月]] 添加这一支持。由于没有通配符证书,我只好在 =nginx.config= 里加上所有二级域名(这样生成证书的才能够为这些域名提供验证)。
  530 
  531 *** 下一步?
  532 在鼓捣了几个小时后(其实大部分时间是在等 DNS 记录扩散),我的新站就上线了。既然选择了运行 VPS,我打算好好发挥它的潜能并架设了自己的电子邮箱。我正在考虑把架设邮箱过程中从各个网站七拼八凑其来的命令行笔记也整理成一篇日志。目前我仍在试图寻找使用 =org-mode= 在 =hugo= 里写多语言日志的最优工作流程。当我确信已经找到一套可以接受的解决方案的时候我会一并写成日志。
  533 
  534 * DONE Spam or Ham
  535 :PROPERTIES:
  536 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :date 2017-10-14 :slug spam-or-ham
  537 :END:
  538 
  539 ** DONE en
  540 :PROPERTIES:
  541 :EXPORT_TITLE: Spam or Ham
  542 :EXPORT_FILE_NAME: 2017-10-14-spam-or-ham.en.md
  543 :END:
  544 
  545 As planned, I am documenting my mail server setups. Setting up the mail server is probably documented everywhere, but I had to put in some effort make my setup secure enough to prevent it from been mistaked as spam.
  546 
  547 *** Setting up the mail server
  548 I really don't see how I can write anything better than [[http://www.netarky.com/programming/arch_linux/Arch_Linux_mail_server_setup_1.html][this tutorial]], so I will just document some of the steps that seemed missing from the tutorial.
  549 
  550 **** Setting DNS Record
  551 Before anything, I needed to setup my DNS record. I created an =A= record for my mail server address, and added a =MX= record indicating the mail will be handled by the mail server.
  552 
  553 **** Creating =Maildir=
  554 After setting up =postfix= for the first time, I needed to setup the =Maildir= manually and giving it appropriate permissions:
  555 #+BEGIN_SRC sh
  556 $ mkdir -p /home/<username>/Maildir/{cur,new,tmp}
  557 $ chown <username> /home/<username>/Maildir/{,cur,new,tmp}
  558 $ chmod 0755 /home/<username>/Maildir/{,cur,new,tmp}
  559 #+END_SRC
  560 
  561 **** SSL Certificate
  562 In stead of using the built-in certificate generators in =dovecot=, I choose to use the same SSL certificate for my website. I added my mail server address to the =server_name= field in =/etc/nginx/nginx.conf= and generated my certificate with =certbot=. After that, I simply changed =/etc/dovecot/conf.d/10-ssl.conf= for =dovecot= :
  563 #+BEGIN_SRC sh
  564 use_ssl = yes
  565 ssl_cert = </path/to/fullchain.pem
  566 ssl_key = </path/to/privkey.pem
  567 #+END_SRC
  568 
  569 Similarly for =postfix= I also used this certificate. Do note that =dovecot= and =postfix= should be run as =root= to have read permissions to read these certificates.
  570 
  571 **** Mail Client
  572 I am using Thunderbird as my mail client and for receiving mail. I used SSL/TLS while for sending mail, I needed to set STARTTLS.
  573 
  574 *** Security Measures
  575 After completing the email setup, I immediately tested the server by sending test emails, only to find them been tossed straight into spam by gmail. It seems that gmail has a new feature that shows the security check status on the email (accessible by 'View Original'). These measures include SPF, DKIM and DMARC. My avatar showed up as an octagon with a question mark, indicating the mail server failing the basic SPF check. In order to avoid this, I took a bunch of security measures to tick all the boxes from email security test sites like [[https://intodns.com][intodns]] and [[https://mxtoolbox.com][mxtoolbox]].
  576 
  577 **** Sender Policy Framework (SPF)
  578 An SPF TXT record documents the allowed servers to send emails on behalf of this address. In my case where only mail servers documented in the MX TXT record are used, I simply put in:
  579 #+BEGIN_SRC sh
  580 v=spf1 mx -all
  581 #+END_SRC
  582 
  583 **** DomainKeys Identified Mail (DKIM)
  584 I am using =opendkim= to sign and verify that emails are indeed from my server. After installing the =opendkim= package, I followed the instruction in [[https://wiki.archlinux.org/index.php/OpenDKIM][Arch Wiki]]. First copy example configuration file from =/etc/opendkim/opendkim.conf.sample= to =/etc/opendkim/opendkim.conf= and edit (socket selection can be arbitrary):
  585 #+BEGIN_SRC sh
  586 Domain                  <domainname>
  587 KeyFile                 /path/to/keys.private
  588 Selector                <myselector>
  589 Socket                  inet:<dkimsocket>@localhost
  590 UserID                  opendkim
  591 Conicalization          relaxed/simple
  592 #+END_SRC
  593 
  594 Next, in the specified keyfile directory (the default is =/var/db/dkim/=), generate keys with:
  595 #+BEGIN_SRC sh
  596 $ opendkim-genkey -r -s <myselector> -d <domainname> --bits=2048
  597 #+END_SRC
  598 
  599 Along with the generated =.private= file is a =.txt= file with the necessary TXT record for DKIM. It basically posts the public key for your mail server. Note that the TXT record may need to be broke down into several strings to comply with the 255 character limit. To check if the TXT record has been properly setup, I used (requires package =dnsutils= ):
  600 #+BEGIN_SRC sh
  601 $ host -t TXT <myselector>._domainkey.<domainname>
  602 #+END_SRC
  603 
  604 The final step would be to start the =opendkim= service and  make sure =postfix= performs the encryption upon sending email. Edit =/etc/postfix/main.cf= to be:
  605 #+BEGIN_SRC sh
  606 non_smtpd_milters=inet:127.0.0.1:<dkimsocket>
  607 smtpd_milters=inet:127.0.0.1:<dkimsocket>
  608 #+END_SRC
  609 
  610 After reloading =postfix=, DKIM should be in effect.
  611 
  612 **** Domain-based Message Authentication, Reporting and Conformance (DMARC)
  613 Without surprise, there is a package =opendmarc= that implements DMARC and there is also an [[https://wiki.archlinux.org/index.php/OpenDMARC][Arch Wiki]] page for it. Do note that this would require SPF and DKIM to be setup first. After installation, I edited =/etc/opendmarc/opendmarc.conf=:
  614 #+BEGIN_SRC sh
  615 Socket inet:<dmarcsocket>@localhost
  616 #+END_SRC
  617 
  618 After starting the service, enable DMARC filter in =postfix= (separate with comma):
  619 #+BEGIN_SRC sh
  620 non_smtpd_milters=inet:127.0.0.1:<dkimsocket>, inet:127.0.0.1:<dmarcsocket>
  621 smtpd_milters=inet:127.0.0.1:<dkimsocket>, inet:127.0.0.1:<dmarcsocket>
  622 #+END_SRC
  623 
  624 The final step is to add a DMARC TXT record in DNS settings as detailed on Arch Wiki page and reload =postfix=.
  625 
  626 *** Ticking the Boxes
  627 I tested my server by sending test email to =check-auth@verifier.port25.com= and everything seems to be working. Not to mention that my email no longer gets classified as spam by gmail and I can see my emails passing SPF, DKIM and DMARC checks in 'View Original'. I also get an detailed daily report from gmail due to DMARC. At this point, I am pretty comfortable about ditching all my previous gmail addresses and sticking to my own email. I am also looking into options of self-hosting calenders. Hopefully in the near future I can completely ditch Google for my essential communication needs.
  628 
  629 ** DONE zh
  630 :PROPERTIES:
  631 :EXPORT_TITLE: 是 Spam 还是 Ham
  632 :EXPORT_FILE_NAME: 2017-10-14-spam-or-ham.zh.md
  633 :END:
  634 
  635 遵循之前的计划,我打算将设置邮箱的过程记录下来。设置邮箱大部分地方都有教程,不过我需要添加不少额外的安全设置来避免邮件被扔进垃圾箱。
  636 
  637 *** 搭建邮件服务器
  638 我八成是写不出比 [[http://www.netarky.com/programming/arch_linux/Arch_Linux_mail_server_setup_1.html][这篇教程]] 更好的步骤说明的,所以我就在这里把我额外需要的一些设置记录下来。
  639 
  640 **** 设置 DNS 记录
  641 在开始搭建邮箱之前,我需要设置 DNS 记录。我为我的邮件服务器地址设置了一条 =A= 记录,并用一条 =MX= 记录来标明所使用的邮件服务器。
  642 
  643 **** 创建 =Maildir=
  644 在设置好 =postfix= 之后,我需要手动创建 =Maildir= 文件夹并赋予其合适的权限:
  645 #+BEGIN_SRC sh
  646 $ mkdir -p /home/<username>/Maildir/{cur,new,tmp}
  647 $ chown <username> /home/<username>/Maildir/{,cur,new,tmp}
  648 $ chmod 0755 /home/<username>/Maildir/{,cur,new,tmp}
  649 #+END_SRC
  650 
  651 **** SSL 证书
  652 我没有使用 =dovecot= 自带的证书生成器,而是直接沿用了我网站的 SSL 证书。我将邮件服务器地址加入 =/etc/nginx/nginx.conf= 中的 =server_name= 下,并用 =certbot= 生成了合适的证书。在这之后,我修改了 =dovecot= 的设置文件 =/etc/dovecot/conf.d/10-ssl.conf= :
  653 #+BEGIN_SRC sh
  654 use_ssl = yes
  655 ssl_cert = </path/to/fullchain.pem
  656 ssl_key = </path/to/privkey.pem
  657 #+END_SRC
  658 
  659 我也在 =postfix= 上用了这个证书。需要注意的是 =dovecot= 和 =postfix= 都需要用 =root= 账户运行才会有权限读取证书。
  660 
  661 **** 邮件客户端
  662 我使用 Thunderbird 作为邮件客户端。收取邮件时,我使用 SSL/TLS,而发送邮件则使用 STARTTLS。
  663 
  664 *** 安全措施
  665 设置好邮件服务器后,我试着发了几封邮件,不过发现都被 gmail 扔进了垃圾箱。似乎 gmail 最近添加了显示邮件安全检查状态的功能(在 gmail 中点击“查看原件”即可看到)。这些检查包括 SPF , DKIM ,和 DMARC 。由于我的邮件服务器没有通过最基本的 SPF 检查,所以我的头像显示为一个标着问号的八边形。为了避免邮件被扔进垃圾箱,我进行了一系列安全设置以保证我的邮件服务器能通过网上邮箱安全测试平台(我使用的是 [[https://intodns.com][intodns]] 和 [[https://mxtoolbox.com][mxtoolbox]] )的考验。
  666 
  667 **** 发件人策略框架( SPF )
  668 SPF TXT 记录标明了某一域名所承认的邮件服务器地址。在我的情况下,我只会用到 MX TXT 记录中所提到的邮件服务器,所以我的 SPF TXT 记录就是:
  669 #+BEGIN_SRC sh
  670 v=spf1 mx -all
  671 #+END_SRC
  672 
  673 **** 域名密匙邮件认证( DKIM )
  674 我使用 =opendkim= 来为邮件署名,以验证邮件的确来自于我的服务器。在安装了 =opendkim= 软件包后,我遵循 [[https://wiki.archlinux.org/index.php/OpenDKIM][Arch Wiki]] 里的步骤完成了设置。首先,复制设置文件模板 =/etc/opendkim/opendkim.conf.sample= 到 =/etc/opendkim/opendkim.conf= 并编辑(端口可以随意选择):
  675 #+BEGIN_SRC sh
  676 Domain                  <domainname>
  677 KeyFile                 /path/to/keys.private
  678 Selector                <myselector>
  679 Socket                  inet:<dkimsocket>@localhost
  680 UserID                  opendkim
  681 Canonicalization        relaxed/simple
  682 #+END_SRC
  683 
  684 接下来,在设置文件所指定的密匙文件路径下(默认为 =/var/db/dkim/= ),生成密匙:
  685 #+BEGIN_SRC sh
  686 $ opendkim-genkey -r -s <myselector> -d <domainname> --bits=2048
  687 #+END_SRC
  688 
  689 执行指令后生成的不仅仅是 =.private= 密匙文件,还有装有完成 DKIM 设置所需 TXT 记录的 =.txt= 文件。这一记录的功能在于公布邮箱服务器的公共密匙。需要注意的是这条 TXT 记录有可能会被分成数条字符串,以满足每条字符串最长 255 字符的要求。为了查看 TXT 记录是否有设置成功,我运行了(需要安装 =dnsutils= 软件包):
  690 #+BEGIN_SRC sh
  691 $ host -t TXT <myselector>._domainkey.<domainname>
  692 #+END_SRC
  693 
  694 接下,重启 =opendkim= 服务并确保 =postfix= 在发出邮件之前执行加密。编辑 =/etc/postfix/main.cf= :
  695 #+BEGIN_SRC sh
  696 non_smtpd_milters=inet:127.0.0.1:<dkimsocket>
  697 smtpd_milters=inet:127.0.0.1:<dkimsocket>
  698 #+END_SRC
  699 
  700 在重启 =postfix= 后, DKIM 就开始运作了。
  701 
  702 **** 基于域名的邮件认证,报告和一致性检查( DMARC )
  703 毫无意外,有一个软件包 =opendmarc= 可以用于部署 DMARC ,并且这一软件包也有对应的 [[https://wiki.archlinux.org/index.php/OpenDMARC][Arch Wiki]] 页面。需要注意的是, DMARC 必须在 SPF 和 DKIM 都设置完成后才能生效。在安装软件包后,编辑 =/etc/opendmarc/opendmarc.conf=:
  704 #+BEGIN_SRC sh
  705 Socket inet:<dmarcsocket>@localhost
  706 #+END_SRC
  707 
  708 在启动 =opendmarc= 服务后,在 =postfix= 中启用 DMARC 邮件滤网(与 DKIM 滤网用逗号隔开):
  709 #+BEGIN_SRC sh
  710 non_smtpd_milters=inet:127.0.0.1:<dkimsocket>, inet:127.0.0.1:<dmarcsocket>
  711 smtpd_milters=inet:127.0.0.1:<dkimsocket>, inet:127.0.0.1:<dmarcsocket>
  712 #+END_SRC
  713 
  714 最后,按照 Arch Wiki 所指示的步骤在 DNS 设置中加上一条 DMARC TXT 记录并重启 =postfix= 就大功告成了。
  715 
  716 *** 通过所有测试
  717 给 =check-auth@verifier.port25.com= 发送测试邮件后,我收到了一份邮件服务器的测试报告。报告显示所有安全设置都在正常运作。除此之外, gmail 不再将我的邮件扔进垃圾箱了,而“查看原件”页面下也显示我的邮件通过了 SPF , DKIM , 和 DMARC 检查。 由于启用了 DMARC , gmail 还会每天向我的邮箱发送一份安全报告。折腾到这个地步后,我对我的新邮箱比较满意了,并准备废除我之前所使用的邮箱。我还在寻找可以自己架设的日历服务,希望不久的将来我可以完全摆脱在通讯方面对 Google 服务的依赖。
  718 
  719 * DONE No More Disqusting Disqus
  720 :PROPERTIES:
  721 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :date 2017-10-22 :slug no-more-disqusting-disqus
  722 :END:
  723 
  724 ** DONE en
  725 :PROPERTIES:
  726 :EXPORT_TITLE: No More Disqusting Disqus
  727 :EXPORT_FILE_NAME: 2017-10-22-no-more-disqusting-disqus.en.md
  728 :END:
  729 
  730 A while back Disqus had a [[https://blog.disqus.com/security-alert-user-info-breach][user info breach]], which made me reconsider my choice of commenting system. If I am already hosting my own blog and email, why stop there and leave out commenting system to be served by a third-party platform?
  731 
  732 *** The Good, The Bad, and The Ugly
  733 I have mixed feelings for Disqus' idea of turning comments across different sites into a unified social network. Personally, I use most social media services as 'media' rather than a social tool: they are obviously ill-suited for posting large paragraphs (thus the plethora of external links), and even for posting random thoughts, the sheer time it takes to type out a sensible and logically coherent argument (especially on mobile devices) frequntly puts me off. Since I'm so used to being that creepy lurker, I inevitably got into the habit of judging my social media identity: what would I think about this Frankenstein's monster made up of retweets and likes.
  734 
  735 Blog Comments work a little differently. I feel more relieved when commenting on a blog: it feels more like a convrsation with the blog owner rather than broadcasting myself to everyone on the Internet. Disqus, however, takes this away by social network-ifying blog comments. I guess the potential upside to Disqus is to attract more traffic, but I do not want my blog comments to become just another social media live feed: if one has valuable comment, the lack of Disqus should not deter him or her from posting it (while I've noticed the opposite happening quite a few times).
  736 
  737 Here's comes the ugly part though. Not to mention the fact that embedding JavaScript that I have no control over is a very bad idea, it was only until yesterday did I notice viewer tracking in Disqus is an opt-out system. Since I don't plan on monetizing on my blog, it really isn't worth risking blog viewers' privacy for what Disqus provides. Besides, it really worried me when I realized majority of upvotes in my Disqus comments came from zombie accounts with profile links set to dating sites. Whether these 'disqusting' (bad pun alert) accounts were hijacked due to the security breach or were simply created by spammers is beyond me, but yeah, I don't want these zombies lurking around my blog's comments.
  738 
  739 *** The Search for Replacements
  740 I have decided to selfhost a commenting system and my top priority is to avoid any external service if possible. After careful selection, the two finalists for the job are [[https://posativ.org/isso/][isso]] and [[https://staticman.net][staticman]]. Isso is a lightweight comment server written in Python, while staticman is an interesting set of APIs that parses comments into text files and adds them to your site's Github repo. Installing isso means having to deal with databases, which I really dread and would like to avoid at all cost; using staticman allows the site to remain static, yet relies on GitHub's API (and staticman.net's API if I don't host a instance myself). While maintaining an entirely static site is very tempting, I decided to try out Isso first to see if ditching all external sites is worth the effort.
  741 
  742 Just for shits and giggles, here's another interesting alternative: [[https://github.com/tessalt/echo-chamber-js][Echochamber.js]].
  743 
  744 *** Setting Up Isso
  745 The official website provides fairly good [[https://posativ.org/isso/docs/][documentation]] already. I installed isso from [[https://aur.archlinux.org/packages/isso/][AUR]] and enabled it via =systemctl=. Setting isso up was surprisingly painless(including the part with database), and I used a different [[https://posativ.org/isso/docs/setup/sub-uri/][configuration]] than default since I am running isso on the same server. The only issue I encountered is with =smtp=. By checking the status of =postfix=, I quickly determined the problem lies in =smtpd_helo_restrictions=: by disabling the option =reject_unknown_helo_hostname=, isso can now use the local =smtp= server without issues. I took some extra effort to customize the CSS template for isso and the comment section looks fairly good now (a lot faster as well).
  746 
  747 Happy Commenting!
  748 
  749 ** DONE zh
  750 :PROPERTIES:
  751 :EXPORT_TITLE: 不再使用 Disqus
  752 :EXPORT_FILE_NAME: 2017-10-22-no-more-disqusting-disqus.zh.md
  753 :END:
  754 
  755 不久之前, Disqus 发生了一起 [[https://blog.disqus.com/security-alert-user-info-breach][用户信息泄露事件]] 。这导致我开始重新考虑评论系统的选择:既然已经架设了自己的博客和电子邮件,也不差一个评论系统。
  756 
  757 *** 好家伙,坏家伙,丑家伙
  758 我对 Disqus 将不同网站的评论统一成一个社交网络的主意抱有比较复杂的看法。我个人使用社交媒体时更多的是作为 “媒体” 而不是社交的工具:这些服务显然不适合发表长篇大论(所以大多社交网站帖子都充斥着链接和长图),而就算是作为发表随感的工具,我也觉得在这些网站上编辑文字不怎么理想(尤其是在手机上)。常年潜水的习惯使得我时常反过来审视自己的社交网站人格:我站在第三者的角度会怎么看这堆转推和赞所构成的怪物。
  759 
  760 博客评论则比较不同。我在评论博客时更为放松:这种感觉更接近与博主一对一对话,而不是向整个网络广播自己的座标。社交媒体化的博客评论就不再给我这种感觉。使用 Disqus 的一大潜在好处大概在于能够吸引更多访客,不过我并不想让自己的博客评论区沦为又一个社交网络时间线:高价值的评论并不会因为我的网站不使用 Disqus 而消失(虽然相反的事情时有发生,并不是所有人都会愿意为了评论而注册新的社交网络帐号的)。
  761 
  762 接下来就要说到 Disqus 比较丑陋的一面了。且不提在网站上嵌入我自己没有办法控制的 JavaScript 是一大安全隐患,我直到昨天才意识到 Disqus 的访客数据收集是默认启用的。由于我不打算通过博客获得收入,以牺牲访客隐私为代价换取 Disqus 的服务并不值得。除此之外,我还发现 Disqus 评论中的大部分“赞同”都来自于挂着交友网站的僵尸帐号。至于这些僵尸帐号的来源是被盗用的帐号还是水军机器人我就无从了解了。总之我可不想让这些僵尸帐号在我的博客上晃悠。
  763 
  764 *** 寻找替代品
  765 我决定自己架设评论系统并尽量避开任何第三方服务。在细心搜寻后,[[https://posativ.org/isso/][isso]] 和 [[https://staticman.net][staticman]] 成为了最终的候选者。 Isso 是一个使用 Python 写成的轻量评论服务器;而 staticman 则是一套将评论转换成文本文件并自动加入博客 Github 仓库的 API 。安装 isso 意味着我必须使用我之前一直尽力避免的数据库;使用 staticman 则可以让我的网站保持静态,但是必须依靠 Github 的 API (如果我不自己架设 staticman 的话,还需要 staticman.net 的官方 API )。虽然保持一个完全静态的站点很吸引人,不过我还是决定先尝试 isso ,看看脱离第三方服务是否值得我花时间鼓捣数据库。
  766 
  767 我在寻找评论系统的过程中还发现了一个有趣的替代品:[[https://github.com/tessalt/echo-chamber-js][Echochamber.js]] 。
  768 
  769 *** 设置 isso
  770 Isso 的官网有很详细的 [[https://posativ.org/isso/docs/][说明文档]] 。我从 [[https://aur.archlinux.org/packages/isso/][AUR]] 安装了 isso 并使用 =systemctl= 启用了它。设置过程出奇的顺利(包括数据库的部分),因为我的 isso 和博客共用一台服务器,我使用了与默认不同的 [[https://posativ.org/isso/docs/setup/sub-uri/][设置]] 。我所遇到的唯一问题在于 =smtp= 。在检查 =postfix= 的运行状态后,我很快发现问题在于 =smtpd_helo_restrictions= :在停用 =reject_unknown_helo_hostname= 后, isso 就能使用 =smtp= 发送通知邮件了。除此之外,我稍微花了点时间修改 isso 的 CSS 模板。新的评论区看起来不仅更契合博客主题,速度也比 Disqus 快多了。
  771 
  772 祝评论愉快!
  773 
  774 * DONE 2017 in Review
  775 :PROPERTIES:
  776 :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :date 2017-12-31 :slug 2017-in-review
  777 :END:
  778 
  779 ** DONE en
  780 :PROPERTIES:
  781 :EXPORT_TITLE: 2017 in Review
  782 :EXPORT_FILE_NAME: 2017-12-31-2017-in-review.en.md
  783 :END:
  784 
  785 2017 is over within the next few hours and I fell obliged to write something about it. Hopefully I won't have too much regrets by the time I finish this post.
  786 
  787 *** What Have I Done
  788 I have been working full time since June. Working life is surprisingly more
  789 relaxing than I expected. My daily schedule has seen a great increase in
  790 stability: no more 4-hour-sleeping-schedule is an obvious improvement and I can
  791 finally set aside time for my interests.
  792 
  793 By the end of 2017, I have:
  794 
  795 - Set up my new blog and wrote more stuff than 2015 and 2016 combined.
  796 - Been using Emacs for 3 months.
  797 - Been using my own email for 3 months.
  798 - Found out I am pretty good at cooking.
  799 - Been running nearly daily for 6 months. I finished my first half-marathon with
  800   a sub 2 hour time.
  801 - Lost 20 pounds since June thanks to running.
  802 
  803 Doesn't look too shabby huh? It's been a great year.
  804 
  805 *** What's Next
  806 I've gotten into the habit of listening to Dayo Wong's stand-up comedy from time
  807 to time and for some reason one of his earlier shows /跟住去边度/ ( /What's
  808 Next/ ) left the deepest impression on me. I now also post this question to
  809 myself. Here's where I will be in 2018:
  810 
  811 - Train for a full marathon and hopefully finish one.
  812 - Write at least 20 blog articles.
  813 - Get the first signature for my PGP key.
  814 - Install Gentoo.
  815 - Read more, watch less.
  816 
  817 If I've learned anything from my past failed plans, it would be to always
  818 underestimate my own capabilities when planning, so I will just stop my list
  819 here and add additional goals as I march into 2018.
  820 
  821 Happy New Year and hopefully 2018 will be another spectacular one!
  822 
  823 ** DONE zh
  824 :PROPERTIES:
  825 :EXPORT_TITLE: 回顾 2017
  826 :EXPORT_FILE_NAME: 2017-12-31-2017-in-review.zh.md
  827 :END:
  828 
  829 2017 年再过几个小时就结束了,所以我觉得很有必要回顾一下过去这一年。但愿我在写完这篇日志的时候还能觉得 2017 过得没有后悔。
  830 
  831 *** 我都做了啥
  832 我从六月份开始全职工作了。社畜生活其实比我想象的要轻松不少,我的日常生活比上学时反而有规律得多:至少 4 小时的睡眠时间不再显得那么奢侈,而且我总算能分配一部分时间来发展兴趣了。
  833 
  834 在 2017 年里:
  835 
  836 - 使用 Emacs 三个月。
  837 - 使用自己架设的电子邮箱三个月。
  838 - 架设了新的站点并且更新了比 2015-2016 两年更多的内容。
  839 - 发现自己其实有点煮饭的隐藏才能
  840 - 我在后六个月中保持几乎每天跑步。我在 2 小时之内完成了我的第一个半程马拉松比赛。
  841 - 由于跑步,我的体重下降了 10 千克左右。
  842 
  843 我觉得2017是很充实很开心的一年。
  844 
  845 *** 跟住去边度
  846 最近常常听黄子华的栋笃笑,而 /跟住去边度/ 给我留下的印象最深。我也打算问问自己这个问题。 2018 我会:
  847 
  848 - 以马拉松为目标继续训练,有机会的话完成一次正式比赛。
  849 - 写 20 篇以上的日志。
  850 - 获得第一个 PGP 密匙签名。
  851 - 安装 Gentoo 。
  852 - 少看,多阅读。
  853 
  854 如果我有从过去那些我制定后没能执行的计划里得到任何经验的话,那就是定计划时最好稍微低估自己的能力,所以我的新年目标就先列到这里。在踏入2018后我会视情况添加新的内容。
  855 
  856 新年快乐!希望 2018 也会是充满惊喜的一年!