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 也会是充满惊喜的一年!