Categories
Uncategorized

Practising code with Exercism

During the Coronavirus lockdown, I’ve been doing a programming exercise on Exercism every few days.

Level up your programming skills with 3,355 exercises across 50 languages, and insightful discussion with our dedicated team of welcoming mentors. Exercism is 100% free forever.

What is Exercism?

I started with their PHP track a few years ago and completed exercises on-and-off, but lately I’m enjoying the Python track. Here are a few of my most recent solutions:

Once you’ve finished an exercise, you can view other programmers’ solutions, or get feedback from mentors who are further along with your chosen language.

The Exercism people are working on some good improvements for version 3, one of which is improving the UI around mentor-student communication. As a result of mentors’ involvement in that work, mentorship is slower than normal, but it remains one of my favourite things about the platform.

Categories
Uncategorized

Trying Cloudflare

I installed the free version of Cloudflare on this blog in order to understand the setup involved. The advertised benefits of Cloudflare are:

  1. Security, e.g. mitigating denial-of-service attacks, identifying bots and limiting scrapers. These measures reduce workload on your own infrastructure and protect your content.
  2. Performance, including an easy-to-use (and often automatic) content delivery network (CDN) to serve files quickly from diverse geographical locations closer to each user;
  3. Reliability, by increasing redundancy in responding to DNS queries and routing traffic efficiently on distributed infrastructure.

I don’t have any problems with bots or scalability on this blog (I can dream) but a little extra performance never rarely hurts. Mostly it’s a learning experience ahead of getting Cloudflare up and running on more important websites.

If my past CDN experience is anything to go by, re-routing all traffic always comes with a few challenges but, for a simple WordPress site like this one, the setup was simple. The main step was to point the domain nameservers to Cloudflare instead of my original DNS provider. It felt incredibly simple.

The remaining quirks were around user IP addresses and cache invalidation.

Ensuring that WordPress sees the end user’s IP address

Since HTTP(S) requests from users’ browsers go to Cloudflare, and Cloudflare makes corresponding (less frequent) requests to my server, WordPress would see Cloudflare’s IP addresses every time instead of the IP addresses of individual end users.

This matters, for example, because WordPress saves the IP address of a user when they add a comment, and Akismet relies upon it to help identify spam.

Cloudflare helpfully passes the original user’s IP address in an HTTP request header, but I needed a way to tell WordPress to look for that header. There are two Apache modules which help:

  1. mod_cloudflare is mentioned in some old Cloudflare documentation, but it’s no longer supported;
  2. mod_remoteip is recommended now although it isn’t Cloudflare-specific and requires some configuration.

However, instead of solving the problem at that low level, I realised there was a Cloudflare plugin for WordPress itself. Not only did it solve the IP address issue, but it also met my another requirement…

Clearing the CDN cache when something changes

If all your static files (images, CSS, JavaScript) are cached around the world on Cloudflare’s CDN, you need a way to tell them to clear those caches when you change something.

You can do this manually in Cloudflare’s website, which would probably be okay for a site this small. Alternatively, you can send an API request with the same instruction. Best of all, the process can be automated fully by the Cloudflare WordPress plugin above, which gave it the edge over the Apache modules.

Categories
Uncategorized

Backing up WordPress to S3

This blog is hosted on a virtual machine at Linode, who provide a backup facility of their own. I’m using that, but I think it’s worthwhile to push an additional snapshot somewhere else at least once a week for additional redundancy.

I already have a personal account at Amazon Web Services, so each week, I’m sending a database dump and a tarball of the WordPress filesystem to an S3 bucket.

The high level steps:

  1. Create an S3 bucket taking care not to allow public access.
  2. Configure the bucket’s Lifecycle Policy to expire old backups after 95 days.
  3. Create an Amazon IAM user and grant API access to the S3 bucket, but not to any other resources on the AWS account.
  4. Install s3cmd on the Linode box where WordPress is hosted. It’s a command line interface for S3, written in Python.
  5. Deploy a shell script to create the filesystem tarball and dump the MySQL database before pushing both files to S3. Guy Rutenberg published a simple, but effective, WordPress backup script in 2008. I added a new command at the end to clean up the local copies of the backup files once they’re pushed successfully to S3.
  6. Download phusion-server-tools to the Linode box. These include a script called silence-unless-failed. Used as a wrapper around cron jobs, it suppresses output unless a script exits with an error code. Combined with cron’s own MAILTO command, it generates email alerts when something goes wrong, but only then.
  7. Create the cron job. I think weekly is enough to balance risk, storage cost and my blogging frequency. I’m relying on Linode’s backups in the first instance, so the S3 backups will only become important if something really bad happens.

Here’s Guy’s shell script, with the new cleanup command at the end:

#!/bin/bash

# (C) 2008 Guy Rutenberg
# This is a script that creates backups of my blog.

DB_NAME=database_name
DB_USER=database_user
DB_PASS=****
DB_HOST=db_host

#no trailing slash
BLOG_DIR=/path/to/blog
BACKUP_DIR=/path/to/backups
S3BUCKET=s3://bucket-name/

# end of configuration - you probably don't need to touch anything below
DUMP_NAME=${DB_NAME}-$(date +%Y%m%d).sql.bz2

echo -n "dumping database… "
mysqldump --user=${DB_USER} --password=${DB_PASS} --host=${DB_HOST} ${DB_NAME} \
| bzip2 -c > ${BACKUP_DIR}/${DUMP_NAME}
if [ "$?" -ne "0" ]; then
    echo "failed!"
    exit 1
fi
echo "done"

TAR_NAME=${BLOG_DIR##/}-$(date +%Y%m%d).tar.bz2
echo -n "Creating tarball… " tar -cjf ${BACKUP_DIR}/${BLOG_DIR##/}-$(date +%Y%m%d).tar.bz2 ${BLOG_DIR}
if [ "$?" -ne "0" ]; then
    echo "failed!"
    exit 1
fi
echo "done"

echo -n "Uploading SQL dump to Amazon S3… "
s3cmd put ${BACKUP_DIR}/${DUMP_NAME} ${S3BUCKET}${DUMP_NAME}
if [ "$?" -ne "0" ]; then
    echo "failed!"
    exit 1
fi
echo "done"

echo -n "Uploading tarball to Amazon S3… "
s3cmd put ${BACKUP_DIR}/${TAR_NAME} ${S3BUCKET}${TAR_NAME}
if [ "$?" -ne "0" ]; then
    echo "failed!"
    exit 1
fi
echo "done"

# additional command to delete local copies
echo -n "Deleting local copies of SQL dump and tarball… "
rm ${BACKUP_DIR}/${TAR_NAME} ${BACKUP_DIR}/${DUMP_NAME}
if [ "$?" -ne "0" ]; then
    echo "failed!"
    exit 1
fi
echo "done"