ADUFRAY

Setting up a simple Jabber service on Red Hat Enterprise Linux (or any of its derivatives) is very straight-forward. If you install the Extra Packages for Enterprise Linux (EPEL) repository, you’ll have access to jabberd2.

The Quick StartGuide for RPM documentation provided by the jabberd2 project is almost all you need to get it up and going.

# yum install jabberd
# chkconfig jabberd on

The documentation tells you to switch to MySQL, but this is unnecessary. The default configuration uses an SQLite database for user registration and session storage, so you can set that up instead. To do so, simply initialize the database:

# sqlite3 /var/lib/jabberd/db/sqlite.db < /usr/share/jabberd/db-setup.sqlite

Then all that’s left is setting up your ID entries in c2s.xml and sm.xml:

c2s.xml:
    <local>
      <id register-enable='mu' password-change='mu'>domain.com</id>
      ...
    </local>

sm.xml:
    <local>
      <id>domain.com</id>
      ...
    </local>

Now you’re all set:

# service jabberd start

This, of course, only sets up the most basic implementation. There are a few extra steps I took to have a slightly more secure setup. I also wanted to host multiple domains for friends to use. By default:

To fix the encrypted password issue, you have to use MySQL instead of SQLite. There’s an open bug on GitHub to implement this feature, but it’s still waiting for patches. It’s pretty easy to change to MySQL, though. The database setup script, /usr/share/jabberd/db-setup.mysql, wants to create the database for you, which can cause problems if you’ve already created one, so go ahead and comment out the first few lines:

-- CREATE DATABASE jabberd2;
-- USE jabberd2;

Then you can create the database, its user, and run the script:

# mysql -u root -p
> CREATE DATABASE jabber;
> GRANT ALL ON jabber.* to 'jabber'@'localhost' IDENTIFIED BY 'password';
> QUIT
# mysql -u jabber -p jabber < /usr/share/jabberd/db-setup.mysql

Then edit both c2s.xml and sm.xml again, changing the DB driver to use MySQL instead of SQLite:

c2s.xml:
    <authreg>
      ...
      <module>mysql</module>
      ...
      <mysql>
        <host>localhost</host>
        <port>3306</port>

        <dbname>jabber</dbname>

        <user>jabber</user>
        <pass>password</pass>

        <password_type>
          <crypt/>
        </password_type>
      </mysql>
      ...
    </authreg>

sm.xml:
    <storage>
      ...
      <driver>mysql</driver>
      ...
      <mysql>
        <host>localhost</host>
        <port>3306</port>

        <dbname>jabber</dbname>

        <user>jabber</user>
        <pass>password</pass>

        <transactions/>
      </mysql>
      ...
    </storage>

This gives us a strong database backend with passwords that are somewhat securely stored. The hashing method uses the crypt(3) function to generate a salted MD5 hash. Without digging into the source code, I can’t tell how many rounds of MD5 it is, but it’s sort of irrelevant: MD5 is broken and unsuited for password hashing. Still, better than plaintext — basically only keeps honest people honest. Moving on…

To set up TLS/SSL you have a decision to make: self-signed or legitimate certificate. I prefer legitimate because these days you can get SSL certificates very cheaply (or even free). It’s a bit easier to set up self-signed though:

# openssl genrsa -out ./jabber.key 2048
# openssl req -new -key ./jabber.key -x509 -sha1 -out ./jabber.crt
# cat jabber.crt jabber.key >> combined.crt
# rm jabber.crt jabber.key

jabberd2 requires that they key (and any intermediate certificates) be present in the PEM file. I don’t like this approach — the key should not be readable by anyone but root. Unfortunately the jabberd2 processes aren’t clever enough read in the key as root and then drop privileges — patches are welcome, I’m sure.

If you want to go the legitimate certificate route, create a key and certificate signing request:

# openssl genrsa -out ./jabber.key 2048
# openssl req -new -key ./jabber.key -sha1 -out ./jabber.csr

Send the CSR to your certificate authority. They should send you back a certificate and one or more intermediate / root certificates. Your combined certificate should look something like this:

# cat certificate.crt intermediate.crt root.crt key.key > combined.crt

To install the SSL certificate (either self-signed or legitimate), you need to edit the <id> tag in c2s.xml:

<local>
  <id register-enable='mu' pemfile='/path/to/combined.crt' require-starttls='mu' password-change='mu'>domain.com</id>
  ...
</local>

My server requires all client connections to be encrypted. If you want to support TLS, but don’t care whether or not the connections are encrypted, just remove the require-starttls parameter.

Next up is setting the IP address to listen on. This is a very quick edit to c2s.xml and s2s.xml:

<local>
  ...
  <ip>0.0.0.0</ip>
  ...
</local>

Adding an administrator is similarly easy. Just edit the aci section of sm.xml:

<aci>
  ...
  <acl type='all'>
    <jid>admin@domain.com</jid>
  <acl>
  ...
</aci>

Securing the inter-service communication is fairly easy, but a little cumbersome. You need to edit all the service configuration files (c2s.xml, s2s.xml, and sm.xml) as well as the router configuration (router.xml) and the router users file (router-users.xml).

For each service, create a user entry in router-users.xml:

<users>
  <user>
    <name>c2s</name>
    <secret>random_password</secret>
  </user>
  <user>
    <name>s2s</name>
    <secret>random_password</secret>
  </user>
  <user>
    <name>sm</name>
    <secret>random_password</secret>
  </user>
</users>

Then edit router.xml to give access to each of these users:

<aci>
  <acl type='all'>
    <user>c2s</user>
    <user>s2s</user>
    <user>sm</user>
  </acl>
  ...
</aci>

While you’re there, go ahead and enable SSL:

<local>
  ...
  <pemfile>/path/to/combined.crt</pemfile>
  ...
</local>

You could probably be more granular in the ACLs, but I don’t know enough about what permissions are needed for each process. Next, you have to edit each service’s configuration file and change the user & password settings — make sure you match the passwords correctly to what you defined in router-users.xml:

<router>
  ...
  <user>c2s OR s2s OR sm</user>
  <pass>corresponding password</pass>
  <pemfile>/path/to/combined.crt</pemfile>
  ...
</router>

Now all your services should be using a unique password to communicate. In addition, the traffic will be encrypted.

All that remains is to set up multiple domains. Searching around the net I couldn’t find very much documentation, but thankfully it’s very easy. In previous versions of jabberd2, you needed to run an sm process for each separate domain. That no longer seems to be the case. You just need to edit c2s.xml, sm.xml, and configure appropriate SRV records. In c2s.xml, just add another ID entry for the second domain:

<local>
  ...
  <id register-enable='mu' pemfile='/path/to/combined.crt' require-starttls='mu' password-change='mu'>domain1.com</id>
  <id register-enable='mu' pemfile='/path/to/combined.crt' require-starttls='mu' password-change='mu'>domain2.com</id>
  ...
</local>

Pretty much the same thing in sm.xml:

<local>
  <id>domain1.com</id>
  <id>domain2.com</id>
</local>

Then add the SRV records to your DNS:

_xmpp-client._tcp.domain1.com. IN    SRV 5    5 5222 domain1.com.
_xmpp-server._tcp.domain1.com. IN    SRV 5    5 5269 domain1.com.

Do the same thing for domain2.com, leaving domain1.com as the destination at the end:

_xmpp-client._tcp.domain2.com. IN    SRV 5    5 5222 domain1.com.
_xmpp-server._tcp.domain2.com. IN    SRV 5    5 5269 domain1.com.

This configuration will let you use Jabber IDs for either domain1.com or domain2.com. Just make sure in your client’s configuration you put in the correct value for the Connect Server — in this example, that would be domain1.com.

Once you’ve created your accounts using a Jabber client, you might consider going back to c2s.xml and removing the register-enable parameter from the id tag. Otherwise any Internet user can create accounts on your server.

I recently set up Marco Arment’s Second Crack blogging platform on my RHEL 6 server. I had been using Wordpress for awhile, but got frustrated with its dynamic rendering strategy. I want a blogging engine that scales easily and plays nicely with nginx, not something that has to parse code and query databases just to get the content. Here’s how I did it.

Firstly, per Marco’s advice, I installed both the command-line interface to Dropbox and the inotifytools package from the EPEL repo. This allows me to write and edit blog posts from anywhere I have access to Dropbox and have my changes applied instantly. It’s really amazing to be able to edit blog posts in plaintext using Markdown syntax from my iPad mini. I cannot understate this.

I’m very minimalist when it comes to installing packages on my server. I generally start with the absolute Minimal distribution and only install packages as needed. There is no reason for a webserver to have Xorg, after all. This methodology presented a problem with Dropbox at first. The Dropbox for Linux page only lists packages for Ubuntu and Fedora (with an option to build from source). These packages, however, are for the desktop interface of Dropbox — which is not needed. Instead, I found a link to a simple dropbox.py utility which keeps everything in sync and only requires Python 2.6. Best of all, the installer and corresponding daemon run as an unprivileged user. Simply download the script and run the install command:

$ python dropbox.py start -i

After it finishes the download and install, it should prompt you to visit a URL to link the system to your Dropbox account. The installer will download the necessary libraries and runtime data into ~/.dropbox-dist/ and put the configuration stuff into ~/.dropbox/. By default it will create ~/Dropbox/ to hold the items you want synced. The only caveat to the Dropbox install is that the process will need to be relaunched after each reboot: python ~/dropbox.py start

Installing Second Crack is basically as straight-forward as he lays it out in the included README.md. Just pull down the repository, make the changes to the configuration file (blog name, URL, etc.), configure the crontab, and start designing your template (that’s where I spent the vast amount of my time).

By default, Second Crack will install a simple .htaccess file to perform the slug line URL redirects. Unfortunately, .htaccess files don’t translate directly to nginx, but in this case the needed configuration is incredibly easy:

index index.html
location ~ ^/blog/. {
    default_type text/html;
    try_files $uri $uri.html;
}

To stop Second Crack from automatically reinstalling the .htaccess file, simply comment out the line in {SECOND_CRACK}/engine/Updater.php, line 438 — but it really doesn’t matter:

//if (! file_exists(self::$dest_path . '/.htaccess')) copy(dirname(__FILE__) . '/default.htaccess', self::$dest_path . '/.htaccess'); 

If you’ve more or less followed along, you should be pretty much good-to-go. For going mobile, I literally searched the App Store for “text editor dropbox” and bought the first one: PlainText by Hog Bay Software. There are several things I absolutely love about this app:

Happy blogging!

Setup

The process is fairly straight forward, but there are some requirements:

  1. A TFTP server with some specific files. These should all be in the root of the TFTP directory.
    1. The latest version of the SheevaPlug U-Boot binary.
    2. The latest version of the Debian installer image (uImage and uInitrd).
    3. The latest version of the Linux kernel (optimized for SheevaPlug; uImage and Modules).
  2. A 2+ GB USB thumb drive.
  3. Terminal emulation software (GNU screen, PuTTY, minicom, HyperTerm) [Note: Mac OS X’s version of screen seems to have issues with the debian installer, so I used PuTTY in a VM.]

There’s a lot of interrupting the initial boot process, which requires fairly fast attachment of your terminal. If you’re using a VM environment, make sure you tell it to remember your “Attach to Host or VM?” preference, otherwise you’ll miss the interrupt prompt.

Upgrade U-Boot

  1. Reset the SheevaPlug
  2. Interrupt the boot process

    1. “Hit any key to stop autoboot:”
  3. Document the MAC address

    Marvell>> print ethaddr
    ethaddr=FF:FF:FF:FF:FF:FF
    
  4. Boot using TFTP

    Marvell>> setenv ipaddr x.x.x.x
    Marvell>> setenv serverip y.y.y.y
    Marvell>> tftpboot 0x0800000 u-boot.kwb
    Marvell>> nand erase 0x0 0x60000
    Marvell>> nand write 0x0800000 0x0 0x60000
    Marvell>> reset
    
  5. Fix the MAC address by interrupting the boot process (the new U-Boot loses the setting).

    Marvell>> setenv ethaddr FF:FF:FF:FF:FF:FF
    Marvell>> saveenv
    Marvell>> reset
    

Burn the new kernel

Marvell>> setenv ipaddr x.x.x.x
Marvell>> setenv serverip y.y.y.y
Marvell>> tftpboot 0x2000000 sheeva-3.4.7-uImage
Marvell>> iminfo
Marvell>> nand erase 0x100000 0x400000
Marvell>> nand write 0x2000000 0x100000 0x400000
Marvell>> setenv mainlineLinux yes
Marvell>> setenv arcNumber 2097
Marvell>> saveenv

Install Debian

For this section, I recommend using PuTTy on a Windows VM. Or at least something other than GNU Screen on Mac OS X. It doesn’t play nice with the Debian installer character set for some reason. You can try using SynchTERM on Mac OS X, but it still isn’t quite right and it becomes very easy to check the wrong boxes.

Marvell>> setenv ipaddr x.x.x.x
Marvell>> setenv serverip y.y.y.y
Marvell>> tftpboot 0x0400000 uImage
Marvell>> tftpboot 0x0800000 uInitrd
Marvell>> setenv bootargs console=ttyS0,115200 base-installer/initramfs-tools/driver-policy=most
Marvell>> bootm 0x0400000 0x0800000

Once in the installer, answer the defaults to all the questions, set a root password, etc. When you get to the disk partitioning, it should not detect any disks and will ask to configure iSCSI.

  1. Plug in a USB pen drive
  2. Use [TAB] to select Go Back
  3. Select “Disk Partitioning” again
  4. The USB drive is now detected
  5. Use default partitioning (everything in /)
  6. Be careful selecting packages. I only select the SSH server and NOT Standard System Utilities — otherwise you’ll fill the SheevaPlug
  7. Once finished, interrupt boot process and boot from USB:

    Marvell>> setenv bootargs_console console=ttyS0,115200
    Marvell>> setenv bootcmd_usb 'usb start; ext2load usb 0:1 0x0800000 /uInitrd; ext2load usb 0:1 0x400000 /uImage'
    Marvell>> setenv bootcmd 'setenv bootargs $(bootargs\_console); run bootcmd\_usb; bootm 0x400000 0x0800000'
    Marvell>> boot
    
  8. Set up UBIFS (so much faster than JFFS2; 2+ minute boot down to 20 seconds)

    # apt-get install mtd-utils
    # ubiformat /dev/mtd2 -s 512
    # ubiattach /dev/ubi_ctrl -m 2
    # ubimkvol /dev/ubi0 -N rootfs -m
    # mount -t ubifs ubi0:rootfs /mnt
    
  9. Clone the USB root to the internal flash (UBIFS)

    # mkdir /tmp/rootfs
    # mount -o bind / /tmp/rootfs/
    # cd /tmp/rootfs
    # sync
    # cp -a . /mnt/
    
  10. Fix the /mnt/etc/fstab file

    # cat << END > /mnt/etc/fstab
    /dev/root / ubifs defaults,noatime,rw 0 0
    tmpfs /var/run tmpfs size=1M,rw,nosuid,mode=0755 0 0
    tmpfs /var/lock tmpfs size=1M,rw,noexec,nosuid,nodev,mode=1777 0 0
    tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0
    END
    
  11. Reboot — interrupt boot cycle, unplug USB

  12. Reconfigure the boot command

    Marvell>> setenv bootargs 'console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs'
    Marvell>> saveenv
    Marvell>> reset
    
  13. Install some packages

    # apt-get install sudo
    

Resources: