ZNHOO Whatever you are, be a good one!


  1. ABCs
  2. Style
  3. Security
  4. server_default
  5. Server
  6. NickServ
  7. Identification
    1. Manually Identification
    2. SASL plain scheme
    3. SASL external scheme
      1. irc.pem
      2. Nick and Certificate Association
      3. Renew certificate
  8. Unaffilicated Cloak
  9. proxy - Tor
  10. Relay
    1. Weechat Relay
    2. Nginx Reverse Proxy
    3. Direct Relay
    4. Connect to Relay
  11. Systemd user Unit
  12. Troubleshooting

Simple Authentication and Security Layer (SASL) is a method that simplify identification to NickServ as the first step after connecting to IRC servers, before anything else happens. To connect to freenode using Tor, SASL is required. In this post, I will take Weechat and Freenode for example.


  1. Conncet through WebChat on browser.

    Just fill in nick and channel names on freenode webchat. HTTPS (ssl) establish a secure connection IRC server compared to HTTP.

    By Webchat, we cannot require other services.

  2. Connect in the clear.

    Similar to Webchat, the clear way connects directly without proxy or nick reservation (by NickServ).

    Should provide IRC hostname (chat.freenode.net) and port (6697) which are implicit in Webchat (webchat.freenode.net and 80).

    After connection, join a channel to talk.

  3. Connect through Clients (Weechat Irssi etc.).
  4. Nickserv - register/identify

    Reserve and identify your nick name.

  5. SASL authentication

    Automatic identification on connection by SASL. Weechat SASL supports different authentication mechanisms:

    • plain: plain text file password (default)
    • ecdsa-nist256p-challenge: challenge with public/private key
    • external: self-signed SSL certificate
  6. Connect with proxy (i.e. Tor).
  7. BNC (i.e. ZNC), or Weechat relay protocol.

    Weechat relay supports IRC protocol as well (to be compatibile with other IRC clients).


jim@laptop ~ $ weechat
  1. iset

    /script search iset
    Alt + i

    /save after changes. WeeChat also saves your up-to-date configuration any time you exit the program.

    Script iset is decpreated and please use built-in script fset instead.

  2. Some specific server commands (i.e. /ns) are not standard and cannot be recoginized by IRC client.

    irc.network.send_unknown_commands on
  3. This will close the buffer (or called tab) immediately when parting a channel.

    irc.look.part_closes_buffer on
  4. By default, server and core buffers are merged together. Use Ctrl+x to tear apart or:

    irc.look.server_buffer independent


  1. SSL

    irc.server_default.ssl on
    irc.server_default.ssl_verify on
    irc.server_default.sasl_mechanism external

    The client verify the server certificate and also the server needs to verify the client certificate - mutual authentication!

  2. Turn off ctcp to prevent others from querying IRC client information.

    *ctcp*  ""
    *ctcp* off
  3. Message

    irc.server_default.msg_part ""
    irc.server_default.msg_quit ""


Some extra optional default server arguments.

irc.server_default.nicks ""
irc.server_default.username ""
irc.server_default.realname ""


/server add freenode chat.freenode.net/6697 -ssl
/set irc.server.freenode.nicks "username"
/connect freenode

Check server_default section of ~/.config/weechat/irc.conf. Common default server options can be set here (i.e. irc.server_default.ssl).


NickServ allows users to register nicks on IRC servers. Different IRC servers support different set of NickServ commands. We can check by /msg nickserv help beforehand. Make sure you are connected to IRC server with your desired nick by /nick new-nick command.

Don't execute the following commands in a channel tab, otherwise sensitive information (i.e. password) might be disposed and sniffed. All IRC commands are case-insensitive.

Take Freenode for example:

  1. /msg NickServ REGISTER <password> youremail@example.com

    In Weechat, the pasword youremail@example.com part will be displayed as asterisks. But don't worry as long as you put a space between password and youremail@example.com.

    After this command, Weechat will show password and youremail@example.com as plain text. IRC server uses the current nick (username) as the account name. So username is both the nick and account name registered on freenode. This special nick is called primary nick.

    In a while, you will receive an email, from which you should copy the verification command to complete the registration process:

  2. /msg nickserv confirm <temporary-code> or /msg nickserv verify register <username> <temporary-code>

    This temporary-code is only for account registration confirm.

    Now, account name username has just one nick username associated on Freenode server, no one else can use nick username unless the correct password is identified (talked later on).

    OFTC server does need this extra confirmation step.

  3. /msg NickServ SET HIDE EMAIL ON

    To keep your email address private, rather than displaying it publicly, mark it as hidden.

    For OFTC, it's /msg nickserv set private on.

  4. Group more nicks account.

    A Freenode account can reserve multiple nicks. First switch to a new nick and then group it to our account (as long as that nick is not reserved by others). Grouping nicks in this way gives you the benefit of having all your nicks covered by the same unaffiliated cloak. The default group name is the account name, namely username.

    # switch to nick "username_"
    /nick username_
    /msg nickserv group

    To remove a nick from your account:

    /nick username
    /msg nickserv ungroup username_
  5. /reconnect

    It will prompt like username is registered… you must identify yourself…. To identify yourself as nick username:

    /msg NickServ identify username <password>


Manually Identification

If you don't configure SASL, then you have two choices:

  1. Manual identification after connection to server as above.

    /reconnect freenode
    /msg NickServ identify username <password> # freenode
    /msg NickServ identify <password> username # oftc
  2. Use freenode.command to run identify.

    irc.server.freenode.command "/msg NickServ identify username <password>"

    freenode.command runs a command automatically once connected to the server.

SASL plain scheme

OFTC disallow this scheme.

  1. irc.server.freenode.sasl_mechanism plain
  2. set irc.server.freenode.sasl_username username

    The username can be any one of your grouped nicks. But usually the primary nick (namely the account name) is used.

  3. /secure set freenode <password>

    Password will be recorded in ~/.config/weechat/sec.conf.

  4. irc.server.freenode.sasl_password "${sec.data.freenode}"

    Tell weechat where to get the password.

  5. irc.server.freenode.sasl_fail disconnect

    If SASL auth fail, disconnect.

SASL external scheme

  1. irc.server.freenode.sasl_mechanism external

    As long as sasl_mechanism is changed to external, sasl_username and sasl_password setting won't take effect.

  2. irc.server.freenode.ssl_cert "%h/ssl/freenode.pem"

    We should generate a self-signed X509 certificate before /reconnect.


OpenSSL is a cryptography toolkit implementing the SSL/TLS protocols and related cryptography libraries. Virtually, almost any packages using SSL/TLS require OpenSSL support, OpenSSH and Firefox (HTTPS) included.

The openssl program is a command line tool from OpenSSL, providing various cryptography functions. In this post, it will used to genrate self-signed X509 certificate.

jim@laptop ~ $ openssl req -newkey rsa:4096 -nodes -keyout irc.pem -sha256 -x509 -days 365 -out irc.pem -subj "/C=US/ST=NewYork/L=NewYork/O=UST/OU=CS/CN=irc" -addext "subjectAltName = DNS:irc, DNS:weechat, DNS:"
jim@laptop ~ $ mkdir -p ~/.config/weechat/ssl
jim@laptop ~ $ mv irc.pem ~/.config/weechat/ssl/
  1. req: certificate request and certificate generating utility.
  2. nodes: no DES encryption. The RSA private key won't be encrypted by DES.
  3. keyout: the private key file.
  4. sha256: the digest to sign certificate.
  5. out: the certificate file.

    The keyout and out specify the same output file name, which means private key and certificate will be merged automatically.

  6. subj: certificate Subject field. If not provided on command line, openssl will prompt for user input.

Nick and Certificate Association

To achieve certificate authentication, we should add the certificate's fingerprint to NickServ on freenode server

Get the SHA512 fingerprint.

jim@laptop ~ $ man x509
jim@laptop ~ $ openssl x509 -noout -text -sha512 -fingerprint -in irc.pem

Add the fingerprint:

/whois nick
/msg nickserv cert list
/msg nickserv cert add/del [sha1]


The fingerprint value can be ommited and NickServ on the server will automatically calculate the value.

Finally reconnect to identify nick by SASL external. You can see a line:

gnutls: sending one certificate

during connection. Run /whois nick to see:

has client certificate fingerprint:

Renew certificate

Upon expiration, we need to renew the certificate. Acutally, renewing is to create a new certificate herein.

# Extract private key from certification file (PEM)
~ # openssl rsa -in irc.pem -out irc.key
# Extract public certificate from certification file (PEM)
~ # openssl x509 -in irc.pem -out irc.crt
# Converts the certificate into a certificate request (PEM)
~ # openssl x509 -x509toreq -in irc.crt -out irc.csr -signkey irc.key
# Create a new certification for one year
~ # openssl x509 -req -days 365 -in irc.csr -out irc.crt.new -signkey irc.key
# Concatenate the new certificate and original key
~ # cat irc.crt.new irc.key > irc.pem.new
# Chceck validity
~ # openssl x509 -noout -text -in irc.pem.new

Remember to add the new certificate's fingerprint to IRC server and del the old one.

Unaffilicated Cloak

  1. Unaffiliated Cloak is to hide your IP from IRC channels.
  2. To obtain a cloak, just join the official #freenode channel, ask for one there and reconnect.

    When channel staff notices your request, you might get cloaked. Unaffiliated Cloak applies to all channels on Freenode server.

  3. To get a cloak on OFTC is much easier:

    /msg nickserv SET CLOAK ON

The above method is now deprecated! Freenode automatically turns on cloak (vHost) for every account. Just run command /msg HOSTSERV ON. Checking by /whois <username>. Before and after:

# before
(~weechat@joseon-eldv4c.jnih.mqbr.vquou2.IP): weechat
# after
(~weechat@joseon/user/username): weechat

proxy - Tor

Suppose you would like to connect to IRC server by proxy, how to set?

  1. Add proxy

    /proxy add tor socks5 9050

    This will tell Weechat that a proxy named 'tor' is added.

  2. Server copy

    Suppose we find Tor proxy is troublesome someday, updates to current server must be restored. To ease configuration, issue the following command:

    /server copy freenode freenode-tor

    Update freenode-tor configuration instead.

  3. Enable proxy for IRC server

    /set irc.server.freenode-tor.proxy tor
  4. However Freenode does not allow Tor connection to chat.freenode.net.

    The server hostname should be changed to hidden url freenodeok2gncmy.onion while keeping the original port.

    /set irc.server.freenode-tor.addresses freenodeok2gncmy.onion/6697
  5. Onion certificate.

    Cannot wait to reconnect? Yeah, me too. The server certificate cannot be verified since onion url is not certified by almost all CAs.

    gnutls: the hostname in the certificate does NOT match "freenodeok2gncmy.onion"

    Currently, only a few onion url is signed by digicert.

    The solution is maully trust fetched certificates in which though the hostname is freenode.net instead of freenodeok2gncmy.onion.

    When connected to chat.freenode.net, Weechat usually receive three certificates with their SHA-1 fingerprints listed. Collect those fingerprints and assign to:

    /set irc.server.freenode-tor.ssl_fingerprint fp1,fp2,fp3,...

    Alternatively we can turn off certificate verification:

    /set irc.server.freenode-tor.ssl_verify off

    If IRC client supports key pinning, we can choose to trust freenode's public key fingerprint instead certificate's fingerprint which benefits us in that the former keep consistent while the later varies in accord with the real freenode server you connect to. Unfortunately, Weechat does not.

    If Weechat throws errors like:

    gnutls: peer's certificate is NOT trusted

    gnutls: peer's certificate issuer is unknown

    Please check whether weechat.network.gnutls_ca_file is correctly set. On Centos, it should be /etc/pki/tls/certs/ca-bundle.crt; but on archlinux, it should be /etc/ssl/certs/ca-certificates.crt.

    Recently, freenode Tor servers do not report certificate fingerprint anymore. We can manually print fingerprint by:

    ~ $ torify gnutls-cli --tofu freenodeok2gncmy.onion:6697  --print-cert | openssl x509 -noout -text -sha256 -fingerprint -in /dev/stdin
    ~ $ sed 's/://g' <<< "fingerprint delimited by colons"


To preserve or share IRC message, we can use Bounced Network Connection (BNC) like ZNC. ZNC allows connections from different end users and relay message for each of them.

To simplify the setup, we can use the standard IRC relay and its extended version - weechat relay. Weechat supports both the weechat relay and the standard IRC relay.

If you add a standard IRC relay in Weechat, you can connect to it with any IRC client like HexChat, Irssi etc. The weechat relay runs over Websocket and only allows connections from clients that support Websocket like glowing-bear or Weechat android. However, you can not connect to a weechat relay by weechat installed from Linux package manager!

This section demonstrates the following schema:

  1. Create a weechat relay instance on a remote server, bound to loopback.
  2. Nginx as a reverse proxy.
  3. Glowing-bear or Weechat-android as the front-end client.

Weechat Relay

  1. Add relay

    /relay add ipv4.weechat 9000  # plaintext relay without SSL
    /set relay.network.bind_address ""
    /set relay.network.password MY-RELAY-PASSWORD
    /set relay.network.max_clients 3

Nginx Reverse Proxy

  1. Nginx HTTPS sample

    server {
        listen 80;
        # enforce https
        return 301 https://$server_name$request_uri;
    server  {
        ssl_certificate "/etc/letsencrypt/live/irc.example.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/irc.example.com/privkey.pem";
  2. Add nginx proxy

    # Set connection header based on upgrade header
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    # Protect from brute force attack
    limit_req_zone $binary_remote_addr zone=weechat:10m rate=5r/m;
    server {
        listen 80;
        server_name irc.example.com;
        return 301 https://$server_name$request_uri;
    server {
        listen 443 ssl http2;
        server_name cloud.example.com;
        ssl_certificate "/etc/letsencrypt/live/irc.example.com/fullchain.pem";
        ssl_certificate_key "/etc/letsencrypt/live/irc.example.com/privkey.pem";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout 10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        location /weechat {
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection $connection_header;
             proxy_set_header Host $http_host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_read_timeout 3600;
             limit_req zone=weechat burst=1 nodelay;

Direct Relay

Acutally, we can connect to the weechat relay directly.

Create a SSL relay and configure as below.

relay.network.max_clients    integer  5
relay.network.password       string   "password"
relay.network.ssl_cert_key   string   "%h/ssl/irc.pem"
relay.port.ssl.irc           integer  12345

Run /relay sslcertkey to load the cert and key without restart.

Connect to Relay

irc.server.ora1.addresses          string   ""
irc.server.ora1.password           string   "password"
irc.server.ora1.sasl_mechanism     integer  plain
irc.server.ora1.ssl                boolean  on
irc.server_default.ssl_verify      boolean  on
irc.server.ora1.ssl_fingerprint    string   "<sha512>"

We pin the relay's cert fingerprint for SSL verification.

Systemd user Unit

We can create a systemd user unit to start launch Weechat in headless mode.

Create user unit file ~/.config/systemd/user/weechat-headless.service as bellow.

Description=A headless WeeChat client and relay service

ExecStart=/usr/bin/weechat-headless --daemon


Enable and start user unit.

~ $ systemctl --user daemon-reload

~ $ systemctl --user enable weechat-headless.service
~ $ systemctl --user start weechat-headless.service

~ $ systemctl --user status weechat-headless.service

If something wrong, we can send signal SIGHUP to the headless process.

~ $ kill -HUP <pid>


If it reports "unable to load plugin", please install the optional dependencies.

│22:49:38 =!= | Error: unable to load plugin
│             | "/usr/lib/weechat/plugins/spell.so": libaspell.so.15:
│             | cannot open shared object file: No such file or
│             | directory
│22:49:38 =!= | If you're trying to load a script and not a C plugin,
│             | try command to load scripts (/perl, /python, ...)
│22:49:38 =!= | Error: unable to load plugin
│             | "/usr/lib/weechat/plugins/tcl.so": libtcl.so: cannot
│             | open shared object file: No such file or directory
│22:49:38 =!= | If you're trying to load a script and not a C plugin,
│             | try command to load scripts (/perl, /python, ...)
│22:49:38 =!= | Error: unable to load plugin
│             | "/usr/lib/weechat/plugins/ruby.so": libruby.so.2.7:
│             | cannot open shared object file: No such file or
│             | directory
│22:49:38 =!= | If you're trying to load a script and not a C plugin,
│             | try command to load scripts (/perl, /python, ...)