How to Install Pixelfed on Ubuntu 24.04 — Self-Hosted Federated Instagram Alternative
Pixelfed is an open-source, federated photo-sharing platform — a sovereign alternative to Instagram built on the ActivityPub protocol. Running your own Pixelfed instance means your photos, captions, and social graph live on hardware you control, and they can still federate with millions of users across Mastodon, PeerTube, and the rest of the fediverse. This tutorial takes you from a blank Ubuntu 24.04 VPS to a production-ready Pixelfed node with TLS, a queue worker, and optional S3 media storage.
Short on time? Deploy Pixelfed on a VPS tuned for media workloads. Launch a Professional VPS and you will be ready to start the install in under two minutes.
Table of Contents
What is Pixelfed?
Pixelfed is a federated image-sharing server written in PHP on the Laravel framework. In a single instance you get a photo timeline, stories, collections, direct messages, hashtag discovery, and a clean mobile-friendly web UI. The defining feature is federation: Pixelfed speaks ActivityPub, the same protocol that powers Mastodon and PeerTube, so a user on your Pixelfed instance can be followed by — and interact with — anyone across the fediverse.
Technically, a Pixelfed node is a Laravel application backed by MariaDB or PostgreSQL for durable storage, Redis for cache and queues, Horizon for background job management, FFmpeg for video transcoding, and ImageMagick for image variants. Media can live on the local filesystem or any S3-compatible object store. The whole stack runs happily on a single VPS for small to medium instances, and horizontally scales by detaching Horizon workers, the database, and object storage onto separate machines when an instance grows.
The official project documentation at docs.pixelfed.org is the canonical reference for configuration flags, upgrade notes, and federation internals. This tutorial covers the install path; keep that page bookmarked for ongoing operations.
Why Self-Host a Federated Instagram Alternative?
Running your own Pixelfed instance rather than using a hosted service (or Instagram) delivers benefits that matter more every year:
- You own your photos and metadata. No silent algorithmic demotion, no ad-based ranking, no surprise policy change that pulls your content offline. Your posts live in a database you control and remain available as long as your instance is up.
- No ads, ever. Pixelfed has no ad system and no telemetry pipeline. A chronological timeline shows exactly what the accounts you follow posted.
- Federation reach without platform lock-in. Users on Mastodon, Mastodon instances, PeerTube, Misskey, and other Pixelfed nodes can follow and interact with your posts using the same ActivityPub protocol. You publish once, reach many networks.
- Full moderation control. You set the rules for your instance, choose which remote servers to federate with, and can defederate bad actors without waiting for a platform to act.
- Predictable flat cost. A VPS that runs a healthy Pixelfed instance costs the same whether you post once a week or three times a day. No storage tier upgrades, no bandwidth surprises.
- EU data residency. Hosting on a VPS in your jurisdiction simplifies GDPR handling because you control the full data lifecycle.
- Image quality preserved. Pixelfed does not aggressively recompress uploads the way commercial platforms do. Photographers get a platform that respects their work.
Pixelfed vs. Instagram at a Glance
| Feature | Self-Hosted Pixelfed | |
|---|---|---|
| Monthly cost | Free but ad-funded | EUR 19.99/mo VPS (flat) |
| Ads in timeline | Yes | Never |
| Algorithmic feed | Yes | No, chronological |
| Export your data | Limited | Full data export any time |
| Federation / cross-platform follow | No | Yes (ActivityPub) |
| Custom moderation | No | Yes |
| Open-source | No | Yes (AGPL) |
| Mobile apps | Official only | Official Pixelfed + many Mastodon clients |
Prerequisites
Before starting make sure you have:
- An Ubuntu 24.04 LTS VPS with root or sudo access
- A domain name (for example
pixels.example.com) with an A record pointing at the server's public IP - At least 8 GB RAM and 100 GB of free disk (12 GB RAM and 200 GB disk recommended)
- SMTP credentials for sending account verification and notification emails
- Ports 80 and 443 open on your firewall
Recommended Plan: Professional>
For a small-to-medium federated instance we recommend the Professional VPS plan:>
- 6 vCPU cores
- 12 GB RAM
- 200 GB NVMe SSD
- Unmetered bandwidth
- EUR 19.99/month>
This plan has enough headroom for PHP-FPM workers, Horizon queue processes, MariaDB, Redis, and image/video transcoding running side by side.
Connect via SSH:
ssh root@your-server-ipStep 1: Update the System
Bring the server up to date and install the build utilities we will need.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git unzip software-properties-common ca-certificates gnupg lsb-releaseIf the kernel was updated, reboot before continuing:
sudo rebootStep 2: Install PHP 8.3 and Required Extensions
Pixelfed requires PHP 8.1 or newer; we install 8.3 because it offers the best performance. Ubuntu 24.04 ships with PHP 8.3 in its default archive, but the Ondrej PPA gives access to all extension packages and future point releases.
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install -y \
php8.3 php8.3-fpm php8.3-cli php8.3-common \
php8.3-mysql php8.3-redis php8.3-gd php8.3-imagick \
php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip \
php8.3-bcmath php8.3-intl php8.3-tokenizer php8.3-exif \
php8.3-fileinfo php8.3-opcacheVerify the version:
php -vExpected output:
PHP 8.3.10 (cli) (built: ...)
Copyright (c) The PHP Group
Zend Engine v4.3.10, Copyright (c) Zend Technologies
with Zend OPcache v8.3.10, ...Tune php.ini for a media application:
sudo tee -a /etc/php/8.3/fpm/conf.d/99-pixelfed.ini > /dev/null <<EOF upload_max_filesize = 30M post_max_size = 35M memory_limit = 512M max_execution_time = 120 EOF
sudo systemctl restart php8.3-fpm
Install Composer, which resolves the PHP dependencies Pixelfed declares in composer.json:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --versionStep 3: Install MariaDB and Create the Database
sudo apt install -y mariadb-server mariadb-client
sudo mysql_secure_installationAccept the defaults and set a strong root password when prompted. Create the Pixelfed database and user:
sudo mysql -u root -pInside the MariaDB prompt:
CREATE DATABASE pixelfed CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pixelfed'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_STRONG_PASSWORD';
GRANT ALL PRIVILEGES ON pixelfed.* TO 'pixelfed'@'localhost';
FLUSH PRIVILEGES;
EXIT;Keep the password handy — you'll paste it into .env in a later step.
Step 4: Install Redis
Redis stores Pixelfed's cache, session data, and queue backlog.
sudo apt install -y redis-server
sudo sed -i 's/^supervised .*/supervised systemd/' /etc/redis/redis.conf
sudo systemctl enable --now redis-server
redis-cli pingExpected output:
PONGStep 5: Install FFmpeg and ImageMagick
FFmpeg handles short-video transcoding and ImageMagick generates image variants for every upload. Both must be present before Pixelfed will accept media uploads.
sudo apt install -y ffmpeg imagemagick jpegoptim optipng pngquant
ffmpeg -version | head -1
convert -version | head -1Expected output (versions will differ):
ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2024 the FFmpeg developers
Version: ImageMagick 6.9.12-98 Q16 ...ImageMagick ships with a restrictive default policy that blocks some formats. Open /etc/ImageMagick-6/policy.xml and make sure the PDF rights stay disabled but that PNG, JPEG, GIF, and WEBP all have rights="read|write".
Step 6: Clone Pixelfed and Install Dependencies
Create a system user so Pixelfed does not run as www-data or root, and clone the repository into /var/www/pixelfed:
sudo useradd -r -m -d /var/www/pixelfed -s /bin/bash pixelfed
sudo -u pixelfed git clone -b dev https://github.com/pixelfed/pixelfed.git /var/www/pixelfed
cd /var/www/pixelfed
sudo -u pixelfed git checkout $(git tag --sort=-creatordate | head -1)Install the PHP dependencies with Composer in production mode:
sudo -u pixelfed composer install --no-dev --optimize-autoloaderThis pulls the Laravel framework, Horizon, the ActivityPub library, and everything else declared in composer.json.
Fix ownership so the web server can read and the pixelfed user can write:
sudo chown -R pixelfed:www-data /var/www/pixelfed
sudo find /var/www/pixelfed -type f -exec chmod 0644 {} \;
sudo find /var/www/pixelfed -type d -exec chmod 0755 {} \;
sudo chmod -R ug+rwX /var/www/pixelfed/storage /var/www/pixelfed/bootstrap/cacheStep 7: Configure the .env File
Pixelfed reads its configuration from .env at the project root. Copy the example and edit it:
sudo -u pixelfed cp .env.example .env
sudo -u pixelfed php artisan key:generate
sudo -u pixelfed nano .envSet the following values. Replace pixels.example.com, the database password, and SMTP settings with your own.
APP_NAME="My Pixelfed" APP_ENV=production APP_DEBUG=false APP_URL=https://pixels.example.comDB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=pixelfed DB_USERNAME=pixelfed DB_PASSWORD=REPLACE_WITH_THE_PASSWORD_YOU_SET
REDIS_CLIENT=phpredis REDIS_SCHEME=tcp REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_PASSWORD=null
CACHE_DRIVER=redis QUEUE_DRIVER=redis SESSION_DRIVER=redis BROADCAST_DRIVER=redis
MAIL_MAILER=smtp MAIL_HOST=smtp.your-provider.com MAIL_PORT=587 [email protected] MAIL_PASSWORD=REPLACE_WITH_SMTP_PASSWORD MAIL_ENCRYPTION=tls [email protected] MAIL_FROM_NAME="${APP_NAME}"
ACTIVITY_PUB=true AP_REMOTE_FOLLOW=true AP_INBOX=true AP_OUTBOX=true AP_SHAREDINBOX=true
INSTANCE_DESCRIPTION="A friendly Pixelfed instance" OPEN_REGISTRATION=false ENFORCE_EMAIL_VERIFICATION=true PF_MAX_USERS=1000
MAX_PHOTO_SIZE=15000 MAX_ALBUM_LENGTH=4 MAX_CAPTION_LENGTH=500 IMAGE_QUALITY=80
FILESYSTEM_CLOUD=local
The ACTIVITY_PUB=true block is what turns on ActivityPub federation — leave it enabled unless you want a private, non-federating instance.
Step 8: Run Migrations and Cache Config
Apply the database schema and build Laravel's optimised caches:
cd /var/www/pixelfed
sudo -u pixelfed php artisan storage:link
sudo -u pixelfed php artisan migrate --force
sudo -u pixelfed php artisan import:cities
sudo -u pixelfed php artisan instance:actor
sudo -u pixelfed php artisan route:cache
sudo -u pixelfed php artisan view:cache
sudo -u pixelfed php artisan config:cacheExpected tail of output:
Migration table created successfully.
Migrating: 2018_08_08_230220_create_users_table
Migrated: 2018_08_08_230220_create_users_table (12.45ms)
...
Route cache cleared!
Routes cached successfully!
Configuration cache cleared!
Configuration cached successfully!Any time you later change .env, re-run php artisan config:cache for the change to take effect.
Step 9: Set Up Horizon as a Queue Worker
Horizon is Pixelfed's supervisor for Redis-backed queues. Federated deliveries, media transcoding, email notifications, and feed fan-out are all queued jobs — without Horizon running the site appears to work but nothing happens in the background.
Create a systemd unit:
sudo tee /etc/systemd/system/pixelfed-horizon.service > /dev/null <<'EOF' [Unit] Description=Pixelfed Horizon Queue Worker After=network.target mariadb.service redis-server.service[Service] Type=simple User=pixelfed Group=pixelfed WorkingDirectory=/var/www/pixelfed ExecStart=/usr/bin/php artisan horizon Restart=always RestartSec=5
[Install] WantedBy=multi-user.target EOF
sudo systemctl daemon-reload sudo systemctl enable --now pixelfed-horizon sudo systemctl status pixelfed-horizon
Expected status line:
Active: active (running) since Thu 2026-04-16 11:10:00 UTC; 5s agoPixelfed also ships a scheduler that must fire every minute. Add it to the pixelfed user's crontab:
sudo crontab -u pixelfed -eAppend:
* cd /var/www/pixelfed && /usr/bin/php artisan schedule:run >> /dev/null 2>&1Step 10: Configure Nginx and PHP-FPM
Install Nginx:
sudo apt install -y nginxCreate the virtual host:
sudo tee /etc/nginx/sites-available/pixelfed > /dev/null <<'EOF' server { listen 80; server_name pixels.example.com; root /var/www/pixelfed/public; index index.php;client_max_body_size 35M;
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; fastcgi_read_timeout 120; }
location ~ /\.(?!well-known).* { deny all; }
location /storage/ { expires 30d; add_header Cache-Control "public, immutable"; } } EOF
sudo ln -s /etc/nginx/sites-available/pixelfed /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx
Browse to http://pixels.example.com to confirm Pixelfed answers (you will see the homepage served over plain HTTP). If the domain resolves and you see the site, move to TLS.
Step 11: Enable TLS with Let's Encrypt
Certbot issues and renews a free certificate from Let's Encrypt and rewrites the Nginx virtual host to redirect HTTP to HTTPS.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d pixels.example.comFollow the prompts (agree to the ToS, opt-in or opt-out of the EFF newsletter, and choose the redirect option). Verify the renewal timer:
sudo systemctl status certbot.timerNow update APP_URL in .env to https://pixels.example.com (if not already), and rebuild config cache:
cd /var/www/pixelfed
sudo -u pixelfed php artisan config:cache
sudo systemctl restart pixelfed-horizonVisiting https://pixels.example.com should now show the Pixelfed welcome screen with a valid certificate.
Step 12: Optional — Offload Media to S3
If you expect significant uploads or want to keep the VPS disk lean, move media to S3-compatible object storage (AWS S3, Wasabi, Backblaze B2, MinIO, or Contabo Object Storage all work).
Set the cloud filesystem in .env:
FILESYSTEM_CLOUD=s3 PF_ENABLE_CLOUD=true
AWS_ACCESS_KEY_ID=REPLACE_ME AWS_SECRET_ACCESS_KEY=REPLACE_ME AWS_DEFAULT_REGION=eu-central-1 AWS_BUCKET=my-pixelfed-media AWS_URL=https://my-pixelfed-media.s3.eu-central-1.amazonaws.com AWS_ENDPOINT=https://s3.eu-central-1.amazonaws.com AWS_USE_PATH_STYLE_ENDPOINT=false
Rebuild caches and restart Horizon:
cd /var/www/pixelfed
sudo -u pixelfed php artisan config:cache
sudo systemctl restart pixelfed-horizonNew uploads will land in the bucket. For already-uploaded local media, Pixelfed ships an artisan command to migrate existing files — check the current syntax in the official docs before running it.
Step 13: Verify ActivityPub Federation
Your instance is federation-ready the moment TLS is valid and ACTIVITY_PUB=true. Confirm the WebFinger and actor endpoints respond:
curl https://pixels.example.com/.well-known/webfinger?resource=acct:[email protected] | head
curl -H "Accept: application/activity+json" https://pixels.example.com/users/admin | headBoth calls should return JSON (after you create the admin account via the signup page). From a Mastodon account on another server, paste @[email protected] into the search bar — within seconds you should see the profile appear, and a follow from there delivers a signed ActivityPub request into your Horizon queue that you can watch in sudo journalctl -u pixelfed-horizon -f.
At this point you have a fully functional, federated Pixelfed instance: sign up the first user, mark them admin from the database (or via php artisan user:admin), and start posting.
FAQ
What are the minimum server specs for a Pixelfed instance?
A small personal Pixelfed instance runs comfortably on 4 GB of RAM and 2 vCPU, but for a federated node that handles inbox deliveries from the wider fediverse and stores media for a handful of active users we recommend at least 6 vCPU, 12 GB of RAM, and 200 GB of fast NVMe storage. Media is what fills disk fastest, so plan for growth or offload to S3 from day one.
Do I need a GPU to run Pixelfed?
No. Pixelfed is a PHP application and does all of its image and short-video processing on CPU via ImageMagick and FFmpeg. A modern 6 vCPU server handles image variants (thumbnails, small, medium) and MP4 transcoding for normal posting volume with plenty of margin. GPUs come into play only if you attach a separate ML service for automated image description or content classification.
Can I migrate my Instagram account to Pixelfed?
Pixelfed can import an Instagram data export. After you request your archive from Instagram and wait for the ZIP to arrive, upload it via the account settings in your Pixelfed instance and the importer will recreate your posts with captions and original timestamps. Follower and following lists do not transfer because Instagram is not part of the fediverse, but you can publish a redirect post so existing followers know where to find you.
How does federation work in Pixelfed?
Pixelfed implements the ActivityPub protocol. When federation is enabled, your instance publishes posts, follows, and likes as signed ActivityPub messages that are delivered to remote inboxes on Mastodon, PeerTube, Pixelfed, and any other compatible fediverse server. Users on those platforms can follow your Pixelfed account and see your posts in their timelines, comment, and like, with everything flowing back to your instance through Horizon's queue workers.
Should I store media on S3 or on the local disk?
For any public instance, S3-compatible object storage is the safer long-term choice. Media grows quickly with high-resolution photos and short videos, and object storage scales independently of your VPS disk and is trivial to back up with lifecycle rules. For a single-user or small private instance where you just want something simple to operate, local disk on an NVMe-backed VPS works fine — just watch free space and take regular off-server snapshots.
Is Pixelfed compatible with Mastodon apps?
Yes, largely. Pixelfed implements a large subset of the Mastodon client API, so many Mastodon mobile apps can log in to a Pixelfed account and browse timelines, post, and follow. That said, photo-centric features such as filters, multi-image albums, and collections are best experienced through the official Pixelfed mobile apps on iOS and Android.
How do I keep my Pixelfed instance updated?
Pixelfed ships regular tagged releases. A safe upgrade sequence is: put the site into maintenance mode with php artisan down, back up the database and .env, pull the new tag from git, run composer install --no-dev --optimize-autoloader, apply php artisan migrate --force, rebuild caches with php artisan config:cache route:cache view:cache, restart Horizon with sudo systemctl restart pixelfed-horizon, and bring the site back up with php artisan up. Always read the release notes before upgrading across a minor version.
Next Steps
Now that Pixelfed is live on your VPS, consider these follow-ups:
- Run a Mastodon node alongside Pixelfed — see our guide on how to install Mastodon on Ubuntu to add microblogging to your fediverse footprint with shared TLS and a shared Redis.
- Add video with PeerTube — pair Pixelfed with PeerTube so your community can share longer video content alongside photos, all federating with the same followers.
- Set up off-server backups — back up both the MariaDB
pixelfeddatabase and the media directory (or S3 bucket) to a separate location nightly. Pixelfed is a stateful service and losing storage means losing posts. - Harden the server — enable UFW, fail2ban, and automatic security updates. Restrict SSH to key-based authentication and consider a non-standard SSH port.
- Monitor Horizon — keep an eye on queue depth at
https://pixels.example.com/horizon. A growing backlog usually means you need another worker or more Redis memory. - Join the fediverse conversation — read the project blog and release notes at docs.pixelfed.org and follow
@[email protected]from your new account to stay current on feature changes.
Need More Power for Your Fediverse Stack?>
Pixelfed instances grow with their community. If you are planning to host a public instance with hundreds of users, our higher-tier plans give you the RAM and NVMe headroom to keep Horizon snappy and media uploads fast.>
- 6+ vCPU and up to 32 GB RAM for busy instances
- NVMe storage that handles image variants without IO lag
- Unmetered bandwidth for federation traffic spikes
- EU and North American data centres for latency-sensitive audiences>
Deploy Your Pixelfed VPS Now — Plans start at EUR 19.99/month.