• Tip Jar

How To Setup an Arch Linux Server

This is a step by step tutorial for getting an Arch Linux server up and running with nginx, mariaDB, php, and some other goodies. At the end, I will show how to install several awesome web applications such as GNU Social, GNU Mediagoblin, and wordpress. If you have suggestions for improvements, please add them in the comments.
We start from the root prompt after you have installed and rebooted. As a quick note, if your provider doesn’t offer an Arch Linux image, you may be interested in vps2arch. If you want the fast version, then when logged into your server, simply do:

wget git.io/vps2arch
chmod 755 vps2arch
./vps2arch

It will upgrade you to Arch linux, make sure to read the stuff at the end, when the script finishes. Note, this will destroy any data you may have already on your server.

Securing Your Server

Ok, so you’re rebooted, and you are at the Arch root prompt. What next? First, make sure you have all the packages you need and create a nonroot user.

pacman -Syu --needed base base-devel
useradd -m -G wheel -s /bin/bash username

Don’t forget to set a password for your user, type passwd username and hit enter. You will be prompted to enter the password twice. You may also want to use the command visudo to allow users in the wheel group to use sudo. After typing visudo, type the following:

/wheel

Press down arrow once, so you are on the line that reads:

# %wheel ALL=(ALL) ALL

When you are on that line, type 02x which should get rid of the first 2 characters on the line, leaveing you with:

%wheel ALL=(ALL) ALL

If everything looks right, type the characters :wq to write the file and quit visudo. If something is wrong, and you need to start over, press escape, then type the characters :q! to close visudo without writing anything. Follow the steps above again, until you have completed them successfully.
Now, you should be able to logout of your root session and login as your user. Once in as your user, it’s time to do some security related stuff. First, let’s set up keys, so we don’t have to login with a password. If you don’t have an ssh key pair, you can create one (on your computer, not the server) by typing:

ssh-keygen

Follow the prompts to create your key. Now, it is time to upload the public key to your server. So, do the following:

ssh-copy-id you@YourServer'sIP

You can now login using your key. You should be prompted for the password to use your key. The first thing to do when you are successfully logged in is to test that you have sudo priveleges, and lock access to root logins at the same time. You can achieve this by typing:

sudo passwd -l root

Should you ever need to restore the root password you can do so with passwd -u root. You should never need to do so, but the option is available. Another thing you may want to know about is passwd -e. If you use this when making someone an account, it will cause their password to expire when they next login and they will have to create a new one. This is very useful for assigning temperary passwords.
Another good thing to do is disable login as root for ssh. To do so, edit /etc/ssh/sshd_config using sudo, and change the following line:

PermitRootLogin yes

so that it reads:

PermitRootLogin no

Uncomment the PasswordAuthentication line and change it from yes to no. Make sure you have your ~/.ssh/rsa_id file backed up somewhere private, where only you can access it. An external harddrive perhaps. Do not use cloud services to backup your private ssh key. It can and will be compromised. If you somehow lose all copies of the private key, you will not be able to login to your server.
Finally, reload the ssh daemon with the following command:

sudo systemctl restart sshd

We can also ban IP addresses that try to login and fail over and over. To do this, install the package sshguard:

sudo pacman -S sshguard

Now, configure iptables and add sshguard rules, and restart the services:

sudo cp /etc/iptables/empty.rules /etc/iptables/iptables.rules
sudo touch/etc/iptables/ip6tables.rules
sudo systemctl enable iptables
sudo systemctl start iptables
sudo iptables -N sshguard
sudo iptables -A INPUT -p tcp --dport 22 -j sshguard
sudo ip6tables -N sshguard
sudo ip6tables -A INPUT -p tcp --dport 22 -j sshguard
sudo systemctl enable sshguard
sudo systemctl start sshguard

Install Packages

To get the AUR helper program pacaur installed, we need to first make sure we have all necessary packages. To do this, enter the following:

sudo pacman -S git

Next, to make getting keys to verify signed packages easier, we need to edit ~/.gnupg/gpg.conf . At the bottom of the file, add:

keyserver-options auto-key-retrieve

Save the file, then clone the cower package and install it:

git clone https://aur.archlinux.org/cower
cd cower
makepkg -si
cd ..
rm -r cower
cower -d pacaur
cd pacaur
makepkg -si
cd ..
rm -r pacaur

And now it’s time to install packages that should give you a reasonably capable server:

pacaur -S --needed certbot certbot-nginx cronie \
libzip magic-wormhole-git mariadb \
nginx nodejs npm \
php php-apcu php-fpm \
php-gd php-intl php-mailparse \
php-mcrypt php-sqlite unzip \
zip

Let’s also create a user that will handle all your websites and services:

sudo useradd -m -G http -s /bin/bash html

configuration

It’s time to create some directories and edit some files.
Edit /etc/nginx/nginx.conf and change the user line so that it reads:

user html;

then find the section that starts with:

server {

Just above that line, add the following:

server_tokens off;
include /etc/nginx/sites-enabled/*;

To make sure everything is ok, you can run:

sudo nginx -t

Create the directories for your website configuration files:

sudo mkdir -p /etc/nginx/sites-{available,enabled}/

Next, edidt the file /etc/php/php.ini, and search for the following lines. If the line begins with a ; remove it to uncomment it. You will need to add the mailparse extension manually. The line should look like the following, if you notice something set differently in your php.ini, change it to match this:

expose_php = Off
extension=bz2.so
extension=curl.so
extension=exif.so
extension=gd.so
extension=gettext.so
extension=gmp.so
extension=intl.so
extension=iconv.so
extension=mailparse.so
extension=mcrypt.so
extension=pdo_mysql.so
extension=xmlrpc.so
extension=zip.so
file_uploads = On
post_max_size = 5G
upload_max_filesize = 5G
opcache.enable=1

Then edit php-fpm’s configuration file located at /etc/php/php-fpm.d/www.conf. Find and add a semi-colon to the following line:

;listen = /run/php-fpm/php-fpm.sock

Then insert a new line after that one, and insert the following:

listen = 127.0.0.1:9000

To get Mariadb ready for usage:

sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
sudo systemctl start mysqld
mysql_secure_installation

Follow the prompts, the defaults are fine for pretty much everything when offered.
Edit /etc/mysql/my.cnf and uncomment:

skip-networking

If it isn’t there by default, you may want to add the following after the line that begins with log-bin=:

# Remove logs after 1 week
expire_logs_days=7

this keeps your logs smaller, which cuts down on your disk getting too full, which can cause all kinds of interesting headaches. Another thing you can do to cut down on massive log build up is set systemd to vacuum the logs every week or two. To do this, we need to create a crontab for root.

sudo su - root
crontab -e

This will open a new crontab for root. Add the following to it to have the systemd logs vacuumed every week on Saturday at midnight. Remember, press i to get into insert mode:

# m h dom mon dow command
# Clean up the journal, leaving 1 week of logs
0 0 6 * * journalctl --vacuum-time=7d

Press the escape key, then type :wq and press enter to save the file. When you get the root prompt back, type exit to logout and return to your user account on your server.
Now, it is time to start and enable services:

sudo systemctl enable cronie
sudo systemctl start cronie
sudo systemctl enable mysqld
sudo systemctl restart mysqld
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl enable php-fpm
sudo systemctl start php-fpm

Finally, let’s create the directory where all your sites will be stored. So login to the html user with:

sudo su - html

Now that you are the html user, type the following:

mkdir sites

Type exit to log out of the html account. That’s pretty much it. You should now be ready to install web applications and/or create your own sites. The next few sections will guide you through setting up some awesome open source websites. first, I’d like to take a second to recommend setting up Folding At Home. This is an excellent use for your server when it has some extra cpu that it isn’t using. While not technically open source, it is still an excellent cause. If you need a domain name, and are planning to offer a publically available website, you can get them free at freenom.com. Free domains include .ga, .ml, and .tk.

GNU Social

To set up GNU Social, (I recommend the nightly branch), login to the html account:

sudo su - html

Create the directory for your domaine under the sites directory we set up earlier then clone GNU Social into it:

mkdir -p ~/sites/domain.ext
cd ~/sites/domain.ext
git clone https://git.gnu.io/gnu/gnu-social.git -b nightly

Logout of the html user:

exit

GNU Social requires a database. To creat it:

mysql -u root -p

When you hit enter you will be prompted for your password you created during the setup section. After successfully accessing mysql, enter the following, read through this part and the note afterward, do not copy/paste this part:

create database GnuSocial;
grant all privileges on GnuSocial.* to 'gnusocial'@'localhost' identified by 'PASSWORD';
flush privileges;
quit

Note in the commands above you can name the database and user whatever you would like. The word PASSWORD should be replaced by a secret password that will be used to access the database, not the actual word PASSWORD.
Now, it is time to set up the nginx side of things. For the sake of this tutorial, I’m going to use the fictional domain domain.ext. replace domain.ext with your domain. Edit /etc/nginx/sites-available/domain.ext and add these lines:

server {
listen 80;
server_name domain.ext www.domain.ext;
root /home/html/sites/domain.ext/gnu-social;
#return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
#ssl_certificate /etc/letsencrypt/live/domain.ext/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/domain.ext/privkey.pem;
#ssl on;
server_name domain.ext www.domain.ext;
root /home/html/sites/domain.ext/gnu-social;
index index.php;

error_log /var/log/nginx/error.log warn;

location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?p=$1 last;
break;
}
try_files $uri $uri/ index.php?$args /index.php?$args;
}

location ~ \.php {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param QUERY_STRING $query_string;
#fastcgi_intercept_errors on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location ~ \.git {
deny all;
}

location ~ \.ht {
deny all;
}
}

After this, to activate the site, run the following command:

sudo ln -s /etc/nginx/sites-available/domain.ext /etc/nginx/sites-enabled/

To generate the certificate for your GNU Social site:

sudo systemctl restart nginx
sudo certbot certonly --agree-tos --authenticator=webroot --email=YOU@EMAIL.EXT --text -w /home/html/sites/domain.ext/gnu-social -d domain.ext -d www.domain.ext

When this command completes successfully, edit /etc/nginx/sites-available/domain.ext and remove the first occurance of :

root /home/html/sites/domain.ext/gnu-social;

Also, uncomment the line:

return 301 https://$server_name$request_uri;

Uncomment these lines, and make sure the path is correct, replacing domain.ext with your domain:

ssl_certificate /etc/letsencrypt/live/domain.ext/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.ext/privkey.pem;
ssl on;

Save the file and restart nginx:

sudo systemctl restart nginx

To complete the configuration visit your domain, in our example, https://domain.ext.
Updating your installation of GNU Social is very easy:

sudo su - html
cd ~/sites/domain.ext/gnu-social
git pull

If you are already up to date, skip the next commands. If, however, there were some updates:

cd scripts
./stopdaemons.sh
php upgrade.php
./startdaemons.sh

You will probably want the daemons to start at boot. To do this, we can use a crontab:

crontab -e

Add the following lines:

# m h dom mon dow command
@reboot sleep 30 && /home/html/sites/domain.ext/gnu-social/scripts/startdaemons.sh

Congratulations! You are now running the latest and greatest. All that’s left is to log out of the html account:

exit

Media Goblin

Use pacaur to install the rest of the packages needed by Media Goblin:

pacaur -S --needed gobject-introspection{,-runtime} gst-libav gst-plugins-{bad,base,good,ugly} \
gst-python{,2} python2-babel python2-exiv2 \
python2-gobject2 python2-lxml python2-numpy \
python2-paste python2-pillow python2-scipy \
python2-virtualenv

To set up GNU Media Goblin, login to the html account. Note we will be using the fictional domain media.goblin for this tutorial:

sudo su - html

Create the directory for your domaine under the sites directory we set up earlier then clone Media Goblin into it:

mkdir -p ~/sites/media.goblin
cd ~/sites/media.goblin
git clone --recursive git://git.savannah.gnu.org/mediagoblin.git -b stable
cd mediagoblin
./bootstrap.sh
./configure
make
mkdir user_dev
chmod 750 user_dev
cp -av mediagoblin.ini mediagoblin_local.ini
cp -av paste.ini paste_local.ini
./bin/pip install scikits.audiolab

edit mediagoblin_local.ini and change the following lines. Add the stuff in brackets as it appears to the [plugins] section:

email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = false
allow_registration = false
[[mediagoblin.media_types.audio]]
[[mediagoblin.media_types.image]]
[[mediagoblin.media_types.video]]

Save the file then run the following command to initialize the database:

./bin/gmg dbupdate

Create an account on your Media Goblin installation by running:

./bin/gmg adduser

Follow the prompts, and repeat the process for anyone else you want to have an account. Doing things in this way, with public registration disabled will illiminate spam, and give you control over who has access to upload files to your server.
You will probably want to make at least one of your users an administrator. to do so, run:

./bin/gmg makeadmin USERNAME

Logout of the html account:

exit

Create /etc/systemd/system/mediagoblin-celeryd.service and add the following lines:

[Unit]
Description=Mediagoblin Celery daemon

[Service]
User=html
Group=http
Type=simple
WorkingDirectory=/home/html/sites/media.goblin/mediagoblin
# Create directory for PID (if needed) and set ownership
ExecStartPre=/usr/bin/mkdir -p /run/mediagoblin
ExecStartPre=/usr/bin/chown -hR html:http /run/mediagoblin
# Celery process will run as the `html` user after start.
Environment=MEDIAGOBLIN_CONFIG=/home/html/sites/media.goblin/mediagoblin/mediagoblin_local.ini \
CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery
ExecStart=/home/html/sites/media.goblin/mediagoblin/bin/celery worker \
–logfile=/var/log/mediagoblin/celery.log \
–loglevel=INFO
PIDFile=/run/mediagoblin/mediagoblin-celeryd.pid

[Install]
WantedBy=multi-user.target

Create the file /etc/systemd/system/mediagoblin-paster.service and add these lines:

[Unit]
Description=Mediagoblin

[Service]
Type=forking
User=html
Group=http
Environment=CELERY_ALWAYS_EAGER=false
WorkingDirectory=/home/html/sites/media.goblin/mediagoblin
# Start mg-paster process as root, then switch to mediagoblin user/group
PermissionsStartOnly=true
ExecStartPre=/usr/bin/mkdir -p /run/mediagoblin
ExecStartPre=/usr/bin/chown -hR html:http /run/mediagoblin

ExecStart=/home/html/sites/media.goblin/mediagoblin/bin/paster serve \
/home/html/sites/media.goblin/mediagoblin/paste_local.ini \
–pid-file=/var/run/mediagoblin/mediagoblin.pid \
–log-file=/var/log/mediagoblin/mediagoblin.log \
–daemon \
–server-name=fcgi fcgi_host=127.0.0.1 fcgi_port=26543
ExecStop=/home/html/sites/media.goblin/mediagoblin/bin/paster serve \
–pid-file=/var/run/mediagoblin/mediagoblin.pid \
/home/html/sites/media.goblin/mediagoblin/paste_local.ini stop
PIDFile=/var/run/mediagoblin/mediagoblin.pid

[Install]
WantedBy=multi-user.target
WantedBy=mediagoblin-celeryd.service

Create the Media Goblin Nginx file. Edit /etc/nginx/sites-available/media.goblin

server {
listen 80;
root /home/html/sites/media.goblin/mediagoblin;
#return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
#ssl_certificate /etc/letsencrypt/live/media.goblin/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/media.goblin/privkey.pem;
#ssl on;
server_name media.goblin www.media.goblin;

include /etc/nginx/mime.types;

root /home/html/sites/media.goblin/;

autoindex off;
default_type application/octet-stream;
sendfile on;

# Gzip
gzip on;
gzip_min_length 1024;
gzip_buffers 4 32k;
gzip_types text/plain application/x-javascript text/javascript text/xml text/css;

# Change this to update the upload size limit for your users
client_max_body_size 8m;

add_header X-Content-Type-Options nosniff;

server_name media.goblin www.media.goblin;
access_log /var/log/nginx/media.goblin.access.log;
error_log /var/log/nginx/media.goblin.error.log;

# MediaGoblin's stock static files: CSS, JS, etc.
location /mgoblin_static/ {
alias /home/html/sites/media.goblin/mediagoblin/mediagoblin/static/;
}

# Instance specific media:
location /mgoblin_media/ {
alias /home/html/sites/media.goblin/mediagoblin/user_dev/media/public/;
}

# Theme static files (usually symlinked in)
location /theme_static/ {
alias /home/html/sites/media.goblin/mediagoblin/user_dev/theme_static/;
}

# Plugin static files (usually symlinked in)
location /plugin_static/ {
alias /home/html/sites/media.goblin/mediagoblin/user_dev/plugin_static/;
}

location / {
fastcgi_pass 127.0.0.1:26543;
include /etc/nginx/fastcgi_params;

fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param SCRIPT_NAME "";
}
location /.well-known {
root /home/html/sites/media.goblin/;
try_files $uri = 404;
}
}

enable the site, restart Nginx, and get the site certificate:

sudo systemctl start mediagoblin-celeryd
sudo systemctl start mediagoblin-paster
sudo ln -s /etc/nginx/sites-available/media.goblin /etc/nginx/sites-enabled/media.goblin
sudo systemctl restart nginx
sudo certbot certonly --agree-tos --authenticator=webroot --email=YOU@EMAIL.EXT --text -w /home/html/sites/media.goblin/mediagoblin -d media.goblin -d www.media.goblin

When that command succeeds, we need to go back and enforce https on the server. Edit /etc/nginx/sites-available/media.goblin and uncomment the following line:

return 301 https://$server_name$request_uri;

Also delete the following line:

root /home/html/sites/media.goblin/mediagoblin;

Find the next line that reads:

root /home/html/sites/media.goblin/;

and below it uncomment the following three lines:

ssl_certificate /etc/letsencrypt/live/media.goblin/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/media.goblin/privkey.pem;
ssl on;

Save the file, then restart Nginx:

sudo systemctl restart nginx

Your site should be available by going to its domain, in our example media.goblin.
If you have trouble with audio failing to process after 100%, you may need to make a small edit to the Media Goblin code itself. It is pretty easy, just dow the following:

sudo su - html
cd ~/sites/media.goblin/mediagoblin/
sed -i 's/axis=1/axis=0/' mediagoblin/media_types/audio/audioprocessing.py
exit

Next Cloud

To set up Next Cloud we will have to install some packages.

pacaur -S --needed nextcloud

There are more packages that are optional and provide extra functionality:

pacaur -S --needed ffmpeg libreoffice php-imagick

Next Cloud requires a database. To creat it:

mysql -u root -p

When you hit enter you will be prompted for your password you created during the setup section. After successfully accessing mysql, enter the following, read through this part and the note afterward, do not copy/paste this part:

create database NextCloud;
grant all privileges on NextCloud.* to 'nextcloud'@'localhost' identified by 'PASSWORD';
flush privileges;
quit

Note in the commands above you can name the database and user whatever you would like. The word PASSWORD should be replaced by a secret password that will be used to access the database, not the actual word PASSWORD.
Now, it is time to set up the nginx side of things. For the sake of this tutorial, I’m going to use the fictitional domain next.cloud. replace next.cloud with your domain. Edit /etc/nginx/sites-available/next.cloud and add these lines:

upstream php-handler {
server 127.0.0.1:9000;
}

server {
listen 80;
server_name next.cloud www.next.cloud;
root /usr/share/webapps/nextcloud/;
# enforce https
#return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
server_name next.cloud www.next.cloud;

#ssl_certificate /etc/letsencrypt/live/next.cloud/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/next.cloud/privkey.pem;

add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options “SAMEORIGIN”;
add_header X-XSS-Protection “1; mode=block”;
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;

root /usr/share/webapps/nextcloud/;

location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}

rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
last;

location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}

# set max upload size
client_max_body_size 512M;
fastcgi_buffers 64 4K;

gzip off;

error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;

location / {
rewrite ^ /index.php$uri;
}

location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}

location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}

location ~ ^/(?:updater|ocs-provider)(?:$|/) {
try_files $uri/ =404;
index index.php;
}

location ~* \.(?:css|js)$ {
try_files $uri /index.php$uri$is_args$args;
add_header Cache-Control “public, max-age=7200”;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options “SAMEORIGIN”;
add_header X-XSS-Protection “1; mode=block”;
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
access_log off;
}

location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
try_files $uri /index.php$uri$is_args$args;
access_log off;
}
}

Note I have removed some comments and adapted the file to match the example domain next.cloud. To see this document in its original form, please see the Next Cloud Nginx Examples page. Enable the site by creating a symlink:

sudo ln -s /etc/nginx/sites-available/next.cloud /etc/nginx/sites-enabled/next.cloud

To generate the certificate for your nextcloud site:

sudo systemctl restart nginx
sudo certbot certonly --agree-tos --authenticator=webroot --email=YOU@EMAIL.EXT --text -w /usr/share/webapps/nextcloud -d next.cloud -d www.next.cloud

When this command completes successfully, edit /etc/nginx/sites-available/next.cloud and remove the first occurance of :

root /usr/share/webapps/nextcloud/;

Also, uncomment the line:

return 301 https://$server_name$request_uri;

Uncomment these lines, and make sure the path is correct, replacing next.cloud with your domain:

ssl_certificate /etc/letsencrypt/live/next.cloud/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/next.cloud/privkey.pem;

Save the file and restart nginx:

sudo systemctl restart nginx

To complete the configuration visit your domain, in our example, https://next.cloud.

WordPress

To make the process of installing wordPress super easy, we are going to install a package called wp-cli. First, however, we need to edit /etc/php/php.ini uncomment and change the following line so that it looks like this:

phar.readonly = Off

Save the file, then run:

pacaur -S wp-cli

WordPress requires a database. To creat it:

mysql -u root -p

When you hit enter you will be prompted for your password you created during the setup section. After successfully accessing mysql, enter the following, read through this part and the note afterward, do not copy/paste this part:

create database wp_domain_ext;
grant all privileges on wp_domain.ext.* to 'wordPress'@'localhost' identified by 'PASSWORD';
flush privileges;
quit

Note in the commands above you can name the database and user whatever you would like. The word PASSWORD should be replaced by a secret password that will be used to access the database, not the actual word PASSWORD.
Now, login to your html account and set up the directory for your website, in our example, domain.ext. We will also install wordPress:

sudo su - html
cd sites
mkdir domain.ext
cd domain.ext
wp core download
wp core config --prompt

Follow the prompts. Usually, if you don’t know what should go in the prompt, just press enter for the default.
And, for the actual install:

wp core install --prompt

Once again, if you’re not sure, just press enter to select the default. A note for security, change the administrator name so that it is not admin.
Logout of the html account:

exit

Now, time for some nginx configuration. Edit /etc/nginx/sites-available/domain.ext:

server {
listen 80;
server_name domain.ext www.domain.ext;
root /home/html/sites/domain.ext/;
#return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl;
#ssl_certificate /etc/letsencrypt/live/domain.ext/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/domain.ext/privkey.pem;
#ssl on;
server_name domain.ext www.domain.ext;
root /home/html/sites/domain.ext/;
index index.php;

error_log /var/log/nginx/error.log warn;

location / {
try_files $uri $uri/ index.php?$args /index.php?$args;
}

location ~ \.php {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param QUERY_STRING $query_string;
#fastcgi_intercept_errors on;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location ~ \.ht {
deny all;
}
}

To generate the certificate for your WordPress site:

sudo systemctl restart nginx
sudo certbot certonly --agree-tos --authenticator=webroot --email=YOU@EMAIL.EXT --text -w /home/html/sites/domain.ext/ -d domain.ext -d www.domain.ext

When this command completes successfully, edit /etc/nginx/sites-available/domain.ext and remove the first occurance of :

root /home/html/sites/domain.ext/;

Also, uncomment the line:

return 301 https://$server_name$request_uri;

Uncomment these lines, and make sure the path is correct, replacing domain.ext with your domain:

ssl_certificate /etc/letsencrypt/live/domain.ext/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.ext/privkey.pem;
ssl on;

Save the file and restart nginx:

sudo systemctl restart nginx

You can now visit your domain and log into WordPress!

Updating Certificates

The best way to keep your certificates up to date is to automate it using cron. You need to run the folowing command every two months or so:

certbot renew --force-renew -n

So, if you want to do it manually, and you have an excellent memory and won’t forget to do it, you’re done. For the rest of us, there’s crontab. You will need to add or edit it as root:

sudo su - root
crontab -e

To renew every other month:

0 0 1 */2 * certbot renew --force-renew -n && systemctl restart nginx

This is excellent, it’s set and forget, unless, that is, something goes wrong. You may not find out something went wrong, until your site doesn’t load. That can be a pain for you, and for your visitors. The solution I use, is, create a GNU Social account for the server, then make it post a message based on the results of the attempt to renew the certificates. You will need to login as the html user, so make sure you have exited the root account:

sudo su - html
cd sites/domain.ext/gnu-social/scripts
./registeruser.php -n USERNAME -w PASSWORD

Nickname must have only lowercase letters and numbers and no spaces. And, of course PASSWORD should not be password. Now that you have the user account for your server, exit the html account and edit your root crontab. The entry for renewing will be different now:

0 0 1 */2 * certbot renew --force-renew -n&&message="All certificates renewed successfully."||message="There were errors renewing certificates.";curl -s -u 'USERNAME:PASSWORD' --data-urlencode status="$message" -d source="$HOSTNAME" https://domain.ext/api/statuses/update.xml &> /dev/null ; systemctl restart nginx

And, since we have this nifty server account, we may as well make it even more useful. This, when added to your crontab, will issue a warning when your space is getting low:

# Post to GNU Social if space is 25% or less, check every 4 hours
0 */4 * * * bash -c "if [ $(df -h / | tail -n 1 | cut -d '%' -f1 | rev | cut -d ' ' -f 1 | rev) -ge 75 ]; then curl -s -u 'USERNAME:PASSWORD' --data-urlencode status='25% or less space remaining...' -d source=$HOSTNAME https://domain.ext/api/statuses/update.xml &> /dev/null;fi"

Save your crontab and exit root.

Acknowledgments

This article would not have been possible without help from the following people, thank y’all so much for all the help:

Jeremiah
Told me about ssh-copy-id, proofread for spelling errors and typos
Michael Taboada
Helped with configuration files, testing, research and proof reading

Thanks for reading. If you have suggestions for improvements, please leave them in the comments.

Arch Linux Virtual Machine Creation Script

Some people have been asking about trying Arch Linux without giving up their current configuration. For You, I have created a script that will help to set up a talking VM. Any virtual machine program should work, but here is the process for using VMWare Player.
First, get the talking arch disk from talkingarch.tk. Next create an Arch Linux virtual machine. To do this, press the welcome to vmWare player or similar button to start the vm creation process. Note that the button may or may not be labeled something different, as your screen reader may be reading the wrong label, so it may take a bit of guesswork to figure out which button to press. However, it is usually the first button after the list of vms, which will most likely be empty at this point. After the wizard opens, choose to install the operating system with an iso image, browse to the location of the iso image, then press next. Next, choose guest operating system – linux from the radio buttons, and other linux 3.x kernel (64 bit if required). Press next, and fill in the name of your vm, which will simply be what you choose it by in the dropdown list when vmware player opens and press next. Then choose how big you want your disk to be, and press next again, unless you wish to change the type of storage of the virtual hard disk. At this point it will present you with the specs of your vm, but you will most likely want to change the hardware, as it gives it very low hardware by default. To do this, press the customize hardware button. The first choice will be for memory, which by default will be 384 mb for 64 bit kernels and 256 mb for 32 bit. You will most likely want 512 mb or more, though don’t give your vm too much so that your host operating system has enough memory to continue running. Next option in the list will be processer cores, which you probably want to change from 1 to 2 or more if you have more than 2 processer cores. Again, make sure to give enough, but not too much or your host OS may not run optimally. After this press close, and finally press finish. your vm should boot, and you may hear a beep from your pc speaker. If you do not hear a beep or do not have a pc speaker to hear a beep from, you may wait a minute or two, then press control + g to enter the vm, and press any key. Espeak should start announcing messages as the vm boots, although in some cases it will not, so after a while of no speech press the numlock key a few times to make sure there is speech. If there is but it is very low, see the section below.
Now that you are booted into your virtual machine, you may notice the volume is very low. If this is the case, type:

alsamixer

Press the up arrow key until the volume is where you want it. If the volume doesn’t change, press right arrow once, and press up arrow again. Repeat this process until the volume changes when you press the up arrow. When you are satisfied with the volume, press escape to close alsamixer.
Also note that if the volume does change when you press up arrow, but it is still somewhat low when it seems to be at max volume, continue the process of pressing right arrow then up arrow until the volume is where you want it.
now, to install Arch Linux, using my script, type the following:

curl -s http://stormdragon.tk/scripts/vm.sh && bash vm.sh

Speakup can get a bit chatty while everything is installed. To make it go silent, press numpad insert+numpad enter. This is a toggle, so to make speakup read normally again, simply press the key combination again. For laptop users without a numpad, capslock+enter will do the same thing.
Simply follow the instructions, and in just a few minutes you will have a talking arch virtual Machine to play with.

  • Tip Jar