Migrating Pixelfed (Part One)

Migrating Pixelfed (Part One)
小笼包 xiǎo lóng bāo -- soup dumpling @ J&J Restaurant (San Gabriel, CA)

About a year ago, I wanted to join the fediverse and wanted to see what their alternatives were to Instagram. And while I saw that Pixelfed provided the framework, a food-centric photo platform has been missing from the landscape, going back to the days of Flickr before they were acquired by Yahoo. I went about manually deploying a Pixelfed instance to small, single-core VPS as part of some promo deal.

Fast forward about a year and the true, non-promo rate of that VPS has come to bear and it was astonishingly bad. I followed this self-hosting guide (originally intended for torrent-related usage) and spun up an Oracle Cloud Instance with a pay-as-you-go plan, setting up $1 budget guardrails to ensure that I stay within the free tier of usage. The first gotcha I ran into (which required me to terminate and spin up another instance) was that, while attempting to configure the instance to allow for multiple services running at once, I inadvertently enabled ufw. This runs counter to the documented best-practices, which explicitly says it might cause an instance not to boot.

This was the sign that I needed forget everything I did surrounding my manual deployment on the promo VPS. It was time to containerize, and that included the reverse proxy. Luckily there was extensive documentation for Traefik, which would act as an orchestrator of sorts. Essentially, docker would act as a discovery layer, and any time any docker instance was spun up, Traefik would look at the labels applied in its respective docker-compose.yml and use that as configuration.

This includes Traefik's own labels. So the first task was configuring Traefik's own docker-compose.yml to properly route the certificate resolver, which requires an HTTP challenge.

# ./docker-compose.yml

services:
  traefik:
    image: traefik:v3.6.7
    container_name: traefik
    restart: unless-stopped
  network:
    - traefik-public
  labels:
    - "traefik.enable=true"
    # ACME bypass
    - "traefik.http.routers.acme-priority.rule=PathPrefix(`/.well-known/acme-challenge/`)"      
    - "traefik.http.routers.acme-priority.entrypoints=web"
    - "traefik.http.routers.acme-priority.priority=10000"
    - "traefik.http.routers.acme-priority.service=acme-http@internal"    
networks:
  traefik-public:
    external: true

Add an ACME bypass block among the labels with an explicitly high priority

You'll note also that there's an external network. In addition to the labels, this ensures that the various containers has visibility to this Traefik instance. You can name this network whatever you like, but it needs to be used across every other app's docker-compose.yml

$ docker network create traefik-public

Traefik includes an image for whoami which could be easily added to its docker configuration. But of course, I hadn't yet set up the DNS for this domain yet. Luckily curl allows for exactly this situation.

$ curl -H "Host: whoami.cobaltroad.com" <my-OCI-instance-IP-address>

This allowed me to tail the Traefik logs and see that it was being handled and routed appropriately.

Once I had confidence in that, it was time to install a docker instance of Pixelfed. I opted to go with Pixelfed Glitch, which forked the original dansup repo in favor of a docker-centric approach. All of the setup scripts are moved into entrypoint initialization scripts. I ran into a problem with one in particular, 09-cache.sh, but it was easy enough to single out that script in the instance .env file which instructed it to skip that file on startup. With very little resistance, tailing the log showed "GET /index.php" 200 and I knew I was in business.

Next up: migrating the data!