• Skip to primary navigation
  • Skip to main content

Will Angley

Just another WordPress site

  • About
  • Photos
  • Words
  • Resume
  • Contact

Will Angley

Why does installing Wi-Fi still involve knocking holes in walls?

January 15, 2021 by Will Angley

Wi-Fi doesn’t need holes in walls. But most Wi-Fi routers are still connected to the Internet through a wired connection to an ISP. This connection does.

Connecting to your ISP

The cable that your ISP uses to reach your home is a lot longer than cables inside your home. Even when it’s the same sort of cable, it uses different protocols that work better over long distances.

Installing Wi-Fi requires installing hardware that translates these protocols to home networking protocols: an optical network terminal (ONT) for fiber-optic networks, or a cable modem for cable Internet.

This hardware is usually installed close to where the cable to the ISP reaches your home, near an outside wall. This makes it easier for the ISP to fix when it breaks.

Connecting to your Wi-Fi router

But an exterior wall is a bad place for a Wi-Fi router. A computer on the other side of your home will be twice as far away as it would be if the Wi-Fi router was in the center of your home.

Wi-Fi is made of radio waves, so the inverse square law applies. Getting twice as far away means you have one fourth the signal strength.

Wi-Fi tries to make up for this by spending longer talking to far away devices, which leaves it less time to talk to every other device on your network. This is a common way to run into Wi-Fi performance problems, even when you think your Wi-Fi router should be good enough.

Putting the Wi-Fi router near the center of your home, and running an Ethernet cable between it and your ISP hardware, resolves this. It’s often the most impactful Wi-Fi upgrade you can make.

And you might save some money if you stop renting your ISP’s router, too.

Filed Under: Words

Marking myself into a corner, part 2: wpautop

January 6, 2021 by Will Angley

Previously: Marking myself into a corner, part 1

I found unexpected paragraph breaks in a post I’d written in Markdown, and copy-pasted into WordPress, about a day after I published it.

Clicking Edit showed I had line breaks in the Markdown source where there were paragraph breaks in the published post. I recognized this as WordPress’s wpautop filter, which uses different rules to place paragraph breaks than Markdown. A quick search shows this was reported upstream and closed as infeasible: jetpack#1965

I worked around it by deleting the line breaks.

Can I fix this with a plugin?

I tried dealing with this by using a plugin, Toggle wpautop, but found that wasn’t the right thing either; Jetpack Markdown relies on having wpautop active.

This is the second time I’ve encountered this; the first time was in 2019, when I was looking at moving from Hugo to WordPress. I felt overwhelmed and gave up on the project then.

This time, I looked back at the Jetpack issue, and saw there’s a workaround: calling wpautop( $content, false ); will do the right thing for Markdown posts. I haven’t found a plugin that implements this, but I might be able to patch it in to the one I’ve found…

Filed Under: Words

How I set up Tailscale on my WiFi router

January 4, 2021 by Will Angley

First published September 18, 2020; Upgrading OpenWRT added January 4, 2021.

Why?

I wanted to get to my WiFi router from the Internet, but didn’t want it serving the Internet. Putting it on a VPN is a good way to do this, and Tailscale makes VPNs easy enough to run and use that there’s no good reason not to.

When?

This past weekend. I’d just gotten back to Brooklyn and installed OpenWRT 19.07, which included a new enough kernel to support Wireguard.

This was possible before – Tailscale’s been shipping ARM builds for a while, and OpenWRT’s been shipping 19.07 for a while too – but I didn’t try it before now.

How?

I get out a MacBook Pro that I’ve already set up Tailscale on, and read through the Tailscale docs for setting up Tailscale with static binaries to know how the install is supposed to flow.

It probably won’t be possible to follow them exactly, because OpenWRT is different, so I start playing around.

Installing Tailscale on the router

I look up my router’s hardware specs, then find the tarball for my router in Tailscale’s stable track, and download it to my machine:

% curl -O https://pkgs.tailscale.com/stable/tailscale_1.0.5_arm.tgz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 11.9M 100 11.9M 0 0 3433k 0 0:00:03 0:00:03 --:--:-- 3433k %
Code language: plaintext (plaintext)

I’m not sure how much free RAM and flash I have on my router, but I know I haven’t installed anything else, and guess that 11.9M is relatively small enough that I don’t need to worry about it.

Warning

I haven’t been able to try this on any other routers, so I’m not sure when it’s safe to do this. If you want to follow along, proceed at your own risk.

So I copy the tarball over:

% scp tailscale_1.0.5_arm.tgz root@192.168.1.1:/tmp
Code language: plaintext (plaintext)

then SSH to the router and try to unpack the tarball:

# cd /tmp # tar xvf tailscale_1.0.5_arm.tgz tar: invalid tar magic #
Code language: plaintext (plaintext)

and it doesn’t work. OpenWRT uses busybox tar, so I fumble around for a bit (xkcd.com/1168 applies) and eventually figure out:

# tar x -zvf tailscale_1.0.5_arm.tgz
Code language: plaintext (plaintext)

Then I try running the binaries to make sure they’re actually the right ones 😛 :

# cd tailscale_1.0.5_arm # ./tailscale version 1.0.5-g31b5dec0a # ./tailscaled --help <...>
Code language: plaintext (plaintext)

Looks it. Then I try to start tailscaled for real to figure out its dependencies.

# ./tailscaled logtail started Program starting: v1.0.5-g31b5dec0a, Go 1.14.4-ts56db765: []string{"/usr/sbin/tailscaled"} LogID: 025f6648f94bcd1d40b0ee005ac472e123f7aeb2813874a71a7ba121da3d1827 logpolicy: using system state directory "/var/lib/tailscale" 2.6M/14.9M Starting userspace wireguard engine with tun device "tailscale0" 2.9M/16.6M Linux kernel version: 4.14.195 2.9M/16.8M is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: 2.9M/16.8M CreateTUN: can't create TUN device; /dev/net/tun does not exist 2.9M/16.8M wgengine.New: can't create TUN device; /dev/net/tun does not exist flushing log. logger closing down logtail: dialed "log.tailscale.io:443" in 415ms logtail: upload: log upload of 659 bytes compressed failed: Post "https://log.tailscale.io/c/tailnode.log.tailscale.io/0055d7ffaa6c80ecda7fef05574c36d025a42ead7d7409fce3b7218f84628e4a": x509: certificate signed by unknown authority logtail: backoff: 12 msec logtail: dialed "log.tailscale.io:443" in 413ms logtail: upload: log upload of 659 bytes compressed failed: Post "https://log.tailscale.io/c/tailnode.log.tailscale.io/0055d7ffaa6c80ecda7fef05574c36d025a42ead7d7409fce3b7218f84628e4a": context canceled #
Code language: plaintext (plaintext)

There are many lines of error messages but really two errors:

  • `modprobe tun` failed means that Tailscale asked the kernel for a TUN device and got back “huh?”
  • x509: certificate signed by unknown authority means that Tailscale tried to make a TLS connection but couldn’t figure out who was on the other end. When this happens with professional software (like Tailscale) it usually means no certificates are installed at all.

Both of these are pretty standard things to get from a package manager, but everyone calls them different names. I poke around OpenWRT’s packages and determine I probably need kmod-tun and ca-bundle, so I install them and try again.

# opkg update # opkg install ca-bundle kmod-tun
Code language: plaintext (plaintext)

After this, tailscaled is able to start:

# ./tailscaled <...>
Code language: HTML, XML (xml)

so I copy it to Flash.

# cp tailscale tailscaled /usr/sbin
Code language: plaintext (plaintext)

Running as a service

Tailscale comes with a simple systemd unit file. OpenWRT can’t use this directly, since it uses procd instead. I read the procd docs and, after about an hour of trial and error, port enough of it to get things working:

#!/bin/sh /etc/rc.common # Copyright 2020 Google LLC. # SPDX-License-Identifier: Apache-2.0 USE_PROCD=1 START=80 start_service() { procd_open_instance procd_set_param command /usr/sbin/tailscaled # Set the port to listen on for incoming VPN packets. # Remote nodes will automatically be informed about the new port number, # but you might want to configure this in order to set external firewall # settings. procd_append_param command --port 41641 # OpenWRT /var is a symlink to /tmp, so write persistent state elsewhere. procd_append_param command --state /etc/tailscale/tailscaled.state procd_set_param respawn procd_set_param stdout 1 procd_set_param stderr 1 procd_close_instance } stop_service() { /usr/sbin/tailscaled --cleanup }
Code language: Bash (bash)

Also available as a GitHub Gist.

It’s my first time working with procd, so I’m pretty happy with how it turned out.

Gists have awkwardly long URLs, so I make a redirect to it that will let me download it with a short URL and upload it to my router easily:

% curl -LO https://willangley.org/tailscale-procd % less tailscale-procd % scp tailscale-procd root@192.168.1.1:/tmp
Code language: plaintext (plaintext)

I SSH to the router, install the init script, and run it to start tailscaled.

# cp /tmp/tailscale-procd /etc/init.d/tailscale # chmod +x /etc/init.d/tailscale # /etc/init.d/tailscale start
Code language: plaintext (plaintext)

Log in to Tailscale

Once tailscaled is running, I run

# tailscale up
Code language: plaintext (plaintext)

to get a login link, and click it to log in.

After logging in, I go to the Tailscale admin console and look for my router’s hostname; since I’ve never changed it, it’s OpenWRT.

I copy its IP address and make sure I can ping it from the machine I’m working from. (This would fail if the machine wasn’t on Tailscale, or was on a different Tailscale network.)

% ping 100.114.61.77 PING 100.114.61.77 (100.114.61.77): 56 data bytes 64 bytes from 100.114.61.77: icmp_seq=0 ttl=64 time=43.378 ms 64 bytes from 100.114.61.77: icmp_seq=1 ttl=64 time=7.895 ms 64 bytes from 100.114.61.77: icmp_seq=2 ttl=64 time=7.046 ms 64 bytes from 100.114.61.77: icmp_seq=3 ttl=64 time=5.387 ms ^C --- 100.114.61.77 ping statistics --- 4 packets transmitted, 4 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 5.387/15.926/43.378/15.875 ms
Code language: plaintext (plaintext)

Once I confirm the connection works, I disable key expiry for the router to avoid it falling off of my network.

Surviving reboot

Now that I know it’s working, I enable the Tailscale service so it launches on every boot.

# /etc/init.d/tailscale enable
Code language: plaintext (plaintext)

And check to make sure it has succeeded:

# ls /etc/rc.d/*tailscale /etc/rc.d/S80tailscale
Code language: plaintext (plaintext)

This took me several tries to get right, because I forgot to add the START=80 variable to my init script; without it, OpenWRT didn’t know where to link it into the startup order.

But now that it’s there, I’m good to go! At least until the next sysupgrade. If we don’t do anything all of this will get wiped away.

Upgrading OpenWRT

Added January 4, 2021

Yes! It is, in fact, possible to upgrade in-place with Tailscale. Keeping Tailscale around solves half of this, and only needs to be set up one time.

Providing its dependencies in an upgrade image solves the other half. This needs to be done for each upgrade, because of how OpenWRT works.

Warning

Unlike other Linux distributions, installing an OpenWRT upgrade image wipes away packages that aren’t in the upgrade image. If you install an image from the OpenWRT Downloads page it will wipe away the dependencies we installed earlier and Tailscale will fail to start.

I forgot this and broke Tailscale while I was figuring this part out too.

Keeping Tailscale around

Reading the CLI upgrade docs shows there’s a config directory, /lib/upgrade/keep.d/, that holds lists of files to keep through sysupgrades. The format isn’t documented, but it looks a lot like “one file or directory a line,” and I create /lib/upgrade/keep.d/tailscale with all of the files above:

/etc/init.d/tailscale /etc/rc.d/*tailscale /etc/tailscale/ /lib/upgrade/keep.d/tailscale /usr/sbin/tailscale /usr/sbin/tailscaled

OpenWRT doesn’t use globs in any of the files in the base image, but they seem to work; testing with sysupgrade -l shows that all the files above are now included in the backup.

Building an OpenWRT image with our dependencies

To make the packages we need available after an upgrade, I’ll make a custom image with those packages using Image Builder. This is much quicker than building from source, O(45 seconds) with a fast network connection. I like fast when I can get it.

Both Image Builder and the targets it contains are specific to your WiFi router. I’m, once again, only going to show what I did for mine.

On Mac

I’ve already set up my Mac with the keys to verify OpenWRT images, so I:

  • download Image Builder there
  • verify it (not shown)
  • then transfer it to an Ubuntu VM I’m already running under Multipass for WordPress development
% curl -LO https://downloads.openwrt.org/releases/19.07.5/targets/ipq806x/generic/openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64.tar.xz % # verify image (snipped) % multipass transfer openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64.tar.xz primary:
Code language: PHP (php)

On Linux

  • install Image Builder’s prerequisites
  • unpack Image Builder
  • figure out my WiFi router’s profile with make info
  • build an image with the packages we’ll need for the install (and LuCI, it’s not included by default)
  • print out where it wound up
$ sudo apt install build-essential libncurses5-dev libncursesw5-dev zlib1g-dev gawk git gettext libssl-dev xsltproc wget unzip python $ tar xvf openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64.tar.xz $ cd openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64/ $ make info $ export LUCI_PACKAGES="uhttpd uhttpd-mod-ubus libiwinfo-lua luci-base luci-app-firewall luci-mod-admin-full luci-theme-bootstrap" $ make image PROFILE=netgear_r7800 PACKAGES="ca-bundle kmod-tun $LUCI_PACKAGES" $ cd bin/targets/ipq806x/generic/ $ realpath openwrt-19.07.5-ipq806x-generic-netgear_r7800-squashfs-sysupgrade.bin /home/ubuntu/openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64/bin/targets/ipq806x/generic/openwrt-19.07.5-ipq806x-generic-netgear_r7800-squashfs-sysupgrade.bin
Code language: JavaScript (javascript)

On Mac

Finally, I copy the built image back to my Mac.

% multipass transfer primary:/home/ubuntu/openwrt-imagebuilder-19.07.5-ipq806x-generic.Linux-x86_64/bin/targets/ipq806x/generic/openwrt-19.07.5-ipq806x-generic-netgear_r7800-squashfs-sysupgrade.bin .
Code language: JavaScript (javascript)

Flashing the custom image

Flashing a custom image works the same way as prebuilt ones. In fact, there’s no difference in the UI. If you’ve worked with both you’ll need to take care to not install a prebuilt image by mistake and break Tailscale.

I upload the image to my router with LuCI, make sure it looks like it’s the right size (it should be slightly larger than the image from the Downloads page for my router; when it was smaller, it meant I’d forgotten LuCI), and that the SHA256 sum does not appear on the Downloads page for my router (which would verify I’m about to break Tailscale.)

I leave the option to keep settings and retain the current configuration selected, and click Continue.

A few minutes later my WiFi router comes back up and Tailscale does too .

Repeat

I’ll need to repeat building a custom OpenWRT image with our dependencies and flashing the custom image for each future OpenWRT upgrade.

Future Work

Updated January 4, 2021

There’s an open Tailscale issue, tailscale/tailscale#724, to package Tailscale for OpenWRT. If this happens soon, there won’t be much to do here 🙂

If it takes longer, I’ll probably try to get OpenWRT to not wipe this away with a sysupgrade – I think this’ll involve some combination of editing /etc/sysupgrade.conf and using sysupgrade -k on future upgrades.

It’s possible to bake Tailscale into the image with the FILES= argument to Image Builder, supplying a Tailscale pre-authenticated key to establish the connection. This should be O(hours) to do as a one off, and I might try this for a future OpenWRT upgrade.

Google Cloud Build makes these sorts of builds easy to automate, and I could probably do so with O(days) work. But this still seems like overkill unless I wind up with a fleet of these somehow.

Appendix

I broke my router’s firmware once doing this.

It wasn’t even a step that I needed to do; I was trying to figure out how much space I’d consumed with packages, and ran a command from a snippet in a Google search that was supposed to remove unused packages without clicking it to read the rest of the page.

DANGER

Seriously, never do this.

The snippet looked reasonable, but if I’d clicked in, I would have seen the command I was about to run was going to remove the WiFi drivers.

But as I said, I didn’t, and wound up needing to rummage for a USB-to-Ethernet adapter and Ethernet cable to reinstall my firmware.

Filed Under: Words

Listening

January 3, 2021 by Will Angley

In August, I emailed my priest, Fr. Mark Burke, to ask for help living with my parents during COVID. We talked, and he included a prayer:

You can grow in your faith if you ask God for the grace to see your parents as He does. Ask for the grace to listen to them better. Let your faith be manifest in your charity. God gently will work through you, even if you’re unaware.

that I prayed, and later realized applied to more than my parents. I’ve come to see it as a statement of my values in life, and often the nearest I have to an answer to “what does it mean for me to be Catholic here?”

It’s largely about listening.

Filed Under: Words

Marking myself into a corner: server-side Markdown, AMP, and inline math

December 27, 2020 by Will Angley

I spoke too soon. Shortly after thinking I’d be happy in the Gutenberg editor for everything, I found that it pushed me towards not writing complicated documents effectively – it’s hard to move sentences that cross paragraph boundaries around, and hard to set information aside when it doesn’t work well – and started writing in Markdown again.

Preparing to publish one of these stories, I turned on server-side Markdown:

  1. install the Classic Editor plugin
  2. enable Markdown in Jetpack
  3. create a post in the Classic Editor.

since it’s closer to the Markdown dialects I’m familiar with than Jetpack’s Markdown block. I did some quick tests, and found that footnotes work1, but syntax highlighting and math don’t:

And then I remembered that I’d only gotten them working with syntax highlighting and MathML Gutenberg blocks. Oops.

What was I supposed to do?

Markdown code blocks output classes compatible with SyntaxHighlighter Evolved, which seems instructive: it looks like I’m meant to handle this in JavaScript.

I can’t, though, because I’m using AMP. This is by design: it’s how AMP is cacheable on third-party servers, and how it defends against XSS. I don’t get enough traffic for caching to matter but I do like having baked-in XSS defense, especially if I want to turn on comments later, and I’m hoping not to turn off AMP.

Instead, if I want to use these with server-side Markdown and AMP, I’ll need to either:

  • use alternatives to native Markdown syntax to embed these in posts, like:
    • GitHub Gists
    • Carbon images of code
    • LaTeX in Jetpack
  • render these in JavaScript on the server side. this is seldom done in WordPress, but Wikipedia has been doing this at scale with Mathoid for some time now
  • or glue together Markdown and the server-side logic I’m already using

I don’t like the way LaTeX in Jetpack renders to images – they’re blurry on the monitor I use most often for this – and I don’t want to upgrade my server in order to run Node, so I started exploring what it would take to render math here. With any luck this will be a superset of the work needed to get syntax highlighting working, too, and I’ll be able to do both quickly once I’ve done one.

Inline math is hard

The normal way of denoting math is $...$ for inline math, and $$
...
$$
for display math.

Double dollar signs are uncommon, so it’s pretty safe to use regexes to match them.

It’s just my $0.02, but I want to type single dollar signs often enough I wouldn’t want them to introduce a math context every time I use them. There are a couple ways of dealing with this:

  • Wrap them in inline code, following Yihui Xie
  • Tighten up the parser, since Marked, Pandoc and Rmarkdown don’t have this problem.

I think I’d rather tighten up the parser, since I’m already using Marked to preview Markdown on the Mac. Marked is closed source, so I can’t be sure what it does. But Pandoc is open-source, and instructive: it uses careful rules to restrict where single dollar signs introduce math contexts, and parser combinators to implement them (source).

A sketch of getting inline math working

  1. Dust off my local development environment, since it tends to bitrot.
  2. Set up a core functionality plugin for my site. Right now I’ve got this logic scattered throughout a Genesis child theme and a bunch of two or three line plugins.
  3. Port the CommonMark Math extension from Haskell to PHP. A straight port is possible, since PHP has parser combinator libraries nowadays like Parsica.
  4. Write a filter that replaces $...$ with <span class="math inline">...</span> and $$...$$ with <span class="math display">...</span>
  5. Write a filter that conditionally replaces <span class="math ..."> with the corresponding <amp-mathml> tags when AMP is enabled
  6. Wire them together in an AMP Custom Sanitizer

It seems simple enough. But I haven’t actually done any step after the first before, and recognize there are ways things could go wrong at each, or all, of the levels2. And I’ll likely need to ask for help along the way if I pick this up; it’ll be the most PHP I’ve written in a decade.

So I might as well write this down and go looking for help before things go wrong rather than after 😛


  1. and are amazing ↩
  2. “it’s in PHP” is not one of them. I’d much rather deal with this than figure out how to build photo essays from scratch in Django or Flask. ↩

Filed Under: Words

Building willangley.org, 2019–Present

November 22, 2020 by Will Angley

I didn’t take notes on how I was building willangley.org in 2019, because I was only planning to build it once; I planned to deal with things going wrong with backups, and things going right with in-place capacity upgrades.

Now it’s prompting me to upgrade, from Ubuntu 18.04 LTS to Ubuntu 20.04 LTS. It’s sometimes necessary to rebuild servers when an in place upgrade doesn’t work, so I might need to build this twice after all; restoring to before a failed upgrade is likely to bring you to a state where the upgrade will fail again .

This is a good reminder to figure out what I did and write it down, even if I don’t upgrade immediately.

Info

Although I’ve published my notes here, I’ve also kept a copy off the system in Bear so I can get to them if willangley.org is broken.

Development environment

I’ve been using Local to run WordPress on my machine since before I knew if I’d go live with a WordPress site, or how I’d serve it if I did.

I don’t develop PHP at work any more and lean heavily on an editor (usually either Sublime Text or Visual Studio Code) to remind me what I’m looking at, and this makes them work well.

I’ve tried to make my site portable between both my server and Local.

Server

I mostly followed the 2019 version of Hosting WordPress Yourself, with some exceptions that follow below.

Machine

willangley.org runs on a single DigitalOcean Basic droplet, with DigitalOcean backups taking weekly snapshots on the server.

PHP

I’m using PHP 7.2, since it’s packaged with Ubuntu, rather than adding a PPA to get a more modern version.

I’ve also added several extensions to PHP to get one plugin or another working. Running dpkg -l | grep php says I’ve got: php-common php-igbinary php-imagick php-intl php-pear php-redis php7.2-bcmath php7.2-cli php7.2-common php7.2-curl php7.2-dev php7.2-fpm php7.2-gd php7.2-imap php7.2-intl php7.2-json php7.2-mbstring php7.2-mysql php7.2-opcache php7.2-readline php7.2-soap php7.2-xml php7.2-xmlrpc php7.2-zip pkg-php-tools installed now, and will likely need them again on a new server too. (Some, but not all, of them are installed by the base PHP install.)

SSH

I followed the guide , set up an SSH key pair, and turned off passwords.

Since then I’ve installed Tailscale on the server, and firewalled off SSH from most of the Internet. Then Jetpack complained, so I opened up SSH back up for their IP address ranges only.

This firewall is applied at the DigitalOcean Networking level, rather than running on the droplet. It’ll apply to my new server automatically when I add it to the web-serving firewall group.

DNS

DNS for my domain lives on Google Domains, but my server lives in DigitalOcean.

In Google Domains, I have an NS record for do.willangley.org that delegates them to DigitalOcean, and I have A records for @ and www that point directly to the IP address of my server in DigitalOcean.

In DigitalOcean, I have an NS record for DigitalOcean, and an A record for the server running willangley.org.

I’d been trying to avoid troubleshooting mail forwarding for @willangley.org by moving as little as possible, because I use a @willangley.org address as a login for some services. But this split setup is seeming like a mistake in hindsight and I’ll likely back it out.

Monitoring

Is set up through the DigitalOcean agent. CPU looks good,

memory meh but probably fine.

Object Cache

I skipped using Redis initially, then came back when I installed the AMP plugin and it asked for an object cache.

I used WP Redis instead of Redis Object Cache like the tutorial recommended, because I wanted to use Redis on a Unix domain socket and Redis Object Cache doesn’t support that. Unix domain sockets mean one less thing to manage passwords and firewall rules for.

Page Cache

I set up WP Super Cache for page caching, instead of handling caching in nginx and using Nginx Cache like the tutorial recommended.

I can’t remember why I did this but it might’ve had something to do with using Local for development instead of a copy of the server.

Email

I ignored the part about sending email from a WordPress plugin. This makes a lot of sense if you’re hosting WordPress for clients, and want them to get WordPress emails and you to get system emails.

But I’m not; I want both WordPress and system emails to go to me. So I followed the Sending email with SendGrid instructions to send mail from Postfix instead.

Backups

I ignored the part about tarball backups, and signed up for Jetpack backups instead.

Since I was already planning to use other Jetpack features this made sense to me. It still largely does, although it’s never fit in super well with Local (protip: Local will create a database for you when it’s creating a site, but the .sql script that Jetpack Backups gives you expects not to have this. Drop the tables in phpMyAdmin, then run the script, and things will work cleanly) and iterating on my theme a few weeks ago didn’t seem to prompt real-time backups.

Automatic security updates

I’ve configured unattended-upgrades to perform security updates and to restart automatically. I did not request a specific reboot time, since I’d rather have brief downtime than run an old kernel for a day until the time arrives again.

Additionally, I’ve set it to use minimal steps to avoid blocking shutdown, and to mail me on upgrades.

Unattended-Upgrade::MinimalSteps "true"; 
Unattended-Upgrade::Mail "root";
Code language: PHP (php)

This reminds me that my server is taking care of itself, and if something goes wrong I’ll hopefully have an email with the bad upgrade in my inbox before an email from Jetpack downtime monitoring telling me that things are broken.

WordPress build

I did this locally first, rather than starting with wp-cli on the server, and copied it over later. I’ve got some plugins with config settings in them, and a customized theme, that both seemed easier to develop this way than across the Internet.

The smallest Basic droplet is powerful enough to serve a pretty good amount of traffic, but Visual Studio Code Remote Development will bring it to its knees in a hurry.

I disabled comments before serving my site. This isn’t a permanent decision – I think they can add value – but I’m only going to think about enabling them if I get to blogging regularly enough I think I’ll be able to sustain a community.

Jetpack is enabled. I’m actively using Anti-Spam (on the contact form only), Backups, Brute Force Login Protection, Contact Form, Downtime Monitoring, Image Optimization, Scan, and Stats.

Automatic updates are turned for WordPress, plugins, and themes too.

Planning to build on 20.04

Now that I’ve poked at this a bit I’m pretty sure it’ll translate to the new version of Hosting WordPress Yourself, Set Up a DigitalOcean Virtual Server for WordPress on Ubuntu 20.04.

Even though 18.04 will be supported for another two and a half years, I’m hoping to go to 20.04 sooner. WordPress is already recommending PHP 7.4, and I’d rather upgrade than spend time getting backports working.

But this time I’ll write down what I’m doing so I don’t have to reverse engineer it all over again when 22.04 comes out.

Filed Under: Words

  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Interim pages omitted …
  • Go to page 5
  • Go to Next Page »

Copyright © 2014–2021 Will Angley · Privacy Policy · Made with ❤️ and WordPress in NYC