Phanpy is an excellent front-end client for Mastodon compatible Fediverse instances that I use with GoToSocial. Here’s how I build the Progressive Web App (PWA).

A screenshot of Phanpy compose window with two black and white images added and the alt-text filled out.
Phanpy compose window now automatically reads the alt-text embedded in image files

Phanpy is a purely static web app so serving it is as simple as pointing your webserver (Caddy in my case) at a static folder. Phanpy has releases that you can just unzip but I want to build and use the latest feature before release sometimes. And I also wanted a single command to update my customized install. I created a Containerfile (Dockerfile) to build the app and a shell script to run the container and extract the build artifact so I can serve it out of Caddy (instead of running another web server within another container).

Phanpy needs node with vite to build so there’s a npm install step and I added git and tar to the alpine container to get the latest Phanpy code and create an archive of the build output.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
FROM node:25-alpine
RUN apk update
RUN apk add git tar
RUN git clone https://github.com/cheeaun/phanpy.git
WORKDIR /phanpy
RUN npm install
RUN PHANPY_CLIENT_NAME="Phanpy" \
    PHANPY_WEBSITE="url-of-where-phanpy-will-be-served-from" \
    PHANPY_DEFAULT_INSTANCE="url-of-the-mastodon-compatible-fediverse-instance" \
    PHANPY_REFERRER_POLICY="no-referrer" \
    PHANPY_DISALLOW_ROBOTS="true" \
    npm run build
RUN tar cf ./phanpy.tar -C /phanpy/dist/ .
ENTRYPOINT ["sh"]

I typically run the application in the same container that builds it. I normally deal with file ingress and egress via folders mounted from the host into the container. But I had to learn that in order to extract a build artifact (phanpy.tar in my case) I had to use podman cp from a running container, so that’s what is happening here, the application is built, containers is started, build artifact copied out and extract, and finally the container is removed. I use Podman but wherever you see podman you can replace with docker if that’s what you’re using.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
set -euo pipefail
podman build --tag phanpy .
podman create --name phanpy phanpy:latest
podman cp phanpy:/phanpy/phanpy.tar ./
rm -rf ./phanpy
mkdir -p ./phanpy
tar xf phanpy.tar -C ./phanpy
rm phanpy.tar
podman rm phanpy

I’m sure there are better and more idiomatic ways of doing this, so if you have any suggestions please drop me a line.