I use ERC in Emacs as my IRC client. An extremely common issue I have is that when my laptop disconnects from the IRC server (due to the laptop going to sleep or due to it losing a network connection), the IRC communication that happened during that time is lost. People had this issue since the dawn of time, and a solution exists: IRC bouncers. You run this on a dedicated server, and it acts as a proxy between the real IRC server and your machine with its flaky network. When you connect to the bouncer, it spews everything you missed at you. I set up a bouncer yesterday, and it was surprisingly painful. This post summarizes the procedure.

I'm using the ZNC bouncer. There are others, and I'm not using this one for any particular reason. I installed it from Debian/sid, so I'm running version 1.4-1+b2. Debian/wheezy has a much older package (0.206-2); I don't know if it would be hugely problematic to use this older ZNC.

ZNC refuses to run as root, so I made an arbitrary user for it: zncman. The procedure you're supposed to follow is

  • use the znc binary to interactively generate a configuration
  • use interactive IRC commands to configure servers and such

This is a pain in the butt. A slightly easier method:

  • log in as zncman
  • use the interactive configurator (znc --makeconf) to generate an arbitrary configuration
  • kill znc
  • edit the configuration
  • restart znc

The configuration syntax is nominally described at http://en.znc.in/wiki/Configuration, but this document is poor at best. This is probably a big reason why upstream doesn't recommend editing this file. It's much easier, though. Here's my ~/.znc/configs/znc.conf file. It's pretty clear what needs to be customized:

// Do NOT edit this file while ZNC is running!
// Use webadmin or *controlpanel instead.
// Altering this file by hand will forfeit all support.
// But if you feel risky, you might want to read help on /znc saveconfig and /znc rehash.
// Also check http://en.znc.in/wiki/Configuration

AnonIPLimit = 10
ConnectDelay = 5
#LoadModule = webadmin
LoadModule = fail2ban
MaxBufferSize = 500
ProtectWebSessions = true
ServerThrottle = 30
Skin = _default_
StatusPrefix = *
Version = 1.4

<Listener listener0>
        AllowIRC = true
#       AllowWeb = true
        IPv4 = true
        IPv6 = true
        Port = 5555
        SSL = false

<User dima>
        Admin = true
        Allow = *
        AltNick = dima_
        AppendTimestamp = true
        AutoClearChanBuffer = true
        Buffer = 50000
        ChanModes = +stn
        DenyLoadMod = false
        DenySetBindHost = false
        Ident = dima
        JoinTries = 10
#       LoadModule = webadmin
        MaxJoins = 0
        MaxNetworks = 1
        MultiClients = true
        Nick = dima
        PrependTimestamp = true
        QuitMsg = ZNC - http://znc.in
        RealName = Got ZNC?
        TimestampFormat = [%H:%M:%S]

        <Network oftc>
                Nick = dima5
                FloodBurst = 4
                FloodRate = 1.00
                IRCConnectEnabled = true
                Server = irc.oftc.net 6667

        <Network freenode>
                Nick = dima5
                FloodBurst = 4
                FloodRate = 1.00
                IRCConnectEnabled = true
                Server = irc.freenode.net 6667

        <Pass password>
                Hash = xxxxx
                Method = yyyyy
                Salt = zzzzz

So with that file, ZNC runs an IRC server on port 5555 and the ZNC user is called dima. ZNC itself talks to oftc and freenode using the Nick dima5 for both. The Debian package for ZNC is not currently integrated into the init system, so you start the daemon with just znc. Clearly this doesn't happen on every boot, and you have to set that up yourself. I haven't bothered yet, but it'll come up at some point.

When logging into the ZNC IRC server, you have to be very clean on what is the ZNC nick and what is the IRC server nick. Same with passwords. On top of that, the ZNC password contains the ZNC nick, the target server and the ZNC password. So in my case I start up ERC thusly:

(erc :server "my_znc_server.com" :port 5555 :nick "dima5" :password "dima/freenode:zncpassword")
(erc :server "my_znc_server.com" :port 5555 :nick "dima5" :password "dima/oftc:zncpassword")

This all does the right thing. Currently there's an issue in that erc-autojoin-channels-alist now sees both the freenode and oftc connection as the same one (since it uses the hostname to differentiate, and the hostname is now my_znc_server.com for both). Otherwise, this works fine.