Home > Uncategorized > Setting up XMPP BOSH server

Setting up XMPP BOSH server

This tutorial explains how to setup/troubleshoot XMPP server with BOSH. I’m not getting into what is XMPP and what is it good for. The first two paragraphs are theoretical. XMPP is stateful protocol in a client-server model. If web application needs to work with XMPP a few problems arise. Modern browsers don’t support XMPP natively, so all XMPP traffic must be handled by program running inside the browser (JavaScript/Flash etc…). The first problem is that HTTP is a stateless protocol, meaning each HTTP request isn’t related with any other request. However this problem can be addressed by applicative means for example by using cookies/post data.

The second problem is the unidirectional nature of HTTP: only the client sends requests and the server can only respond. The server’s inability to push data makes it unnatural to implement XMPP over HTTP. The problem is eliminated if client program can make direct TCP requests (thus eliminating the need of HTTP). However, if we want to address the problem within HTTP domain (for example because Javascript can only forge HTTP requests) there are two possible solutions, both require “middleware” to bridge between HTTP and XMPP. The solutions are “polling” (repeatedly sending HTTP requests asking “is there new data for me”) and “long polling”, aka BOSH. The idea behind BOSH is exploitation of the fact that the server doesn’t have to respond as soon as he gets request. The response is delayed until the server has data for the client and then it is sent as response. As soon as the client gets it he makes a new request (even if he has nothing to send) and so forth.

BOSH is much more efficient, from server load’s point of view and traffic-wise. In this tutorial I set up Openfire XMPP server (which also provides the BOSH functionality) with JSJaC library as client, using Apache as web server on Ubuntu 10.04. Openfire has Debian package and as such, installation is fairly easy. Just download the package and install. After installation browse to port 9090 on the machine it was installed on, and from there it’s web-driven easy setup. If you choose to use MySQL as Openfire’s DB make sure to create dedicated database before (mysqladmin create).

After initial setup, I wasn’t able to login with the “admin” user. This post solved my problem, openfire.xml is located at /etc/openfire (if you installed from package), you will need root privileges to edit it and then restart Openfire (sudo /etc/init.d/openfire restart). Other than that everything worked fine. Openfire server (as well as all major XMPP servers) provides the BOSH functionality, aka “HTTP Binding” aka “Connection Manager”. By default it listens on port 7070, with “/http-bind/” (the trailing slash is important).

To make sure it works (this is the part I couldn’t find anywhere, that’s why it took me long time to resolve all problems) I used “curl”, very handy tool (sudo apt-get install curl). To test the “BOSH server”:
# curl -d “<body rid=’123456′ xmlns:xmpp=’urn:xmpp:xbosh’ />” http://localhost:7070/http-bind/

Switch “localhost” with your server name, notice the trailing slash. Expected result should look like:

<body xmlns="http://jabber.org/protocol/httpbind" xmlns:stream="http://etherx.jabber.org/streams" authid="2b10da3b" sid="2b10da3b" secure="true" requests="2" inactivity="30" polling="5" wait="60"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>CRAM-MD5</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features></body>

Once verified, we can continue with the next step. Since the client is Javascript based, all Javascript restrictions enforced by the browser applies. One of these restrictions is “same origin policy“. It means that Javascript can only send HTTP requests to the domain (and port) it was loaded from and since it is served on HTTP (port 80) it can’t make requests to port 7070. Solution: Javascript client will make requests to the same domain and port. The requests will be forwarded locally to port 7070 by Apache. I guess you can use the same method to forward even to a different server but I didn’t try. I configured forwarding following this post but there is probably more than one way to do it.

Add to /etc/apache2/httpd.conf the following lines (root privileges needed):
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so

Then, add to /etc/apache2/apache2.conf the following lines (root privileges needed):
ProxyRequests Off
ProxyPass /http-bind http://localhost:7070/http-bind/
ProxyPassReverse /http-bind http://localhost:7070/http-bind/
ProxyPass /http-binds http://localhost:7443/http-bind/
ProxyPassReverse /http-binds http://localhost:7443/http-bind/

Now restart the Apache (sudo /etc/init.d/apache2 restart) and make sure it starts properly. To verify the forwarding works, use the same curl method, this time as request to the Apache:
# curl -d “<body rid=’123456′ xmlns:xmpp=’urn:xmpp:xbosh’ />” http://localhost/http-bind

The result should be the same as before. If it doesn’t work there is problem with the forwarding. Update: if you get “403 Forbidden” error from Apache, this may help (thanks Tristan). Once it is working, server side is ready. On the client (in my case JSJaC), you should specify to use BOSH/HTTP Bind “backend” (as opposed to “polling”). For “http bind” url just use “/http-bind” and everything should work. Notice that if you open the client locally on your desktop (not served by the Apache) it won’t work because of the “same origin policy” mentioned before.

I hope you find this tutorial useful, it sure could have helped me… :)

Share and Enjoy:
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • Slashdot
  • email
  • Print
  1. acoyote
    September 13th, 2010 at 18:31 | #1

    good tutorial

  2. elijah saounkine
    November 16th, 2010 at 12:24 | #2

    Aha, the ‘same origin policy’ is the sneaky bitch. Good work.

  3. Yopy
    January 14th, 2011 at 04:58 | #3

    there is error message “couldn’t connect to host”.

    How to solve it?

    Regards

    • frishrash
      February 18th, 2011 at 09:50 | #4

      When exactly are you getting this? sounds like either the service is not running or you try to connect to the wrong port

  4. May 22nd, 2011 at 23:43 | #5

    Quite strangely, I followed the instructions perfectly and am able to connect to my XMPP server using the IP I told it to bind to (my server has 3 IPs, one is HTTP, the next one is XMPP) and I also tell it to bind to 127.0.0.1 and localhost. Whenever I attempt to go to 247server.net/http-bind/ I get a 403. What could I be doing wrong?

    • frishrash
      May 22nd, 2011 at 23:58 | #6

      Sounds like Apache is not configured correctly to forward /http-bind to the XMPP server. Make sure you have the trailing slash on the ProxyPass and ProxyPassReverse lines if you followed my method.

  5. May 23rd, 2011 at 00:11 | #7

    I’m pretty sure I have everything configured. My apache2.conf goes like this:

    ProxyRequests Off
    ProxyPass /http-bind http://173.0.50.7:7070/http-bind/
    ProxyPassReverse /http-bind http://173.0.50.7:7070/http-bind/
    ProxyPass /http-binds http://173.0.50.7:7443/http-bind/
    ProxyPassReverse /http-binds http://173.0.50.7:7443/http-bind/

  6. May 23rd, 2011 at 00:14 | #8

    I also told Apache to load both of the modules you mentioned using a2enmod.

    Apache’s error log says this:

    [Sun May 22 14:13:36 2011] [error] [client 67.164.14.81] client denied by server configuration: proxy:http://173.0.50.7:7070/http-bind/

  7. May 23rd, 2011 at 00:31 | #10

    @frishrash
    Thank you a lot! The first link solved my problem right away. I suggest adding this into your post to save people like me the 4 hours spent panicing =P

    • frishrash
      May 23rd, 2011 at 00:39 | #11

      Glad I could help. Post is now updated :)

  8. May 23rd, 2011 at 06:07 | #12

    Also, quick question time, did jquery-bosh ever work for you? JSJaC is confusing as heck to me.

  9. frishrash
    May 23rd, 2011 at 08:30 | #13

    @Tristan I’ve actually never tried it…

  10. May 23rd, 2011 at 16:41 | #14

    @frishrash I’ve tried both, and I always get the standard invalid auth, even though it’s the same exact user that I can log in with on the admin panel.

    • frishrash
      May 27th, 2011 at 19:12 | #15

      I’m afraid I can’t help ya out with this one, it’s been a long time since I last touched JSJaC…

  11. Albert
    April 2nd, 2012 at 09:36 | #16

    I’m looking for an official confimation that BOSH (XEP-0206) is supported by OpenFire. It’s not on the lost of supported protocols. Can anyone help at this?

  12. Ashish
    May 18th, 2012 at 12:33 | #17

    Thanks….helped me a lot.

  13. Justin
    September 23rd, 2012 at 10:49 | #18

    Thanks… It really helped me.

  1. November 10th, 2010 at 20:15 | #1