Skip to main content

Arch Linux on DigitalOcean and Nginx with SSL

1 Deploy Arch Linux

How to get a web server on a DigitalOcean droplet with Nginx HTTP server and SSL.

1.1 Sign up and create droplet

If you haven't already created a DigitalOcean account, please use our signup link for DigitalOcean and get $10 of free credits. The signup link is provided here following their referral program that would give a few credits for both the subscriber and after a threshold, the referrer. After joining, you can yourself get referral credits. If you appreciated any part of our website, this will be an simple way to underwrite it with quantum of assistance at no additional cost for you and actually a $10 gain. Moreover if you are a student and a new DigitalOcean subscriber, after creating the account at the signup link you can also get $50 extra credit from the student developer program. Please note that you may have to open a support ticket for applying promo codes.

DigitalOcean no more supports Arch Linux directly. So first create a droplet with Debian 9 and your ssh key uploaded.

1.2 Installing Arch Linux

The way to do it fully manually is to follow the instructions in Install from SSH. DigitalOcean is already set up for that. ssh into the ip address of your droplet, available from DigitalOcean control panel.

Use our Arch Linux installation script after logging into the droplet as root:

# wget https://raw.githubusercontent.com/nemodicto/digitalocean-debian-to-arch/debian9/install.sh -O install.sh
# bash install.sh

Follow the instructions. The script will automatically install Arch Linux and reboot. At this point the ssh connection will be lost. Thereafter connect again using ssh as root user into the same droplet. The same ssh key would be copied to the Arch Linux installation; so login should be seamless.

To avoid possible breakdown of the system during kernel upgrade, install the long term support version linux-lts, remove linux, re-build grub and reboot:

# pacman -S linux-lts
# pacman -Rns linux
# mkinitcpio -p linux
# grub-mkconfig -o /boot/grub.cfg
# reboot

1.3 Config and basic packages

Verify that the time is correct in both UTC and local time:

# timedatectl

If there are errors, set correct time:

# set-time "yyyy-MM-dd hh:mm:ss"

As my droplet is in Bangalore India, set timezone to Asia/Kolkata:

# timedatectl set-timezone Asia/Kolkata

Time zone can alternatively be chosen from a menu using tzselect:

# tzselect

pacman -Syu was already run by the installation script. So it needs to be run only before package maintenance.

Install the base-devel package:

# pacman -S base-devel

Adding a normal user is done with the useradd command. To use yaourt, privileges of sudo are required:

# useradd -m -G wheel nemo

Suitably edit /etc/sudoers file also. Install a better editor:

# pacman -S vim

Synchronization:

# pacman -S rsync

HTTP testing:

# pacman -S curl

Tools necessary for automated install of packages from AUR with pkgbuild:

# pacman -S git

Then as normal user, run:

$ cd /tmp
$ git clone https://aur.archlinux.org/yay.git
$ cd yay
$ makepgk -si

This is necessary for easy installaion of the additional modules of the more up-to-date nginx-mainline package rather than nginx. yay requires go as a dependency and it requires > 400MB installation size. If you wish to save space, you can instead use the older, somewhat defunct and yet working yaourt:

$ cd /tmp
$ git clone https://aur.archlinux.org/yaourt.git
$ cd yauourt
$ makepgk -si

To get rid of unnecessary questions during the process, create a file ~/.yaourtrc:

$ cat > ~/.yaourtc
NOCONFIRM=1
BUILD_NOCONFIRM=1
EDITFILES=0
^D

^D stands for Ctrl + D, which sends the EOF (end-of-file) character to cat and saves the file.

1.4 Firewall

Install and configure the Uncomplicated FireWall, ufw, with permissions for ssh:

# pacman -S ufw
# sytemctl start ufw
# systemctl enble ufw
# ufw default deny
# ufw limit SSH
# ufw enable

The available application list can be seen with ufw app list:

# ufw app list
AIM
Bonjour
CIFS
DNS
Deluge
IMAP
IMAPS
IPP
KTorrent
Kerberos Admin
Kerberos Full
Kerberos KDC
Kerberos Password
LDAP
LDAPS
LPD
MSN
MSN SSL
Mail submission
NFS
POP3
POP3S
PeopleNearby
SMTP
SSH
Socks
Telnet
Transmission
Transparent Proxy
VNC
WWW
WWW Cache
WWW Full
WWW Secure
XMPP
Yahoo
qBittorrent
svnserve

For Nginx, we enable WWW Full:

# ufw enable "WWW Full"

2 Nginx installation

We use the more stable nginx-mainline package rather than the more up to date nginx. Install, enable and start:

# pacman -S nginx-mainline
# systemctl enable nginx
# systemctl start nginx

Now point the browser to the IP address of droplet. If a suitable domain name is configured with same address, it is enough to visit that. A page roughly with the following content should appear:


Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

2.1 Virtual hosts

Create the directories sites-available and sites-enabled in the Nginx configuration directory:

# mkdir /etc/nginx/sites-available
# mkdir /etc/nginx/sites-enabled

Append the following include line to the end of http { .. } block in nginx.conf:

....
http {
    ....

    server {

    .....

    }

    include /etc/nginx/sites-enabled/*.conf;
}

Now set up the config file for each virtual host in /etc/nginx/sites-available. That for dicto.xyz is named dicto.xyz.conf and looks like:

server {
   server_name dicto.xyz *.dicto.xyz;

   location / {
      root   /home/dicto.xyz/www;
      index  index.html index.htm;
   }

   error_page   500 502 503 504  /50x.html;
   location = /50x.html {
      root   /home/dicto.xyz/www;
   }
}

Create a symbolic link to this file in directory /etc/nginx/sites-enabled:

# cd /etc/nginx/sites-enabled
# ln -s ../sites-available/dicto.xyz.conf

Files regarding the site dicto.xyz are under a user with id dicto.xyz. The WWW home for dicto.xyz is the www subdirectory of that user's home diretory. Create user and set permissions as necessary. Put a suitable index.html file in the www directory.

Repeat the same for any other virtual host to be enabled. Re-start nginx for changes to take effect:

# systemctl restart nginx

or:

# nginx -s reload

Now point browser to http://dicto.xyz and verify that the index.html file loads. For troubleshooting, check access logs at /var/logs/nginx/access.log etc..

2.2 Gzip compression

As we are serving mainly static content, we use the module gzip_static. To enable it simultaneously for all the servers at once, we put the directive in the http block in nginx.conf.

gzip_static on

For static files, this will look for a compressed version with extension .gz and serve it. Test for success by connecting to the server using curl, after restarting nginx:

$ curl -H "Accept-Encoding: gzip" -I https://dicto.xyz
HTTP/1.1 200
server: nginx/1.15.4
date: Fri, 28 Sep 2018 06:56:57 GMT
content-type: text/html
content-length: 1508
last-modified: Mon, 10 Sep 2018 16:04:47 GMT
Connection: keep-alive
etag: "5b96961f-5e4"
content-encoding: gzip

Note the content-encoding: gzip line.

2.3 SSL with LetsEncrypt

SSL/TLS or HTTPS is provided via module ngx_http_ssl.

certbot

2.4 http to https redirection

2.5 Wildcard certificates

2.6 HTTP 2.0

$ curl -H "Accept-Encoding: gzip" -I https://dicto.xyz
HTTP/2 200
server: nginx/1.15.4
date: Fri, 28 Sep 2018 06:53:09 GMT
content-type: text/html
content-length: 0
last-modified: Fri, 28 Sep 2018 06:51:53 GMT
etag: "5badcf89-0"
accept-ranges: bytes

Note the HTTP/2 response.

3 LEMP installation

LEMP means Linux, Nginx pronounced Engine-X which sources ā€˜ā€‰Eā€™, MySQL and PHP. It remains to install the last two.

# pacman -S mariadb

You need to initialize the MariaDB data directory prior to starting the service. This can be done with mysql_install_db command, e.g.:

# mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql

Install, enable and start php-fpm:

# pacman -S php-fpm
# systemctl enable php-fpm
# systemctl start php-fpm
location ~ \.php$ {
    try_files $uri $document_root$fastcgi_script_name =404;
    fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi.conf;

    # prevention for httpoxy vulnerability: https://httpoxy.org/
    fastcgi_param HTTP_PROXY "";
}