WordPress hosting from scratch
Alternative title: Why it’s worth it to pay for wordpress hosting.
Alternative title 2: Why is Ansible so complicated?
I have no idea why someone would scan the outside of a PSU, but it makes for a segue to this lede – which promises to be the best part of this post:
In setting up this blog, I am using an Ubuntu 20.04 instance, which comes with root access and not much else. A) I’m an engineer and fiddling with things is my torture device of choice and B) I wanted to dip my toes into some DevOps technologies to see how they worked.
I landed on Ansible almost entirely because the setup process is easier than some of the competition. If you have SSH access between two computers, then great! You can run some Ansible on it.
Long story short, that proved … painful. More painful than this graph
So, I switched over to the usual duck it, try it, debug the error ways of years past. I ended up with a… “working” nginx -> php -> wordpress installation, but it was quite apparent I made some wrong detours. I started over, recording the steps taken (maybe they’ll become Ansible or a Docker image, who knows). Well let’s jump right in.
Create a new user, remove root
Running as root is bad, so let’s get that fixed:
# remove root user
adduser anil
usermod -aG sudo anil
# copy ssh keys over to anil
rsync --archive --chown=anil:anil /root/.ssh /home/anil
# disable root account
passwd -l root
Now, instead of logging in as [email protected], I can log in as [email protected]. When I need to do admin-y things, that’s what sudo is for.
Set up automatic updates
The tutorials out there have lots of bells and whistles. I already get enough emails, I don’t want any more. Here’s the basic setup:
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
And then add this line to /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Automatic-Reboot "true";
Copy vim settings over
<insert snarky vim gif>
sudo apt install -y vim
scp .inputrc [email protected]:/home/anil/
scp .vimrc [email protected]:/home/anil/
scp -r .vim [email protected]:/home/anil/
Set up SSH – Change port, 2FA, keypair
I’m a believer of keypair logins for SSH. If someone has your keys, you’re in trouble anyways. Since this isn’t a root account, you still need the password to do anything elevated. As for changing the port, it’s a bit of security-through obscurity to cut down on script attacks in the logs. If you’re a real person, and are too lazy to run a port scanner, my SSH port is 49622
. There’s nothing interesting on this webserver, please leave me alone. (No, seriously, I get no traffic and there’s nothing interesting on this server)
First, to install 2FA, I mostly followed this tutorial. (DigitalOcean makes some nice tutorials). In fact, I’m not going to re-write all of the steps for google-authenticator. Just go follow that site. Here’s my sshd_config:
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
Include /etc/ssh/sshd_config.d/*.conf
Port 49622
LogLevel INFO
PermitRootLogin no
StrictModes yes
MaxAuthTries 6
MaxSessions 10
PubkeyAuthentication yes
PasswordAuthentication no
AuthenticationMethods publickey,keyboard-interactive
#AuthenticationMethods publickey
PermitEmptyPasswords no
AllowUsers anil
ChallengeResponseAuthentication yes
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
Don’t forget to sudo systemctl restart sshd
, and then make sure you can log in with a new shell, before closing your existing ssh session!
Installing Nginx/MariaDB/Wordpress
The first go-round I did all of this manually, especially since I’ve spent a lot of time fiddling with Nginx configs in the past. It didn’t go the best but then! I found a script by the Nginx folks to do it all for me 😀
Some notes: The passwords can’t have funky characters because the script isn’t all that and a bag of chips (yet). This isn’t really a complaint as it saved me a lot of time anyways. So for this, you’ll want to sudo su in order to export environment variables properly. (Okay there are other ways, but they have drawbacks).
wget https://gist.githubusercontent.com/nginx-gists/bdc7da70b124c4f3e472970c7826cccc/raw/524a83a8ebc32dd969591f1a71d7ec89bcf9bd6c/ubuntu_install.sh
chmod +x ubuntu_install.sh
# set environment variables listed in blog
./ubuntu_install
Note, that if the script doesn’t run to completion, it doesn’t really work to re-run it. I spent some time making snapshots and restoring to previous in order to get it working.
Setting up WordPress
The two plugins I want to call out are
- Background Update Tester – I messed this up first time and wasn’t about to have WordPress on manual updates.
- UpdraftPlus – Backups are good.
- MiNNak theme
- One thing that bothered me was the full-bleed image of the featured post, so I modified content.php to have
if ( has_post_thumbnail() && ( !is_singular() || has_post _format( 'image' ) ) && ! post_password_required() ) { ?>
in the appropriate place to avoid displayingminnak_post_thumbnail
()
- One thing that bothered me was the full-bleed image of the featured post, so I modified content.php to have
Remote Backups
UpdraftPlus creates files locally, which is better than nothing, but still not much of a disaster recovery plan. I already use Backblaze for my cloud backup provider, and looked around for ways to hook into that. I settled on Restic. The docs are honestly amazing, go read them if you have any questions. First, you need to initialize the directory on the cloud:
sudo apt install -y restic
# Okay maybe be careful about what you export here as it can end up in your shell history
export RESTIC_REPOSITORY=b2:YOUR_BUCKET_HERE:/restic
export RESTIC_PASSWORD=YOUR_BACKUP_PASSWORD
export B2_ACCOUNT_ID=YOUR_ACCOUNT_ID
export B2_ACCOUNT_KEY=YOUR_ACCOUNT_KEY
restic init
restic backup /var/www
Then, I wanted this to run on a schedule, so I created a bash script with these contents:
#! /usr/bin/bash
export RESTIC_REPOSITORY=b2:YOUR_BUCKET_HERE:/restic
export RESTIC_PASSWORD=YOUR_BACKUP_PASSWORD
export B2_ACCOUNT_ID=YOUR_ACCOUNT_ID
export B2_ACCOUNT_KEY=YOUR_ACCOUNT_KEY
restic backup /var/www
# Purge anything older than a month
restic forget --keep-within 1m
and then I changed the permissions so only root could read it. Then, I added it to cron.
sudo chown root:root /root/backup.sh
sudo chmod 700 /root/backup.sh
sudo crontab -e
# run daily
0 1 * * * /root/backup.sh
Logging
I’m surprised there isn’t much progress here (maybe there is but I haven’t found the right rock to look under). So I set up a free Papertrail log. Looks like I already have some php segfaults to figure out… =I
In Conclusion
Don’t try this at home kids. I mean, I did, so it’s not like you _can’t_. But for anything semi-serious, paying $4/month to host your wordpress blog probably is a better idea.