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

  1. Wait for all containers to reach healthy status:

    docker compose ps
  2. Create the first admin user:

    docker compose exec php bin/console mbin:user:create admin [email protected] --admin

    You’ll be prompted for a password.

  3. Visit http://your-server-ip:8080 (or your domain if DNS is configured). Log in with the admin credentials you just created.

  4. 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

VariablePurposeRequired
KBIN_DOMAINPublic domain for your instanceYes
APP_SECRETApplication encryption keyYes
DATABASE_URLPostgreSQL connection stringYes
REDIS_DNSValkey/Redis connectionYes
MESSENGER_TRANSPORT_DSNRabbitMQ connection for async jobsYes
MAILER_DSNSMTP settings for emailYes (for registration)
KBIN_TITLEInstance display nameNo (defaults to “Mbin”)
KBIN_CONTACT_EMAILAdmin contact shown to usersRecommended
SERVER_NAMECaddy server configurationYes

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:

VolumeContainsPriority
postgres_dataAll content, users, votes, settingsCritical
mediaUser-uploaded images and filesImportant
rabbitmq_dataPending message queueLow (regenerates)
valkey_dataCache dataLow (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

ComponentRAMCPUDisk
PHP (app)512 MB - 1 GB1 core2 GB
Messenger (per replica)256 MB0.5 coreMinimal
PostgreSQL512 MB - 1 GB0.5 core5+ GB (grows)
RabbitMQ256 MB0.25 core1 GB
Valkey128 MB0.1 core500 MB
Total (minimum)~2 GB2 cores10 GB
Recommended4 GB4 cores20 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.

Comments