How to Self-Host Mbin (Kbin Fork) with Docker
What Is Mbin?
Mbin is a federated content aggregation and discussion platform — think Reddit but decentralized. Users create magazines (equivalent to subreddits), post links and articles, comment in threads, and vote on content. It also supports microblogging (similar to Mastodon), so your instance handles both long-form link aggregation and short-form status posts.
Mbin is a community fork of Kbin, created after Kbin’s original developer became less active in late 2023. Mbin is now the actively maintained version with regular releases. It federates via ActivityPub, meaning your instance communicates with Lemmy, Mastodon, Pixelfed, and other fediverse platforms.
Official site: joinmbin.org
Prerequisites
- A Linux server (Ubuntu 22.04+ or Debian 12+ recommended)
- Docker and Docker Compose installed (guide)
- 4 GB of RAM minimum (6 GB recommended)
- 10 GB of free disk space (plus growth for media uploads)
- A domain name with DNS pointed to your server
- SMTP credentials for email delivery (user registration, notifications)
Docker Compose Configuration
Create a project directory and add a docker-compose.yml:
version: "3.8"
services:
php:
image: ghcr.io/mbinorg/mbin:v1.9.1
restart: unless-stopped
environment:
- SERVER_NAME=:80 # Use :80 behind reverse proxy, or your-domain.com for direct
- KBIN_DOMAIN=${KBIN_DOMAIN}
- KBIN_TITLE=${KBIN_TITLE:-Mbin}
- KBIN_CONTACT_EMAIL=${KBIN_CONTACT_EMAIL}
- KBIN_STORAGE_URL=https://${KBIN_DOMAIN}/media
- APP_SECRET=${APP_SECRET}
- APP_ENV=prod
- DATABASE_URL=postgresql://mbin:${POSTGRES_PASSWORD}@postgres:5432/mbin?serverVersion=16&charset=utf8
- REDIS_DNS=redis://${VALKEY_PASSWORD}@valkey:6379
- MESSENGER_TRANSPORT_DSN=amqp://mbin:${RABBITMQ_PASSWORD}@rabbitmq:5672/%2f/messages
- MAILER_DSN=smtp://${SMTP_USER}:${SMTP_PASSWORD}@${SMTP_HOST}:${SMTP_PORT}
- CADDY_MERCURE_JWT_SECRET=${MERCURE_JWT_SECRET}
- MBIN_USER=${MBIN_USER:-1000:1000}
volumes:
- media:/srv/app/public/media
- caddy_data:/data
- caddy_config:/config
ports:
- "8080:80"
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
valkey:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
messenger:
image: ghcr.io/mbinorg/mbin:v1.9.1
restart: unless-stopped
command: ["php", "bin/console", "messenger:consume", "async", "--time-limit=3600", "-vv"]
environment:
- APP_ENV=prod
- APP_SECRET=${APP_SECRET}
- DATABASE_URL=postgresql://mbin:${POSTGRES_PASSWORD}@postgres:5432/mbin?serverVersion=16&charset=utf8
- REDIS_DNS=redis://${VALKEY_PASSWORD}@valkey:6379
- MESSENGER_TRANSPORT_DSN=amqp://mbin:${RABBITMQ_PASSWORD}@rabbitmq:5672/%2f/messages
- KBIN_DOMAIN=${KBIN_DOMAIN}
- MBIN_USER=${MBIN_USER:-1000:1000}
depends_on:
- php
- rabbitmq
- valkey
deploy:
replicas: 2 # Scale up for busier instances
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_DB=mbin
- POSTGRES_USER=mbin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mbin"]
interval: 10s
timeout: 5s
retries: 5
rabbitmq:
image: rabbitmq:3.13-management-alpine
restart: unless-stopped
environment:
- RABBITMQ_DEFAULT_USER=mbin
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD}
volumes:
- rabbitmq_data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 10s
timeout: 5s
retries: 5
valkey:
image: valkey/valkey:8.1-alpine
restart: unless-stopped
command: ["valkey-server", "--requirepass", "${VALKEY_PASSWORD}", "--save", "60", "1"]
volumes:
- valkey_data:/data
volumes:
media:
caddy_data:
caddy_config:
postgres_data:
rabbitmq_data:
valkey_data:
Create a .env file alongside:
# Domain and identity
KBIN_DOMAIN=mbin.yourdomain.com # CHANGE: your actual domain
KBIN_TITLE=My Mbin Instance # Your instance name
KBIN_CONTACT_EMAIL=[email protected] # CHANGE: admin contact
# Security secrets — generate with: openssl rand -hex 32
APP_SECRET=CHANGE_ME_GENERATE_RANDOM_HEX_64_CHARS
MERCURE_JWT_SECRET=CHANGE_ME_GENERATE_RANDOM_HEX_64_CHARS
# Database
POSTGRES_PASSWORD=CHANGE_ME_STRONG_DB_PASSWORD
# Message queue
RABBITMQ_PASSWORD=CHANGE_ME_STRONG_RABBITMQ_PASSWORD
# Cache
VALKEY_PASSWORD=CHANGE_ME_STRONG_VALKEY_PASSWORD
# SMTP — required for user registration and notifications
SMTP_HOST=smtp.yourdomain.com # CHANGE: your SMTP server
SMTP_PORT=587
SMTP_USER=[email protected] # CHANGE: your SMTP username
SMTP_PASSWORD=CHANGE_ME_SMTP_PASSWORD # CHANGE: your SMTP password
# Container user (match your host user for file permissions)
MBIN_USER=1000:1000
Start the stack:
docker compose up -d
Initial Setup
-
Wait for all containers to reach healthy status:
docker compose ps -
Create the first admin user:
docker compose exec php bin/console mbin:user:create admin [email protected] --adminYou’ll be prompted for a password.
-
Visit
http://your-server-ip:8080(or your domain if DNS is configured). Log in with the admin credentials you just created. -
Navigate to the admin panel to configure:
- Instance name and description
- Registration policy (open, approval, or closed)
- Federation settings
- Content policies
Configuration
Key Environment Variables
| Variable | Purpose | Required |
|---|---|---|
KBIN_DOMAIN | Public domain for your instance | Yes |
APP_SECRET | Application encryption key | Yes |
DATABASE_URL | PostgreSQL connection string | Yes |
REDIS_DNS | Valkey/Redis connection | Yes |
MESSENGER_TRANSPORT_DSN | RabbitMQ connection for async jobs | Yes |
MAILER_DSN | SMTP settings for email | Yes (for registration) |
KBIN_TITLE | Instance display name | No (defaults to “Mbin”) |
KBIN_CONTACT_EMAIL | Admin contact shown to users | Recommended |
SERVER_NAME | Caddy server configuration | Yes |
Federation Settings
Mbin federates automatically via ActivityPub. Your instance will:
- Discover other Mbin and Lemmy instances when users subscribe to remote magazines
- Receive posts and comments from federated instances
- Allow Mastodon users to follow your magazines and interact with content
To defederate from problematic instances, use the admin panel under Federation > Blocked Instances.
Registration Control
Three modes available in the admin panel:
- Open — anyone can register
- Approval — registration requires admin approval
- Closed — no new registrations (invite-only or single-user)
For a community instance, start with Approval mode to prevent spam while growing organically.
Advanced Configuration
Scaling Messenger Workers
The messenger service processes background jobs: federation deliveries, notifications, and content indexing. For busy instances, increase replicas:
messenger:
deploy:
replicas: 4 # Increase for larger instances
S3 Object Storage
For media-heavy instances, offload uploads to S3-compatible storage:
# Add to .env
S3_BUCKET=your-bucket
S3_REGION=us-east-1
S3_ENDPOINT=https://s3.amazonaws.com
S3_KEY=your-access-key
S3_SECRET=your-secret-key
RabbitMQ Management
Access the RabbitMQ dashboard at http://your-server:15672 (if port exposed) with the credentials from your .env file. Monitor queue depths — if messages accumulate, add more messenger replicas.
Reverse Proxy
Mbin’s Docker image includes Caddy as a built-in web server. Behind a reverse proxy, set SERVER_NAME=:80 (as configured above) and forward traffic from your reverse proxy to port 8080.
Nginx Proxy Manager configuration:
- Domain:
mbin.yourdomain.com - Forward Hostname:
localhost(or container IP) - Forward Port:
8080 - SSL: Let’s Encrypt
See Reverse Proxy Setup for detailed configuration.
Backup
Critical volumes to back up:
| Volume | Contains | Priority |
|---|---|---|
postgres_data | All content, users, votes, settings | Critical |
media | User-uploaded images and files | Important |
rabbitmq_data | Pending message queue | Low (regenerates) |
valkey_data | Cache data | Low (regenerates) |
Database backup:
docker compose exec postgres pg_dump -U mbin mbin > mbin_backup_$(date +%Y%m%d).sql
See Backup Strategy for comprehensive backup approaches.
Troubleshooting
Federation Not Working
Symptom: Remote magazines show no content, or your posts don’t appear on other instances. Fix: Check that your domain is publicly accessible with valid SSL. Federation requires HTTPS. Verify DNS resolves correctly and port 443 is reachable. Check messenger container logs for delivery failures:
docker compose logs messenger --tail 50
Registration Emails Not Sending
Symptom: Users register but never receive confirmation emails.
Fix: Verify SMTP credentials in .env. Test with:
docker compose exec php bin/console mbin:user:verify [email protected]
Check that your SMTP provider isn’t blocking sends. Common issue: Gmail requires app-specific passwords with 2FA enabled.
High Memory Usage
Symptom: Server running out of RAM, containers restarting.
Fix: Reduce messenger replicas to 1. Check if RabbitMQ queue is growing unbounded (stuck jobs). PostgreSQL may need tuning for shared_buffers on constrained systems. Consider adding swap space.
Database Migration Errors on Upgrade
Symptom: Container fails to start after pulling a new image version. Fix: Run migrations manually:
docker compose exec php bin/console doctrine:migrations:migrate --no-interaction
Media Uploads Failing
Symptom: Image uploads return errors or show broken thumbnails.
Fix: Check volume permissions. The MBIN_USER environment variable must match the UID:GID that owns the media directory. Fix with:
docker compose exec php chown -R 1000:1000 /srv/app/public/media
Resource Requirements
| Component | RAM | CPU | Disk |
|---|---|---|---|
| PHP (app) | 512 MB - 1 GB | 1 core | 2 GB |
| Messenger (per replica) | 256 MB | 0.5 core | Minimal |
| PostgreSQL | 512 MB - 1 GB | 0.5 core | 5+ GB (grows) |
| RabbitMQ | 256 MB | 0.25 core | 1 GB |
| Valkey | 128 MB | 0.1 core | 500 MB |
| Total (minimum) | ~2 GB | 2 cores | 10 GB |
| Recommended | 4 GB | 4 cores | 20 GB |
- RAM: 2 GB minimum with 1 messenger replica. 4 GB recommended for comfortable operation with 2+ messengers.
- CPU: 2 cores minimum. Federation processing and image handling benefit from additional cores.
- Disk: 10 GB base. Media uploads grow quickly on active instances — plan for 50+ GB or use S3 storage.
Verdict
Mbin is the most feature-complete self-hosted Reddit alternative available. The combination of link aggregation, threaded comments, microblogging, and ActivityPub federation makes it uniquely versatile. The setup is more complex than simpler fediverse platforms like GoToSocial — 5 containers versus 1 — but the result is a full-featured community platform.
The main drawback is resource requirements. A 4 GB VPS is the practical minimum, which is more than most self-hosted apps demand. If you just want federated link aggregation without the microblogging component, Lemmy is lighter. If you only want microblogging, Mastodon or GoToSocial are simpler options.
For building a Reddit-style community that participates in the broader fediverse, Mbin is the right choice.
FAQ
Is Mbin the same as Kbin?
Mbin is a community fork of Kbin with active development. Kbin’s original developer became less active in late 2023. Mbin receives regular updates and is the recommended deployment for new instances.
Can Lemmy users interact with my Mbin instance?
Yes. ActivityPub federation means Lemmy communities can subscribe to Mbin magazines and vice versa. Comments and votes flow between platforms.
How many users can Mbin handle?
On a 4 GB VPS with 2 messenger replicas, expect comfortable performance for 100-500 registered users with 20-50 concurrent. Scale up PostgreSQL, add messenger replicas, and use S3 storage for larger instances.
Do I need SMTP for a single-user instance?
Technically no — you can create users via CLI and skip email verification. But SMTP is strongly recommended for password resets and notifications.
Can I customize the UI?
Mbin supports custom CSS through the admin panel. Theme customization is possible but limited compared to platforms with full theme engines.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments