How to Self-Host Pixelfed with Docker Compose

Instagram, But Federated

Pixelfed is a photo-sharing platform that federates with the fediverse via ActivityPub. It looks and feels like Instagram — grid layouts, Stories, filters, hashtags, explore page — but you own the server and your data. Mastodon users can follow Pixelfed accounts and see photos in their timeline. Official site

If you’re tired of Instagram’s algorithmic feed, ads, and data collection but still want a visual social media experience, Pixelfed is the answer.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 2 GB RAM minimum
  • 20 GB of free disk space (grows with photo storage)
  • A domain name
  • SMTP credentials (required for registration)
RequirementMinimumRecommended
CPU2 cores4 cores
RAM2 GB4 GB
Disk20 GB100 GB+ (photo storage)
EmailSMTP requiredTransactional service

Docker Compose Configuration

services:
  pixelfed:
    # Pixelfed does not publish semver Docker tags — :latest is the intended deployment tag
    image: ghcr.io/pixelfed/pixelfed:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - pixelfed-storage:/var/www/storage
      - ./.env:/var/www/.env:ro
    networks:
      - pixelfed

  worker:
    # Same image as the main service — Pixelfed uses :latest as the stable tag
    image: ghcr.io/pixelfed/pixelfed:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - pixelfed-storage:/var/www/storage
      - ./.env:/var/www/.env:ro
    entrypoint: ["php", "artisan", "horizon"]
    networks:
      - pixelfed

  db:
    image: mariadb:11.7
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: change_this_root_password
      MYSQL_DATABASE: pixelfed
      MYSQL_USER: pixelfed
      MYSQL_PASSWORD: change_this_password
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - pixelfed

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - pixelfed

networks:
  pixelfed:

volumes:
  pixelfed-storage:
  db-data:
  redis-data:

Environment Configuration (.env)

Create .env alongside your docker-compose.yml:

# App settings
APP_NAME="Pixelfed"
APP_ENV=production
APP_KEY=  # Generate with: docker compose run --rm pixelfed php artisan key:generate --show
APP_DEBUG=false
APP_URL=https://pixelfed.example.com

# Domain — CANNOT be changed after first run
ADMIN_DOMAIN=pixelfed.example.com
APP_DOMAIN=pixelfed.example.com

# Database
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=pixelfed
DB_USERNAME=pixelfed
DB_PASSWORD=change_this_password

# Redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

# Queue and cache
QUEUE_DRIVER=redis
CACHE_DRIVER=redis
SESSION_DRIVER=redis
BROADCAST_DRIVER=log

# Email (REQUIRED for registration)
MAIL_DRIVER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=your_smtp_user
MAIL_PASSWORD=your_smtp_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=[email protected]
MAIL_FROM_NAME="Pixelfed"

# ActivityPub federation
ACTIVITY_PUB=true
AP_REMOTE_FOLLOW=true
AP_INBOX=true
AP_OUTBOX=true
AP_SHAREDINBOX=true

# Instance settings
OPEN_REGISTRATION=true
ENFORCE_EMAIL_VERIFICATION=true
MAX_PHOTO_SIZE=15000         # KB (15 MB)
MAX_CAPTION_LENGTH=500
MAX_BIO_LENGTH=125
MAX_NAME_LENGTH=30
MAX_ALBUM_LENGTH=4           # Max photos per post
IMAGE_QUALITY=80

# Storage
PF_ENABLE_CLOUD=false
FILESYSTEM_DRIVER=local

# Features
STORIES_ENABLED=true
PF_ENABLE_PORTFOLIO=true

First-Time Setup

# Generate app key
docker compose run --rm pixelfed php artisan key:generate --show
# Copy the output into .env as APP_KEY

# Start services
docker compose up -d

# Run database migrations
docker compose exec pixelfed php artisan migrate --force

# Create storage link
docker compose exec pixelfed php artisan storage:link

# Create admin account
docker compose exec pixelfed php artisan user:create
# Follow the prompts, answer 'yes' to make admin

# Cache configuration
docker compose exec pixelfed php artisan config:cache
docker compose exec pixelfed php artisan route:cache

Initial Setup

  1. Navigate to https://pixelfed.example.com
  2. Log in with your admin account
  3. Go to Admin → Settings to configure:
    • Instance name, description, contact email
    • Registration settings (open, closed, invite-only)
    • Content policies (NSFW, max upload size)
    • Features (Stories, Collections, portfolio)
  4. Upload your first photo to verify everything works

Configuration

Instance Features

FeatureSettingDefault
StoriesSTORIES_ENABLEDfalse
CollectionsAdmin → FeaturesEnabled
Portfolio pagesPF_ENABLE_PORTFOLIOfalse
Direct messagesAdmin → FeaturesEnabled
Video uploadsVIDEO_ENABLEDfalse
Max photos per postMAX_ALBUM_LENGTH4
Max photo sizeMAX_PHOTO_SIZE15000 KB

S3 Object Storage

For larger instances, offload media to S3-compatible storage:

PF_ENABLE_CLOUD=true
FILESYSTEM_CLOUD=s3
AWS_ACCESS_KEY_ID=your_key
AWS_SECRET_ACCESS_KEY=your_secret
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=pixelfed-media
AWS_URL=https://s3.example.com

Reverse Proxy

Pixelfed serves on port 80 inside the container, mapped to 8080 on the host.

Caddy:

pixelfed.example.com {
    reverse_proxy localhost:8080
}

See our Reverse Proxy Setup guide.

Backup

# Database backup
docker compose exec db mariadb-dump -u pixelfed -p pixelfed > pixelfed_db_$(date +%F).sql

# Media storage
docker run --rm -v pixelfed_pixelfed-storage:/data -v $(pwd):/backup \
  alpine tar czf /backup/pixelfed_storage_$(date +%F).tar.gz -C /data .

Also back up .env. See our Backup Strategy guide.

Troubleshooting

Photos Not Processing

Symptom: Uploads hang or fail, thumbnails not generated. Fix: Check the worker container is running: docker compose logs worker. Pixelfed uses Laravel Horizon for queue processing. If the worker died, restart it: docker compose restart worker.

Federation Not Working

Symptom: Remote accounts can’t see your posts. Fix: Verify ACTIVITY_PUB=true and all AP_* settings are enabled. Check that your domain resolves and HTTPS works. Test WebFinger: https://pixelfed.example.com/.well-known/webfinger?resource=acct:[email protected].

500 Error After Config Change

Symptom: Server error after editing .env. Fix: Clear cached configuration:

docker compose exec pixelfed php artisan config:clear
docker compose exec pixelfed php artisan cache:clear
docker compose exec pixelfed php artisan config:cache

Storage Full

Symptom: Uploads fail, disk space exhausted. Fix: Check storage usage. Clean up old temporary files:

docker compose exec pixelfed php artisan media:gc

Consider migrating to S3 storage for long-term scaling.

Resource Requirements

ResourceSmall Instance (<50 users)Medium Instance (50-500 users)
RAM1-2 GB3-4 GB
CPU2 cores4 cores
Disk20 GB100+ GB (photos)
Bandwidth20 GB/month100+ GB/month

Storage is the main cost driver. Photos eat disk space fast. Plan for S3-compatible object storage if you expect significant usage.

Verdict

Pixelfed is the only serious self-hosted Instagram alternative. The UI is polished, federation works well, and features like Stories and Collections make it genuinely usable as a daily photo-sharing app. It’s heavier than a simple gallery but lighter than running Mastodon.

Choose Pixelfed if you want a federated photo-sharing platform with an Instagram-like experience. Your photos, your server, visible across the entire fediverse.

Look elsewhere if you want a private photo backup and management tool — that’s Immich. If you want microblogging with occasional photo posts, Mastodon handles images fine.

FAQ

Can Mastodon users see my Pixelfed posts?

Yes. Mastodon users can follow your Pixelfed account and see your photos in their home timeline. They can like and comment on your posts too.

Does Pixelfed support video?

Yes, with VIDEO_ENABLED=true. Video support includes upload, playback, and federation. It’s not as full-featured as Instagram Reels but handles short video clips.

Can I import photos from Instagram?

Pixelfed has an Instagram data import feature. Download your Instagram data export, then use Pixelfed’s import tool in settings. Photos, captions, and dates transfer.

Is Pixelfed mobile-friendly?

The web app is responsive and works well on mobile. There’s also a native Android app (PixelDroid) and an iOS app in development.

Comments