Skip to content
Menu
Marius Serbanica – Tech Blog
  • My Tech Blog
  • About me
  • Contact Me
  • Curriculum Vitae
  • Projects
  • Current Projects List
  • Certifications
  • Home Lab
  • Self-Hosted
  • Linux Cheat Sheet
  • Linux Commands
  • Privacy Policy
  • Site Map
Marius Serbanica – Tech Blog
October 3, 2025

How I Got qwebirc Running in Docker

How I Got qwebirc Running in Docker (2025-proof, no Apache, works with Cloudflare Tunnel)

qwebirc is awesome, but it’s Python 2 + Twisted era software. On modern hosts that means:

  • you need Debian’s archived packages (buster is EOL),
  • you must run it non-root,
  • and you have to start it in a way that keeps the container alive.

Here’s exactly what I did to make it work, end-to-end.

1) Build a Python-2/Twisted image from the Debian archive

Create ~/qwebirc-docker/Dockerfile:

FROM python:2.7-slim

# buster is EOL → point apt to the archive, then install prebuilt Py2 deps
RUN sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list \
 && sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list \
 && apt-get -o Acquire::Check-Valid-Until=false update \
 && apt-get install -y --no-install-recommends \
      git ca-certificates adduser \
      python-twisted python-twisted-web \
      python-zope.interface python-constantly python-automat \
      python-hyperlink python-incremental python-openssl \
      python-autobahn python-simplejson \
 && rm -rf /var/lib/apt/lists/*

# get qwebirc
WORKDIR /opt
RUN git clone https://github.com/qwebirc/qwebirc.git

# run as non-root so qwebirc doesn't refuse to start
RUN adduser --system --home /opt/qwebirc --ingroup nogroup qwebirc \
 && chown -R qwebirc:nogroup /opt/qwebirc
USER qwebirc
WORKDIR /opt/qwebirc

EXPOSE 9090
Dockerfile

Build it:

cd ~/qwebirc-docker
sudo docker build --no-cache -t qwebirc .
Nix

2) First boot (debug mode) to prime Twisted & confirm it runs

Start a long-running shell so the container stays up:

sudo docker rm -f qwebirc 2>/dev/null || true
sudo docker run -d --name qwebirc -p 9090:9090 qwebirc sleep infinity
Nix

Prime Twisted’s dropin cache (harmless but fixes odd starts-and-stops):

sudo docker exec -u 0 qwebirc /bin/sh -lc "/usr/bin/twistd --help || true"
Nix

Create a default config and run in the foreground once (see any errors live):

sudo docker exec -it qwebirc /bin/sh -lc '\
  cp -n /opt/qwebirc/config.py.example /opt/qwebirc/config.py; \
  /usr/bin/python /opt/qwebirc/compile.py || true; \
  exec /usr/bin/python /opt/qwebirc/run.py 0.0.0.0 9090'
Nix

You’ll see a Java/minify warning — that’s fine. Open http://<docker-host-ip>:9090 to confirm the UI.

Ctrl+C to stop the foreground run.

3) Stable detached run (the bit that finally sticks)

By default qwebirc can exit after compile. Run it in the background and keep the container alive:

sudo docker rm -f qwebirc 2>/dev/null || true
sudo docker run -d --name qwebirc -p 9090:9090 qwebirc /bin/sh -lc '
  cd /opt/qwebirc
  [ -f config.py ] || cp config.py.example config.py
  /usr/bin/python compile.py || true
  /usr/bin/python run.py 0.0.0.0 9090 &
  tail -f /dev/null
'
Nix

Check:

sudo docker ps --filter name=qwebirc
sudo docker logs qwebirc
curl -I http://<docker-host-ip>:9090/
Nix

4) Editing config (three easy ways)

A) Quick copy in/out

sudo docker cp qwebirc:/opt/qwebirc/config.py ~/qwebirc-docker/config.py
nano ~/qwebirc-docker/config.py
sudo docker cp ~/qwebirc-docker/config.py qwebirc:/opt/qwebirc/config.py
sudo docker restart qwebirc
Nix

B) Bind-mount (best for ongoing edits)

mkdir -p ~/qwebirc-docker/config
sudo docker run --rm -v ~/qwebirc-docker/config:/mnt qwebirc \
  /bin/sh -lc 'cp -n /opt/qwebirc/config.py.example /mnt/config.py'

# edit on host
nano ~/qwebirc-docker/config/config.py

# run with the mounted config
sudo docker rm -f qwebirc 2>/dev/null || true
sudo docker run -d --name qwebirc -p 9090:9090 \
  -v ~/qwebirc-docker/config/config.py:/opt/qwebirc/config.py:ro \
  qwebirc /bin/sh -lc '
    cd /opt/qwebirc
    /usr/bin/python compile.py || true
    /usr/bin/python run.py 0.0.0.0 9090 &
    tail -f /dev/null
  '
Nix

C) Edit inside the container

sudo docker exec -it qwebirc /bin/sh
# (install nano temporarily if you really want)
# sudo docker exec -u 0 qwebirc sh -lc 'apt-get -o Acquire::Check-Valid-Until=false update && apt-get install -y nano'
nano /opt/qwebirc/config.py
sudo docker restart qwebirc
Nix

What to set in config.py: your IRC host/ports (6667/6697), network name/branding, optional WEBIRC password to get real client IPs on the IRCd, and the admin engine allowlist.

And there we have it! qwebirc running in a docker container like a boss!

Troubleshooting gotchas (the ones that bit me)

  • ZoPe/Twisted “missing”: Use /usr/bin/python (system Python) because apt installs Py2 modules under /usr/lib/python2.7/dist-packages.
  • “Refusing to run as root”: run as a non-root user (the Dockerfile creates qwebirc). Alternatively --user 1000:1000.
  • Container exits right away: start run.py in the background and keep PID1 alive with tail -f /dev/null (or use a tiny entrypoint script with exec …).
  • Entry script “exec format error”: your script probably had CRLF line endings; fix with sed -i 's/\r$//' entrypoint.sh.
  • Debian apt 404s: buster is EOL. Use archive.debian.org + -o Acquire::Check-Valid-Until=false.
  • Java warnings: harmless. They only affect JS/CSS minification during compile.py.

Final one-liner I’m using to run it

sudo docker rm -f qwebirc 2>/dev/null || true
sudo docker run -d --name qwebirc -p 9090:9090 \
  -v ~/qwebirc-docker/config/config.py:/opt/qwebirc/config.py:ro \
  qwebirc /bin/sh -lc '
    cd /opt/qwebirc
    /usr/bin/python compile.py || true
    /usr/bin/python run.py 0.0.0.0 9090 &
    tail -f /dev/null
  '
Nix

This keeps it rock-solid, easy to edit, and ready to sit behind your Cloudflare Tunnel.

Share on Social Media
x facebook linkedin

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Join my LinkedIn Network.

Recent Posts

  • How I Got qwebirc Running in Docker
  • PiVPN / WireGuard Complete Setup
  • Automation – How to Automatically Clean Up Unused Docker Images
  • PHP-Fusion 7 CMS fully dockerized!
  • Kubernetes cluster. Why and how

Archives

  • October 2025
  • July 2025
  • June 2025
  • February 2025
  • January 2025
  • October 2024
  • May 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023

Categories

  • How-To
  • Tech Industry
  • Tech, but personal
  • Tutorials

Recent Comments

  1. IRC Lamer on Installing GNU-World on ircu2
  2. severus2231 on Transforming a Mini PC into a Powerful Home Network Hub / Router/ Firewall with OPNsense
  3. admin on Mounting a NAS (Network Attached Storage) device on Linux
  4. abL on Mounting a NAS (Network Attached Storage) device on Linux
  5. Alin R on Cleaning up your Linux OS.
Social Media
Find me on social media
Facebook Twitter Instagram LinkedIn

©2025 Marius Serbanica – Tech Blog