A self-hosted, web-based IRC client. Open a browser tab, connect to any IRC network, chat — no desktop app, no plugins, no build step. Inspired by The Lounge and IRCCloud.
- Plain HTML/CSS/JS frontend, no bundler
- Node.js backend bridging browser WebSockets to IRC over TLS
- IRCCloud-inspired UI: navy palette, active-channel highlight, colour-coded join/quit/mode/topic events, op (
@) and voice (+) prefixes in messages and userlist - TLS connection indicator — green shield when connected over SSL/TLS, red when plaintext, grey when disconnected
- Option to accept self-signed / invalid IRC server certificates (off by default)
- Real TLS handshake errors surfaced on the connect screen instead of silent disconnects
- Auto-join channels fire as soon as the IRC registration completes (no fragile polling)
- User-count badge in the chat header; own nick (with mode prefix) shown next to the input
- Multiple channels and private messages per session
- Standard IRC commands:
/join,/part,/msg,/me,/nick,/topic,/whois,/raw - Nick tab-completion, per-nick colours, unread badges
- Connection settings persisted to browser
localStorage(password is never stored) - Mountable behind a reverse proxy at any sub-path (
BASE_PATH)
npm install
npm start
Open http://localhost:3000/irc/.
Environment variables:
PORT— HTTP port (default3000)BASE_PATH— URL prefix the app is mounted under (default/irc)
A one-shot installer for Debian/Ubuntu is included. It sets up Node 22, installs the app to /opt/northernirc, generates a self-signed TLS certificate, configures nginx as a reverse proxy, and creates a systemd unit.
sudo ./setup.sh
Edit the variables at the top of setup.sh (SERVER_IP, INSTALL_DIR, APP_PORT) before running if the defaults don't match your environment.
After install:
- URL:
https://<SERVER_IP>/irc - Status:
systemctl status northernirc - Logs:
journalctl -u northernirc -f
One Node process serves static assets and a WebSocket endpoint. Each browser tab opens a WebSocket, which the server pairs with its own irc-framework client — one tab = one IRC connection. Browser ↔ server messages are typed JSON (connect, message, join, etc.); IRC events become the inverse set (connected, userlist, error, status, ...).
No database, no persistence, no auth — each WebSocket is an ephemeral session. Multi-network support and persistent sessions are on the roadmap.
See CLAUDE.md for contributor notes.
ISC — see LICENSE.
