A Config File Made for Humans
Don't worry, we won't be doing any XML sit-ups to configure the server. Here's an example Vines server configuration file located at wonderland.lit/conf/config.rb:
Vines::Config.configure do host 'wonderland.lit' do storage 'fs' do dir 'data' end components 'tea' => 'secr3t', 'cake' => 'passw0rd' end client '0.0.0.0', 5222 do max_stanza_size 65536 max_resources_per_account 5 end server '0.0.0.0', 5269 do max_stanza_size 131072 hosts  end http '0.0.0.0', 5280 do max_stanza_size 131072 end component '0.0.0.0', 5347 do max_stanza_size 131072 end cluster do host 'redis.wonderland.lit' port 6379 end end
Hopefully, this is mostly self-explanatory, but let's go through the highlights. For full documentation, read the comments in the conf/config.rb file.
One chat server can host user names at many domains: wonderland.lit, verona.lit, example.com, etc. Each of these virtual hosts is configured in the config.rb file. Each virtual host can use its own storage database or they can share a database.
In our example, we've configured the chat server to host the fictitious wonderland.lit domain and store user information in the file system under the data/ directory. This means we can chat with any user name in the wonderland.lit domain: email@example.com, firstname.lastname@example.org, email@example.com, etc.
Vines can store user data in several databases out of the box: Apache CouchDB, Redis, MongoDB, any SQL database, or simply in the local file system. It's easy to plug in custom databases through a simple storage API. Each of these connectors is documented in the default conf/config.rb file.
Our example server is using the local file system storage database, which stores data in one file per user under the data/user directory. A user file is a simple YAML document describing the user and their roster. Let's look at the firstname.lastname@example.org file.
name: Alice password: $2a$10$kDyV4w7tKIEuM5Ii7qFQiuGLbIyH3k . . . roster: email@example.com: name: Cheshire Cat subscription: both ask: groups: - Cats - Friends - Cat Friends firstname.lastname@example.org: subscription: none ask: subscribe
Alice's password is securely stored as a bcrypt hash. She has two users on her roster: email@example.com and firstname.lastname@example.org. The Mad Hatter is on her buddy list, but she doesn't have a presence subscription to him yet so she can't see when he goes on and offline.
To add a new user, the Red Queen, to the chat server, we just copy this file and rename it to email@example.com.
Storing users in the file system is simple and fast, but maybe we're already using an LDAP directory to store passwords. We can add an LDAP connector to the chat server so authentication is performed against our corporate directory instead of the file system.
host 'wonderland.lit' do storage 'fs' do dir 'data' end ldap 'ldap.wonderland.lit', 636 do dn 'cn=Directory Manager' password 'secr3t' basedn 'dc=wonderland,dc=lit' groupdn 'cn=chatters,dc=wonderland,dc=lit' # optional object_class 'person' user_attr 'uid' name_attr 'cn' tls true end end
In this example we're storing user information, like rosters, in the file system, but not their passwords. When a user logs into the chat server, their password will be authenticated with the LDAP server at ldap.wonderland.lit, listening on port 636. The user files under data/user can have their password field deleted. It's never used as long as the LDAP connector is in place.
The LDAP attribute defined by user_attr must contain the user's full chat ID. In our example, the value of Alice's uid field in our LDAP directory is firstname.lastname@example.org. The LDAP mail attribute is also popular because the user's email address generally matches their chat ID.
The optional groupdn value limits which users are allowed to login to the chat server. If not set, all LDAP users that authenticate successfully are allowed to chat. However, if a group is set, only users belonging to that LDAP group are allowed to access the chat server. See the vines ldap command line tool for more information.
This port is listening for typical, client to server, connections from chat programs like iChat. Our example is listening on port 5222 on all interfaces on our machine.
client '0.0.0.0', 5222 do max_stanza_size 65536 max_resources_per_account 5 end
The max_stanza_size property defines, in bytes, the largest message the server will allow a client to send. This helps prevent denial of service attacks where an attacker floods the server with huge messages.
The max_resources_per_account property specifies how many times one user can login at the same time. For example, Alice may be logged in to chat on her laptop and her mobile phone.
Server to Server
One of the best parts of XMPP is server federation. Users at our wonderland.lit domain can chat with users at verona.lit through a server to server connection.
server '0.0.0.0', 5269 do max_stanza_size 131072 hosts ['verona.lit'] end
It's a good idea to set max_stanza_size much higher for server connections than clients, so we've set it to 128 KB. We trust servers a bit more than clients to be well behaved.
The hosts property is a white list of remote chat servers to which we're allowed to connect. The domain must be listed here and its SSL certificate must be trusted for the remote connection to succeed.
Web applications can connect to the chat server by tunneling the XMPP protocol through HTTP. This connector allows our web apps to chat just like normal XMPP clients.
http '0.0.0.0', 5280 do max_stanza_size 131072 end
The XMPP component protocol allows us to extend the chat server with trusted services, or bots.
host 'wonderland.lit' do components 'tea' => 'secr3t', 'cake' => 'passw0rd' end component '0.0.0.0', 5347 do max_stanza_size 131072 end
Each sub-domain listed in the components attribute is allowed to connect to the server if it provides the shared secret configured here. In this example, we would have components at tea.wonderland.lit and cake.wonderland.lit.
Two or more Vines server instances can be clustered together to handle load-balancing and high-availability. The instances use an in-memory Redis database to communicate with one another.
cluster do host 'redis.wonderland.lit' port 6379 end
See the clustering guide for details on how to configure cluster nodes.