soju status

A user-friendly IRC bouncer.

  • Multi-user
  • Support multiple clients for a single user, with proper backlog synchronization
  • Support connecting to multiple upstream servers via a single IRC connection to the bouncer


See the man page at doc/soju.1.scd for more information.

Server side

To create an admin user and start soju, run these commands:

go run ./cmd/sojuctl create-user <soju username> -admin
go run ./cmd/soju -listen irc+insecure://

If you're migrating from ZNC, a tool is available to import users, networks and channels from a ZNC config file:

go run ./contrib/znc-import.go <znc config file>
Client side

soju can operate in two different modes: multi upstream and single upstream.

Single upstream mode

In this mode, 1 upstream connection to a irc server = 1 connection to your soju bouncer.

The easiest and fastest way to use this is to specify the address of the server in your username in your client configuration. For example to connect to Freenode, your username will be: <soju username>/ Also set your soju password in the password field of your client configuration.

This will autoconfigure soju by adding a network with the address and then autoconnect to it. You will now be able to join any channel like you would normally do.

Multi upstream mode

In this mode, a single connection to your soju bouncer can handle multiple upstream connections. You will need to manually configure each upstream connection using the the special BouncerServ user.

Connect to your soju server by specifying your soju username in the username field in your client and your password in the password field.

You should now be able to send private messages to the BouncerServ. You can send it commands to configure soju. Create new networks:

/msg BouncerServ network create -addr -name freenode
/msg BouncerServ network create -addr -name rizon

You will now be able to join channels on these networks by specifying their name:

/join #soju/freenode
/join #somechannel/rizon

soju will automatically save and restore the channels you were connected to.


Send patches on the mailing list or on GitHub, report bugs on the issue tracker. Discuss in #soju on Freenode.



Copyright (C) 2020 The soju Contributors

Expand ▾ Collapse ▴




This section is empty.


This section is empty.


This section is empty.


type Channel

type Channel struct {
	ID       int64
	Name     string
	Key      string
	Detached bool

	RelayDetached MessageFilter
	ReattachOn    MessageFilter
	DetachAfter   time.Duration
	DetachOn      MessageFilter

type DB

type DB struct {
	// contains filtered or unexported fields

func OpenSQLDB

func OpenSQLDB(driver, source string) (*DB, error)

func (*DB) Close

func (db *DB) Close() error

func (*DB) DeleteChannel

func (db *DB) DeleteChannel(id int64) error

func (*DB) DeleteNetwork

func (db *DB) DeleteNetwork(id int64) error

func (*DB) DeleteUser

func (db *DB) DeleteUser(id int64) error

func (*DB) GetUser

func (db *DB) GetUser(username string) (*User, error)

func (*DB) ListChannels

func (db *DB) ListChannels(networkID int64) ([]Channel, error)

func (*DB) ListNetworks

func (db *DB) ListNetworks(userID int64) ([]Network, error)

func (*DB) ListUsers

func (db *DB) ListUsers() ([]User, error)

func (*DB) StoreChannel

func (db *DB) StoreChannel(networkID int64, ch *Channel) error

func (*DB) StoreNetwork

func (db *DB) StoreNetwork(userID int64, network *Network) error

func (*DB) StoreUser

func (db *DB) StoreUser(user *User) error

type Identd

type Identd struct {
	// contains filtered or unexported fields

    Identd implements an ident server, as described in RFC 1413.

    func NewIdentd

    func NewIdentd() *Identd

    func (*Identd) Delete

    func (s *Identd) Delete(remoteAddr, localAddr string)

    func (*Identd) Serve

    func (s *Identd) Serve(ln net.Listener) error

    func (*Identd) Store

    func (s *Identd) Store(remoteAddr, localAddr, ident string)

    type Logger

    type Logger interface {
    	Print(v ...interface{})
    	Printf(format string, v ...interface{})

    type MessageFilter

    type MessageFilter int
    const (
    	// TODO: use customizable user defaults for FilterDefault
    	FilterDefault MessageFilter = iota

    type Network

    type Network struct {
    	ID              int64
    	Name            string
    	Addr            string
    	Nick            string
    	Username        string
    	Realname        string
    	Pass            string
    	ConnectCommands []string
    	SASL            SASL

    func (*Network) GetName

    func (net *Network) GetName() string

    type SASL

    type SASL struct {
    	Mechanism string
    	Plain struct {
    		Username string
    		Password string
    	// TLS client certificate authentication.
    	External struct {
    		// X.509 certificate in DER form.
    		CertBlob []byte
    		// PKCS#8 private key in DER form.
    		PrivKeyBlob []byte

    type Server

    type Server struct {
    	Hostname       string
    	Logger         Logger
    	HistoryLimit   int
    	LogPath        string
    	Debug          bool
    	HTTPOrigins    []string
    	AcceptProxyIPs config.IPSet
    	Identd         *Identd // can be nil
    	// contains filtered or unexported fields

    func NewServer

    func NewServer(db *DB) *Server

    func (*Server) Serve

    func (s *Server) Serve(ln net.Listener) error

    func (*Server) ServeHTTP

    func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)

    func (*Server) Shutdown

    func (s *Server) Shutdown()

    func (*Server) Start

    func (s *Server) Start() error

    type User

    type User struct {
    	ID       int64
    	Username string
    	Password string // hashed
    	Admin    bool


    Path Synopsis