# Pixelfed 0.14: photo posts (Notes with Image attachments, alt text, a `location` Place), comments, likes, follows and # collections, and FEP-8fcf followers sync. Laravel on FrankenPHP (serversideup's image), on the shared Postgres # (database pixelfed) and Redis (dbs 5 and 6), with Horizon (which runs every federation job) and the scheduler as # sidecars of the same image sharing its storage volume. It trusts Caddy's CA through the bundle mounted as its system # store; its URL guard refuses private addresses with no switch, which the pasture's public-looking subnet passes. Its # admin is pfuser; tokens are Passport personal access tokens made through tinker. PIXELFED_IMAGE=${PIXELFED_IMAGE:-ghcr.io/pixelfed/pixelfed:v0.14.4} PIXELFED_PASSWORD=Pixelfed-Pasture-1 . "$here/peers/shared.sh" pixelfed_env() { local key_file="$here/.state/pixelfed/app.key" [ -s "$key_file" ] || { mkdir -p "$here/.state/pixelfed"; echo "base64:$(head -c 32 /dev/urandom | base64)" > "$key_file"; } cat < "$here/.state/pixelfed/env" podman volume exists pasture-pixelfed-storage || podman volume create --label pasture=1 pasture-pixelfed-storage >/dev/null local mounts=(-v pasture-pixelfed-storage:/var/www/html/storage -v "$ca/bundle.pem:/etc/ssl/certs/ca-certificates.crt:z,ro") pixelfed_run pasture-pixelfed -e AUTORUN_ENABLED=true "${mounts[@]}" "$PIXELFED_IMAGE" >/dev/null for _ in $(seq 1 100); do site pixelfed.test -s -o /dev/null -w '%{http_code}' https://pixelfed.test:6443/api/nodeinfo/2.0.json 2>/dev/null | grep -q 200 && break sleep 3 done pixelfed_run pasture-pixelfed-horizon "${mounts[@]}" "$PIXELFED_IMAGE" php artisan horizon >/dev/null pixelfed_run pasture-pixelfed-cron "${mounts[@]}" "$PIXELFED_IMAGE" php artisan schedule:work >/dev/null pixelfed_settle echo "pixelfed: https://pixelfed.test:6443" } pixelfed_artisan() { podman exec pasture-pixelfed php artisan "$@"; } # the instance actor, Passport's keys and personal client, the admin pfuser and its token. Passport takes a token whose # user id equals its client's id for a client-credentials token and refuses it, so the clients are numbered from a # million, past any user. FrankenPHP keeps the keys it read at boot: the web server restarts once they exist. pixelfed_settle() { # 0.14.4's migration making caption and rendered nullable on PostgreSQL checks for a connection named "postgres", # never Laravel's "pgsql", so it does nothing and every remote boost (and DM) fails on NOT NULL: done here instead podman exec pasture-postgres psql -U pasture -d pixelfed -qc \ "alter table statuses alter column caption drop not null, alter column rendered drop not null" >/dev/null pixelfed_artisan instance:actor >/dev/null 2>&1 || true if ! podman exec pasture-pixelfed test -s storage/oauth-private.key; then pixelfed_artisan passport:keys --force >/dev/null 2>&1 || true podman restart pasture-pixelfed >/dev/null for _ in $(seq 1 60); do podman exec pasture-pixelfed curl -sf -o /dev/null http://localhost:8080/api/nodeinfo/2.0.json && break; sleep 2; done fi if [ "$(podman exec pasture-postgres psql -U pasture -d pixelfed -Atc "select count(*) from oauth_clients where personal_access_client and not revoked and id >= 1000000")" = "0" ]; then podman exec pasture-postgres psql -U pasture -d pixelfed -qc "update oauth_clients set revoked = true where personal_access_client; select setval('oauth_clients_id_seq', greatest((select coalesce(max(id), 0) from oauth_clients), 1000000));" >/dev/null pixelfed_artisan passport:client --personal --name=pasture --no-interaction >/dev/null 2>&1 || true fi pixelfed_user pfuser admin pixelfed_token pfuser > "$here/.state/pixelfed.token" # the cities a post's place is chosen from (a couple of minutes, once) [ "$(podman exec pasture-postgres psql -U pasture -d pixelfed -Atc "select count(*) from places")" != "0" ] \ || pixelfed_artisan import:cities --no-interaction >/dev/null 2>&1 || true } # pixelfed_user [admin]: an account with a confirmed email and the pasture's password (user:admin only asks, and # answers no without a terminal, so an admin is made in the database) pixelfed_user() { pixelfed_artisan user:create --name="$1" --username="$1" --email="$1@pixelfed.test" --password="$PIXELFED_PASSWORD" \ --confirm_email=1 --no-interaction >/dev/null 2>&1 || true [ "${2:-}" = "admin" ] && podman exec pasture-postgres psql -U pasture -d pixelfed -qc "update users set is_admin = true where username = '$1'" >/dev/null return 0 } # pixelfed_token : a personal access token with every scope the Mastodon API asks for pixelfed_token() { podman exec pasture-pixelfed php artisan tinker --execute \ "echo App\\Models\\User::where('username', '$1')->first()->createToken('pasture', ['read', 'write', 'follow', 'push'])->accessToken;" 2>/dev/null | tail -1 }