low-key

IRC in 2026: The Soju Way

IRC has been a mainstay of my communications network for a very long time now. I’ve always been tweaking the stack that makes it possible though, trying to arrive at something that offers a pleasant and continuous experience across all of my devices.

I’ve tried WeeChat on a VPS, acting as a relay that my other devices connect to, run ZNC and pounce as bouncers and just straight up connected to networks independently from each device with no message history. There was however always some part of the experience that wouldn’t hold up to the ideal I was pursuing.

Soju is a bouncer with a vibrant ecosystem of clients that has finally let me attain the goal I’d been seeking all these years. A pleasant and continuous IRC experience across every single device, with native clients everywhere.

Disclaimer: This is NOT a tutorial, though you can maybe find some helpful pointers in here. I’m writing this so that I can come back and see just what it is I did to set this up and why.

On the Server

Soju is the centerpiece of this setup and runs on a VPS as a Docker container. The container manifests for soju are hosted at emersion/soju-containers. I adapted the compose.yaml from over there.

 1configs:
 2  soju:
 3    file: config
 4
 5services:
 6  soju:
 7    image: codeberg.org/emersion/soju
 8    restart: unless-stopped
 9    ports:
10      - "127:0.0.1:6667:6667"
11      - "127.0.0.1:3030:3030"
12    configs:
13      - source: soju
14        target: /soju-config
15    volumes:
16      - "./db:/db"
17      - "./uploads:/uploads"

This isn’t my first time trying out Soju but what makes this attempt my best one so far is how TLS is handled. With Caddy. Automatic renewal and dead simple configuration.

#Self-Hosting