Skip to content

Deploying a Pixelfed App

Introduction

Pixelfed is an open-source, federated photo-sharing platform built on Laravel with ActivityPub support. Deploying Pixelfed with a Dockerfile on Klutch.sh provides reproducible builds, managed secrets, and persistent storage for media and cache—all configured from klutch.sh/app. This guide covers installation, repository prep, a production-ready Dockerfile, deployment steps, Nixpacks overrides, sample API usage, and production tips.


Prerequisites

  • A Klutch.sh account (sign up)
  • A GitHub repository containing your Pixelfed Dockerfile (GitHub is the only supported git source)
  • PostgreSQL or MySQL database (deploy as a Klutch.sh TCP app on port 8000; connect on native port)
  • Redis instance for queues/cache (deploy as a Klutch.sh TCP app on port 8000; connect on 6379)
  • Domain and TLS for secure access

For onboarding, see the Quick Start.


Architecture and ports

  • Pixelfed (Laravel) serves HTTP on internal port 8080; choose HTTP traffic.
  • Persistent storage is required for media, cache, and logs.

Repository layout

pixelfed/
├── Dockerfile # Must be at repo root for auto-detection
├── composer.json
├── package.json
├── .env.example # Template only; no secrets
└── storage/ # Laravel storage (persist)

Keep secrets out of Git; store them in Klutch.sh environment variables.


Installation (local) and starter commands

Validate locally before pushing to GitHub:

Terminal window
composer install --no-dev
php artisan key:generate
php artisan migrate --force
npm install
npm run build
php artisan serve --host 0.0.0.0 --port 8080

Dockerfile for Pixelfed (production-ready)

Place this Dockerfile at the repo root; Klutch.sh auto-detects it (no Docker selection in the UI):

FROM php:8.2-fpm-alpine AS backend
WORKDIR /var/www/html
RUN apk add --no-cache git zip unzip libpng-dev libjpeg-turbo-dev libzip-dev oniguruma-dev icu-dev \
&& docker-php-ext-configure gd --with-jpeg \
&& docker-php-ext-install pdo pdo_mysql pdo_pgsql gd intl zip opcache
COPY composer.json composer.lock ./
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer install --no-dev --optimize-autoloader
COPY . .
RUN php artisan config:cache && php artisan route:cache && php artisan view:cache
FROM node:18-alpine AS frontend
WORKDIR /app
COPY package.json pnpm-lock.yaml* yarn.lock* package-lock.json* ./
RUN corepack enable
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM nginx:alpine
ENV PORT=8080
WORKDIR /var/www/html
COPY --from=backend /var/www/html /var/www/html
COPY --from=frontend /app/public /var/www/html/public
RUN apk add --no-cache bash \
&& rm -rf /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]

Example nginx.conf (place alongside Dockerfile):

server {
listen 8080;
server_name _;
root /var/www/html/public;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

Notes:

  • Pin base images for stability. Adjust DB extensions to match your database.
  • Ensure the PHP-FPM socket path matches the base image; update fastcgi_pass if needed.

Environment variables (Klutch.sh)

Set these in Klutch.sh before deploying:

  • PORT=8080
  • APP_ENV=production
  • APP_URL=https://example-app.klutch.sh
  • APP_KEY=<generated via php artisan key:generate>
  • Database (choose one):
    • MySQL: DB_CONNECTION=mysql, DB_HOST=<host>, DB_PORT=3306, DB_DATABASE=<db>, DB_USERNAME=<user>, DB_PASSWORD=<password>
    • PostgreSQL: DB_CONNECTION=pgsql, DB_PORT=5432, plus host/db/user/password
  • Redis: REDIS_HOST=<redis-host>, REDIS_PORT=6379, REDIS_PASSWORD=<password>
  • Queue: QUEUE_CONNECTION=redis
  • Mail (optional): MAIL_MAILER=smtp, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_ENCRYPTION
  • Federation: set ActivityPub-related vars as required by your setup

If you deploy without the Dockerfile and need Nixpacks overrides:

  • NIXPACKS_PHP_VERSION=8.2
  • NIXPACKS_NODE_VERSION=18
  • NIXPACKS_BUILD_CMD=composer install --no-dev --optimize-autoloader && php artisan config:cache && php artisan route:cache && php artisan view:cache && npm install && npm run build
  • NIXPACKS_START_CMD=php artisan serve --host 0.0.0.0 --port 8080

Attach persistent volumes

In Klutch.sh storage settings, add mount paths and sizes (no names required):

  • /var/www/html/storage — media uploads, cache, and logs.
  • /var/www/html/public — built assets if you choose to persist them (optional).

Ensure these paths are writable inside the container.


Deploy Pixelfed on Klutch.sh (Dockerfile workflow)

  1. Push your repository—with the Dockerfile (and nginx.conf) at the root—to GitHub.
  2. Open klutch.sh/app, create a project, and add an app.
  3. Select HTTP traffic and set the internal port to 8080.
  4. Add the environment variables above, including DB, Redis, mail, and ActivityPub settings.
  5. Attach persistent volumes for /var/www/html/storage (and optionally /var/www/html/public) sized for your media and cache.
  6. Deploy. Complete any post-deploy tasks (e.g., queues, horizon) as needed; your Pixelfed instance will be reachable at https://example-app.klutch.sh.

Sample API usage

List public statuses (example; adjust to your API/version and auth):

Terminal window
curl -X GET "https://example-app.klutch.sh/api/v1/timelines/public"

Create a status (replace token):

Terminal window
curl -X POST "https://example-app.klutch.sh/api/v1/statuses" \
-H "Authorization: Bearer <token>" \
-F "status=Hello from Pixelfed on Klutch.sh"

Health checks and production tips

  • Add an HTTP probe to / or a lightweight health endpoint if you expose one.
  • Enforce HTTPS at the edge; forward internally to port 8080.
  • Keep APP_KEY, DB, Redis, and mail credentials in Klutch.sh secrets; rotate regularly.
  • Monitor storage usage on /var/www/html/storage; resize before it fills.
  • Pin image versions and test upgrades in staging; back up DB and storage before updates.

Pixelfed on Klutch.sh combines reproducible Docker builds with managed secrets, persistent storage, and flexible HTTP/TCP routing. With the Dockerfile at the repo root, port 8080 configured, and Postgres/Redis connected, you can deliver a federated photo-sharing experience without extra YAML or workflow overhead.