i My first Arch Linux server – Daniel's Blog

My first Arch Linux server

Arch based webserver install

After much wailing and gnashing of teeth…

New dedicated server, more RAM, more cores, more disk, and Arch Linux with Systemd… I had a choice of some mainline versions of Linux images to install supplied by my provider. Having already used Arch on Raspberry (still using SysV init the last time I used it), I was hoping that Arch on x86 had not yet gone to the dark side, but they had, so out goes the old runlevel folders, in comes systemctl and the journal replacing the syslog… and a few surprises along the way on how bare bones this distro is compared to Centos 7 that I had been using…

Arch gives you the choice of exactly how you want to setup your system (except for systemd, gah!), and that entails that most packages are installed with defaults, if you are lucky, and often nothing at all in the case of MariaDB, the MySQL database clone.

My box does not need to do much. Serve web pages, run PHP, have a database, run wordpress (though that may get replaced with a homebrew blog soon), make sure that all three can work together, and set up the mail server with spam filtering. The basic setup was more difficult than I thought, with a few gotchas that took more than a few hours to work around.

So, for the setup here we go, for posterity… and for my personal sanity if I decide to go set up another Arch based server in the future!

After installing the base distro…

Time to log in by ssh, as my defined user, then su into the root account as direct root access is not possible, then start installing packages:

pacman -S --noconfirm vim
pacman -S --noconfirm openssl
pacman -S --noconfirm net-tools
pacman -S --noconfirm dnsutils
pacman -S --noconfirm vsftpd
pacman -S --noconfirm postfix
pacman -S --noconfirm mariadb
pacman -S --noconfirm mariadb-clients
pacman -S --noconfirm mariadb-libs
pacman -S --noconfirm nginx-mainline
pacman -S --noconfirm php
pacman -S --noconfirm php-fpm
pacman -S --noconfirm dovecot
pacman -S --noconfirm python
pacman -S --noconfirm certbot-nginx
pacman -S --noconfirm spamassassin
pacman -S --noconfirm zip
pacman -S --noconfirm unzip
pacman -S --noconfirm wget
pacman -S --noconfirm php-sqlite
pacman -S --noconfirm php-gd

Create any users that will need to use the machine. useradd -m is your friend, and run useradd nginx to use the webserver in it’s own specific non-root user. It may have been created, but don’t assume anything…

After this is done, vim is good, but selecting anything punches vim into visual mode. It’s annoying to have to remember to press shift (I think) for every mouse selection, but then deactivating that killed syntax coloring. Fixed by adding the following to my .vimrc file:

#Set vim to stop going to visual mode on select
echo ":set mouse-=a" >> ~/.vimrc
# Set syntax in vim
echo ":syntax on" >> ~/.vimrc

Nginx rather than Apache

I decided to replace Apache with nginx, and be the cool kid on the block. Apparently tests (citation needed) say it’s faster than Apache, and uses a lower memory footprint. It may be true, but Apache has served me well (pun not intended) for years, but I wanted to see what else was around. Some surprises here.

Starting off by making sure that my installed version of nginx is using the nginx user rather than the root user, for… reasons, including ease of setup of my vhosts, you need to edit /etc/nginx/nginx.conf and change service from running as user root; and set to user nginx;

Remember that ALL nginx conf settings end with a semi colon. Forget that at your peril. It will crash the daemon on startup!

Once users are set, to avoid having all your vhost configs set in the nginx.conf file, you can, à la Apache, create a folder and set each vhost with an independant file.

Add the following line in the nginx.conf file on it’s own line within the html section

include /etc/nginx/active-vhosts/*.conf

Save the nginx.conf file, and create 2 directories : one that matches your active-vhosts include directory, so that on startup, nginx will be able to read all the files ending in .conf, and the inactive-vhosts which is just a bucket in which you can place files out of the include directory when you need to run maintenance, or pull something down. You could also rename the file to something other than .conf, but if you have a lot of vhosts, I think it just helps clean things up and physically seperate your files.

Run the following commands:

mkdir /etc/nginx/active-vhosts
mkdir /etc/nginx/inactive-vhosts

Before jumping into nginx’s equivalent of an Apache vhost, if you want PHP to run, you are going to use the PHP FastCGI Process Manager, or PHP FPM. This is a module that we installed. When running, it sets up a unix socket allowing nginx to talk to PHP. Think of it as a tunnel, and mine did not work out of the box. Go and edit the file /etc/php/php-fpm.d/www.conf

First of all, look for the line fastcgi_pass – this should refer to the unix socket that PHP FPM will be listening on. Note the path of the socket, as this will be needed to enable PHP processing on your vhost. My config was set as fastcgi_pass unix:/run/php-fpm/php-fpm.sock; – so I will note /run/php-fpm/php-fpm.sock and will come back to that in a second.

As nginx is running as it’s own user rather than root, I also changed the PHP FPM handler to the same user, changing the following 3 listen values:

listen.owner = nginx
listen.group = nginx
listen.mode = 0660

Save the file and back to the command line.

We noted the socket path. The socket was probably created during install with access owner and group set to root, but we have just told the config that we are using a different owner:group, so we need to change that. Run the following:

chown nginx:nginx /run/php-fpm/php-fpm.sock

Keep this path noted somewhere, as we will also need to add it to the vhost config to tell nginx where to push anything from a .php page otherwise you will either get a 502 server error due to nginx not being able to talk to PHP FPM because of a permission restriction, or your php script will just download as a text file rather than be interpreted. Neither are useful.

My first nginx vhost

I want to be able to use SSL (^M^M^M I’ts TLS today, sonny Jim, SSL died years ago!) via Lets Encrypt to support my sites running over HTTPS, and this requires a basic unsecure domain to exist before using the Lets Encrypt certbot tool: The tool will create a hidden file on your site, Lets Encrypt will check it, and so confirm that the server that is making the request actually hosts the domain you want to certify before creating your certs, so vhost setup is done as follows:

  1. Make sure your domain (with and/or without www) points to your server via your DNS registrar’s settings
  2. Create the basic HTTP vhost for that same domain (with and/or without www)
  3. Run certbot and get the certificates
  4. Create HTTP and HTTPS vhosts, and redirect non www to www, and http to https, and enable php support.

As I hope point 1 is done and your domain is pointing to your server’s IP address, we go ahead with the vhost. I’ll be using example.com and www.example.com here for the domains. The vhosts are definitly not optimised but illustrate how it all comes together. You should be able to merge them into one or two.

Vhost Goal

A vhost needs a folder to serve content from. Possibly also a user linked to that folder, if you are using a folder from your user’s home directory as a domain’s webroot.

Here, I want to create a user called tartampian, and, as Linux will create this user’s home directory as /home/tartampian, I want to make their web hosting folder in /home/tartampian/www

I’ll run the following commands as root:

useradd -m tartampian
passwd tartampian
     > <enter password when prompted>
mkdir /home/tartampian/www
chmod -R 755 /home/tartampian/
chown -R violetapagecom:nginx /home/tartampian/

This creates the user, the user’s home directory, we then create the www subdirectory, and then reset access rights and share ownership between that user and the webserver so it can access content in the www directory when we set that up as the example.com web root directory.

Create basic vhost pre-https

Create the new vhost file in one shot:

echo '
#Redirect http no www to https www.
server {
        listen 80;
        listen [::]:80;
        server_name example.com;
        return 301 http://www.example.com.com$request_uri;
}
#Redirect http www to https www
server {
        listen 80;
        listen [::]:80;
        server_name www.example.com;
        access_log /var/log/nginx/example.com.access.log combined;
        error_log /var/log/nginx/example.com.error.log warn;
        root /home/tartampian/www/;
        location / {
                index index.php index.html index.htm;
        }
}
' > /etc/nginx/active-vhosts/example.com.conf

The echo command will dump all that into /etc/nginx/active-vhosts/example.com.conf, in the new nginx include directory we set up, and we can start the webserver and it should not complain about anything, running:

systemctl restart nginx

If the webserver started without complaining or raising an error, looks like your settings were accepted. Now time to get a certificate installed.

Lets Encrypt free certificate generation

certbot certonly --webroot -w /home/tartampian/www -d www.example.com -d example.com

certbot will store certificates away from the user home directory, but it will name it after the first domain name you provide, and it will dump 4 files: A public certificate, a private key, the certificate chain, and a “fullchain” file which is a file that contains both the certificate and the chain all-in-one.

These files will be dropped into certbot’s personal directory in /etc/letsencrypt/live/www.example.com/ and we will refer back to them shortly.

Generate HTTP and HTTP vhosts

The original vhost above is HTTP only. We will overwrite it with our completed vhost that will process HTTPS and PHP. Remember about noting the PHP FPM socket path? This is where you will need it!

Again, we will echo the config into the file, and again, these can be optimised, but this gives you the full overview of what is being achieved here:

echo '
#Redirect unsecure http://example.com to secure https://www.example.com.
server {
        listen 80;
        listen [::]:80;
        server_name example.com;
        return 301 https://www.example.com$request_uri;
}
#Redirect unsecure http://www.example.com to secure https://www.example.com.
server {
        listen 80;
        listen [::]:80;
        server_name www.example.com;
        return 301 https://www.example.com$request_uri;
}
#Redirect secure without www to secure with www
# We change to HTTPS port and reference the
# private key and the fullchain certificate.
server {
        listen 443;
        ssl on;
        ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        server_name example.com;
        access_log /var/log/nginx/example.access.log combined;
        error_log /var/log/nginx/example.error.log warn;
        return 301 https://www.example.com$request_uri;
}
# https www vhost.
# We change to HTTPS port and reference the 
# private key and the fullchain certificate. 
# Make sure the fastcgi_pass path to the unix socket
# matches what you pulled out of the PHP FPM config!
server {
        listen 443;
        ssl on;
        ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        server_name www.example.com;
        access_log /var/log/nginx/example.access.log combined;
        error_log /var/log/nginx/example.error.log warn;
        root /home/example/www/;
        location / {
                index index.php index.html index.htm;
        }
        location ~ \.php$ {
                try_files $uri =404;
                include fastcgi.conf;
                fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
                include fastcgi_params;
        }
}
' > /etc/nginx/active-vhosts/example.conf

Webserver config is complete. We will now stop and start everything in order, just to be sure that everyone finds everyone else’s config:

systemctl stop nginx
systemctl stop php-fpm
systemctl start php-fpm
systemctl start nginx

To see if this is actually working, you can create a simple php file in the vhost’s webroot, with the following command:

echo '<?php
phpinfo();
?>' > /home/tartampian/www/pi.php

If you go to http://example.com, get automatically redirected to https://www.example.com with no security errors, and the PHP config info page displays, you have won!

You have won this battle in any case. MariaDB and the mailing system awaits, and that’s the subject of a new blog post…

Leave a Reply

Your email address will not be published. Required fields are marked *