Most homelabs end up with a Discord server, a Slack workspace, or a family group chat scattered across three different apps. If you already run Proxmox VE for your VMs and containers, there's a decent chance you'd rather keep your chat data on your own hardware too. Rocket.Chat is an open-source, self-hosted alternative to Slack or Microsoft Teams, and it runs comfortably inside a single LXC container on Proxmox VE.

This guide walks you through the whole process: creating the container, installing Docker inside it, and deploying Rocket.Chat with its MongoDB database. You don't need any prior Docker experience, and every command is explained as you go.

What You Will Learn

  • What Rocket.Chat is and why homelab users and small teams run it themselves
  • How to create a Debian-based LXC container sized correctly for Rocket.Chat
  • How to install Docker Engine inside an unprivileged LXC container
  • How to deploy Rocket.Chat and MongoDB using Docker Compose
  • How to complete the first-run admin setup and connect from your network
  • How to fix the errors people run into most often during this install

What Is This Feature?

Rocket.Chat is a self-hosted team messaging platform. Think channels, direct messages, file sharing, and video calls, similar to Slack, except the entire application and its database live on a server you control. There's no per-user monthly fee and no third party reading your message history.

To run it, we're going to lean on two things Proxmox VE already gives you. The first is LXC (Linux Containers), a lightweight way to run an isolated Linux environment that shares the host's kernel instead of virtualizing a whole machine. Containers start in seconds and use a fraction of the RAM a full VM would need for the same job. The second is Docker, a tool that packages an application together with everything it needs to run into a single, repeatable unit called a container image. Rocket.Chat's developers publish official Docker images, which means you get the exact software they tested, not a version you pieced together from a wiki page.

Yes, this means you'll have Docker containers running inside an LXC container. That sounds odd the first time you hear it, but it's a well-worn pattern in the Proxmox community and works reliably as long as the LXC container is unprivileged with nesting enabled, which we'll set up in Step 1.

Why Would You Use It?

If you're already self-hosting things like Nextcloud or Vaultwarden, Rocket.Chat is a natural next step for keeping team or family communication in-house as well. A few common reasons people set it up:

  • Coordinating a small business or side project without paying per-seat SaaS pricing
  • Running a private community or Discord alternative you fully control
  • Integrating chat notifications from home automation, monitoring tools, or CI pipelines through its webhook and bot support
  • Keeping sensitive conversations off third-party servers entirely

Honestly, if you just want a quick group chat for two people, this is overkill — a group chat app on your phone will do. Rocket.Chat earns its keep once you have a handful of users, channels, and integrations to manage.

Prerequisites

Before you start, make sure you have:

  • Proxmox VE 8.x or 9.x installed and reachable from your browser
  • At least 4 GB of free RAM and 20 GB of free storage on the node (Rocket.Chat plus MongoDB is heavier than most self-hosted apps)
  • A Debian 13 (or Debian 12) LXC template downloaded, or access to download one from the Proxmox template list
  • Basic comfort typing commands in a Linux shell — you'll copy and paste most of them anyway
  • Root or an account with permission to create containers on the node

Step-by-Step Tutorial

Step 1: Create the LXC container

Log in to the Proxmox VE shell (or use the web GUI's Create CT wizard) and create an unprivileged container. Nesting has to be enabled, since it lets Docker run its own containers and namespaces inside our LXC container.

pct create 220 local:vztmpl/debian-13-standard_13.1-1_amd64.tar.zst \
  --hostname rocketchat \
  --cores 4 \
  --memory 4096 \
  --swap 512 \
  --rootfs local-lvm:16 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --unprivileged 1 \
  --features nesting=1,keyctl=1
pct start 220

Adjust the template filename to match whatever version you actually downloaded — check with pveam list local if you're not sure what's available. The --features nesting=1,keyctl=1 flag is the part people forget, and skipping it is the single most common reason Docker refuses to start in the next step.

Step 2: Log in and update the container

Open a console to the new container from the Proxmox GUI, or SSH in once it has an IP address.

pct enter 220
apt update && apt full-upgrade -y
apt install -y ca-certificates curl gnupg

Running the update before installing anything else avoids dependency conflicts later, and it's a habit worth keeping for every container you spin up.

Step 3: Install Docker Engine

We'll add Docker's official APT repository rather than using the version bundled with Debian, since it tends to be several releases behind.

install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Once that finishes, confirm Docker is actually working before moving on:

docker run hello-world

If that prints a friendly welcome message, nesting is working correctly and you're clear to continue. If it hangs or errors out, jump ahead to the Troubleshooting section — don't waste time deploying Rocket.Chat on top of a broken Docker install.

Step 4: Write the Docker Compose file

Create a folder to hold Rocket.Chat's configuration and data, then write the compose file.

mkdir -p /opt/rocketchat && cd /opt/rocketchat
nano docker-compose.yml

Paste in the following. This is the same layout Rocket.Chat documents officially: one container for the app, one for MongoDB, and a small helper container that initializes MongoDB's replica set (Rocket.Chat needs this to watch the database for changes in real time).

services:
  rocketchat:
    image: rocket.chat:latest
    restart: unless-stopped
    volumes:
      - ./uploads:/app/uploads
    environment:
      - PORT=3000
      - ROOT_URL=http://your-server-ip:3000
      - MONGO_URL=mongodb://mongodb:27017/rocketchat?replicaSet=rs0
      - MONGO_OPLOG_URL=mongodb://mongodb:27017/local?replicaSet=rs0
    depends_on:
      - mongodb
    ports:
      - 3000:3000

  mongodb:
    image: mongo:6.0
    restart: unless-stopped
    volumes:
      - ./data/db:/data/db
    command: mongod --oplogSize 128 --replSet rs0

  mongo-init-replica:
    image: mongo:6.0
    command: >
      mongosh mongodb://mongodb:27017 --eval
      '
      rs.initiate({
        _id: "rs0",
        members: [ { _id: 0, host: "mongodb:27017" } ]
      })
      '
    depends_on:
      - mongodb

Replace your-server-ip in the ROOT_URL line with the container's actual IP address or a domain name if you're putting a reverse proxy in front of it later. Rocket.Chat uses this value to build links inside emails and notifications, so it's worth getting right from the start.

Step 5: Start the stack

docker compose up -d

Give it a minute or two on first boot — MongoDB has to initialize its replica set and Rocket.Chat has to run its own database migrations before the web interface responds. You can watch progress with:

docker compose logs -f rocketchat

Once you see a line mentioning the app is listening on port 3000, it's ready.

Step 6: Finish setup in the browser

Open http://<container-ip>:3000 in a browser on the same network. Rocket.Chat's setup wizard will ask you to create the first admin account, name your organization, and pick which optional features to enable. None of this is permanent — you can change all of it later from the admin panel.

Commands Explained

CommandWhat it does
pct create ... --features nesting=1,keyctl=1Creates the container and allows it to run its own container runtime (Docker) inside it
docker run hello-worldA tiny test image that confirms Docker can actually pull and run containers before you trust it with something bigger
docker compose up -dReads docker-compose.yml and starts every service it defines in the background (-d for detached)
docker compose logs -f rocketchatStreams live log output from just the Rocket.Chat container, useful for watching startup progress or diagnosing errors
mongod --oplogSize 128 --replSet rs0Starts MongoDB with a replica set named rs0, which Rocket.Chat requires to receive real-time database updates

Common Errors

ErrorCause
docker: Error response from daemon: could not select device driverNesting wasn't enabled on the LXC container, or the container is privileged when it shouldn't need to be
MongoServerSelectionError: connect ECONNREFUSEDRocket.Chat started before MongoDB finished initializing its replica set — usually resolves itself within a minute, or means the mongo-init-replica step never ran
Page loads but login redirects in a loopThe ROOT_URL value doesn't match the address you're actually browsing to
Container has no internet access during apt updateThe bridge or DHCP settings on --net0 aren't matching your actual network — see the general Proxmox VE networking troubleshooting guide

Troubleshooting

If docker run hello-world fails inside the container, stop and go back to the container's options in the Proxmox GUI. Check the Features tab and confirm Nesting is ticked. If you created the container with the CLI, double check the exact flag with:

pct config 220 | grep features

You should see nesting=1 in the output. If it's missing, you can add it without recreating the container:

pct set 220 --features nesting=1,keyctl=1
pct reboot 220

If the web interface never loads at all, check that the container actually got an IP address and that port 3000 isn't already used by something else on that container:

ip a
ss -tulpn | grep 3000

If MongoDB keeps restarting, it's almost always a permissions problem on the ./data/db volume folder. Unprivileged containers map root inside the container to an unprivileged UID on the host, and MongoDB's official image is picky about file ownership. Deleting the folder and letting Docker recreate it usually clears this up, assuming you haven't put real data in there yet.

Best Practices

  • Put a reverse proxy (Nginx Proxy Manager or Caddy) in front of Rocket.Chat and get it on HTTPS before inviting anyone else to use it — chat credentials shouldn't travel in plain text
  • Back up the /opt/rocketchat/data/db and /opt/rocketchat/uploads folders, not just the container itself — that's where your actual messages and files live
  • Set resource limits on the LXC container (CPU and memory) once you know your real usage, rather than leaving it unbounded on a shared node
  • Pin the Rocket.Chat image to a specific version tag instead of latest once you're running it for real — this stops an unexpected upgrade from breaking your setup overnight
  • Snapshot the container before every Rocket.Chat or MongoDB version upgrade

Frequently Asked Questions

Can I run Rocket.Chat without Docker, directly on the LXC container?

Yes, but you'd be building from source with Meteor and managing MongoDB manually, which is significantly more work to maintain. Docker is the officially supported path and the one this guide follows.

How much RAM does Rocket.Chat actually need for a handful of users?

4 GB is comfortable for a small team of five to twenty people. MongoDB is the bigger consumer of the two services, not Rocket.Chat itself.

Can I use an existing MongoDB server instead of running one in this container?

Yes — just point MONGO_URL and MONGO_OPLOG_URL at your external database and remove the mongodb and mongo-init-replica services from the compose file.

Does Rocket.Chat support video calls out of the box?

Basic one-to-one video calling works out of the box using WebRTC. Group video calls require connecting an external Jitsi server, which is a separate setup.

Is this safe to expose directly to the internet?

Not without a reverse proxy handling TLS and, ideally, a firewall rule limiting which IPs can reach port 3000 directly. Treat it the same way you'd treat any other self-hosted login page.

What happens if I reboot the LXC container?

Docker's restart: unless-stopped policy in the compose file brings both containers back up automatically once the LXC container finishes booting. You don't need to run docker compose up again manually.

Conclusion

You now have a working Rocket.Chat instance running entirely on hardware you control, tucked inside a single lightweight LXC container. From here, the natural next steps are putting it behind a reverse proxy with a real domain and HTTPS, inviting your team or household, and exploring the admin panel's integrations if you want chat notifications from your other homelab services. The container itself uses barely any resources at idle, so it's a reasonable thing to leave running alongside everything else on your node.