2017-09-25-my-server-setups-and-whatnot.en.md (12989B)
1 +++
2 title = "My Server Setups and Whatnot"
3 draft = false
4 date = 2017-09-25
5 slug = "my-server-setups-and-whatnot"
6 +++
7
8 ## Why move the blog? And to where? {#why-move-the-blog-and-to-where}
9
10 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:
11
12 - Clunky and eats up my server storage.
13 - Not as easy way to back up with tools I know.
14 - Does not come with a command line interface, which is becoming my preferred way of doing almost anything.
15 - 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.
16 - These theme and plugin marketplaces creeps me out in the same way as ubuntu software center.
17 - 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.
18
19 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`.
20
21 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.
22
23
24 ## Install Arch Linux {#install-arch-linux}
25
26 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.
27
28
29 ### Installation {#installation}
30
31 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 [digitalocean-debian-to-arch](https://github.com/gh2o/digitalocean-debian-to-arch). All I needed to to was [set up a droplet](https://www.digitalocean.com/community/tutorials/how-to-create-your-first-digitalocean-droplet), `ssh` into the server, and follow the instructions:
32
33 ```sh
34 # wget https://raw.githubusercontent.com/gh2o/digitalocean-debian-to-arch/debian9/install.sh -O install.sh
35 # bash install.sh
36 ```
37
38
39 ### Low Level Setup {#low-level-setup}
40
41 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 [Arch Wiki](https://wiki.archlinux.org/index.php/Installation%5Fguide). 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.
42
43
44 #### System Clock {#system-clock}
45
46 Sync system clock and set time zone.
47
48 ```sh
49 # timedatectl set-ntp true
50 # timedatectl settimezone <Region>/<City>
51 ```
52
53
54 #### Base Packages {#base-packages}
55
56 Install/update base packages.
57
58 ```sh
59 # pacman -S base base-devel
60 ```
61
62
63 #### Fstab {#fstab}
64
65 Generate `fstab`.
66
67 ```sh
68 # genfstab -U / >> /etc/fstab
69 ```
70
71
72 #### Set Locale {#set-locale}
73
74 Uncomment `en_US.UTF-8 UTF-8` in `/etc/locale.conf` then generate locale with:
75
76 ```sh
77 locale-gen
78 ```
79
80 Set `LANG=en_US.UTF-8` in `/etc/locale.conf`.
81
82
83 #### Hostname {#hostname}
84
85 Edit `/etc/hosts` and add hostname of droplet:
86
87 ```sh
88 127.0.1.1 <hostname>.localdomain <hostname>
89 ```
90
91
92 #### Boot Loader and Initramfs {#boot-loader-and-initramfs}
93
94 Optimizations for intel processors:
95
96 ```sh
97 # pacman -S intel-ucode
98 # grub-mkconfig -o /boot/grub/grub.cfg
99 ```
100
101 Add `crc32` modules to initramfs, as otherwise the droplet fails to boot. Edit `/etc/mkinitcpio.conf` :
102
103 ```sh
104 MODULES= "crc32 libcrc32c crc32c_generic crc32c-intel crc32-pclmul"
105 ```
106
107 Regenerate the initramfs image.
108
109 ```sh
110 # mkinitcpio -p linux
111 ```
112
113
114 #### Root Password {#root-password}
115
116 You know the drill.
117
118 ```sh
119 # passwd
120 ```
121
122
123 ### User Setups {#user-setups}
124
125 Here are some additional settings to make Arch Linux more useable.
126
127
128 #### Creature User {#creature-user}
129
130 Obviously it is not a good idea to use root account:
131
132 ```sh
133 # useradd -m -G wheel -s /bin/bash <username>
134 # passwd <username>
135 ```
136
137
138 #### Add User to Sudoer {#add-user-to-sudoer}
139
140 Edit `/etc/sudoers` and add:
141
142 ```sh
143 <username> ALL=(ALL) ALL
144 ```
145
146
147 #### Login As User {#login-as-user}
148
149 We will finish the rest of the configuration using the user account.
150
151 ```sh
152 # su <username>
153 ```
154
155
156 #### Package Manager {#package-manager}
157
158 I used to use `packer` as wrapper around AUR and `pacman`. However, after learning about [inherent insecurity](https://wiki.archlinux.org/index.php/AUR%5Fhelpers#Comparison%5Ftable) 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 [AUR Page](https://aur.archlinux.org/packages/trizen/), then clone its [git repo](https://github.com/trizen/trizen) to a local directory. Navigate to the directory containing `PKGBUILD` and run
159
160 ```sh
161 $ makepkg
162 ```
163
164 to make package and
165
166 ```sh
167 $ pacman -U trizen-*.pkg.tzr.xz
168 ```
169
170 to install `trizen`.
171
172
173 #### Useful Packages {#useful-packages}
174
175 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.
176
177
178 ## Security Related Stuff {#security-related-stuff}
179
180 Now that a usable Arch Linux installation is in place, I would employ some security measures before hosting my website on it.
181
182
183 ### Secure Login via `ssh` {#secure-login-via-ssh}
184
185 On local machine, generate your ssh keypair:
186
187 ```sh
188 $ ssh-keygen -t rsa
189 ```
190
191 Send your ssh keys to server:
192
193 ```sh
194 $ ssh-copy-id <username>@<server>
195 ```
196
197 Now, on server, make the following edits to `/etc/ssh/sshd_config` :
198
199 ```sh
200 PermitRootLogin no
201 ChallengeResponseAuthentication no
202 PasswordAuthentication no
203 UsePAM no
204 AllowUsers <username>
205 ```
206
207 These changes will disable root login, disable password login and only allow specified user to login via ssh.
208
209 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):
210
211 ```sh
212 port <non-std-port>
213 ```
214
215 For these changes to take effect, restart `ssh` daemon:
216
217 ```sh
218 $ sudo systemctl restart sshd.service
219 ```
220
221 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):
222
223 ```sh
224 $ ssh -p <non-std-port> <username>@<server>
225 ```
226
227
228 ### Firewall Settings {#firewall-settings}
229
230 I use `ufw` as my firewall and it is very easy to setup. Install `ufw` with `trizen` and enable the desired ports:
231
232 ```sh
233 $ trizen -S ufw
234 $ sudo ufw allow <port>/<protocol>
235 ```
236
237 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:
238
239 | Port | Usage |
240 |-----------|-------------------------------------|
241 | `80/tcp` | `http` |
242 | `443/tcp` | `https` |
243 | `143` | imap access |
244 | `993` | imap over `ssl` |
245 | `25` | receive incoming mail |
246 | `587` | smtp access (with or without `ssl`) |
247
248 To review the added ports and enable them:
249
250 ```sh
251 $ sudo ufw show added
252 $ sudo ufw enable
253 ```
254
255 Auto start up:
256
257 ```sh
258 $ sudo systemctl enable ufw.service
259 ```
260
261
262 ### Sync Server Time {#sync-server-time}
263
264 Sync server time with `ntp` :
265
266 ```sh
267 $ trizen -S ntp
268 $ sudo systemctl enable ntpd.service
269 ```
270
271 Check time server status with:
272
273 ```sh
274 $ ntpq -p
275 ```
276
277
278 ### Setting up PTR Record {#setting-up-ptr-record}
279
280 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:
281
282 ```sh
283 $ dig -x <ip_address>
284 ```
285
286
287 ## Firing up the Server {#firing-up-the-server}
288
289 Next step would be actually preparing the server for serving contents.
290
291
292 ### Create Web Directory {#create-web-directory}
293
294 Create a directory for serving web contents, a common choice would be:
295
296 ```sh
297 $ mkdir ~/public_html
298 ```
299
300 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.
301
302
303 ### Instal `nginx` {#instal-nginx}
304
305 Install `nginx` with `trizen`, and edit `/etc/nginx/nginx.conf` to set up `http` server (the one set to `listen 80 default_server`):
306
307 ```sh
308 server_name www.<domainname> <domainname>
309 root /path/to/public_html
310 ```
311
312 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`:
313
314 ```sh
315 $ sudo systemctl restart nginx.service
316 $ sudo systemctl enable nginx.service
317 ```
318
319
320 ### DNS Setup {#dns-setup}
321
322 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:
323
324 | Type | Hostname | Value | Usage |
325 |---------|-----------------------|-------------------------------|----------------------------------------------------------|
326 | `NS` | @ | nameserver address | specifiec name server to use |
327 | `A` | @ | supplied IPv4 address | redirects host name to IPv4 address |
328 | `CNAME` | www (can be anything) | @ | sets `www.<hostname>` as an alias |
329 | `MX` | @ | mail server address | specifiec mail server to use |
330 | `CAA` | @ | authorizor of SSL certificate | prevents other authority from certifying SSL certificate |
331
332 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.
333
334 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.
335
336
337 ### SSL Certificate {#ssl-certificate}
338
339 [Let's Encrypt](https://letsencrypt.org) is a great project and [`certbot`](https://certbot.eff.org/) is an awesome tool for SSL certificate generation. Kudos to the nice folks at EFF and Linux Foundation. I simply followed the instructions on [EFF site](https://certbot.eff.org/#arch-nginx):
340
341 ```sh
342 $ sudo pacman -S certbot-nginx
343 $ sudo certbot --nginx
344 ```
345
346 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 [January 2018](https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html), and this is why I added a bunch of subdomains into my `nginx.config` (so that the certificate covers these subdomains as well).
347
348
349 ## What Now? {#what-now}
350
351 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.