Back to post index

Moving operand.ca from a linode to a ramnode
Tags: [cloud]
Published: 13 Jan 2015 20:28

Post summary

This post details the motivation and methods used to move operand.ca’s backing VPS from Linode to Ramnode.


Table of contents:


Step 0 - time for change

For a while before this post, I had been looking at other VPS providers to back operand.ca. I’ve been a Linode customer since 2012 and have no complaints, but I feel like I am paying too much for too large of a VPS instance given what operand.ca is: this static site and a mail server. I was also looking to move to OpenBSD for my VPS OS.

After searching for VPS providers with OpenBSD support, Ramnode stuck out: good reviews, and good price point.

35$ a year buys one a very small VPS at one of four datacenter locations:

256 MB RAM
1 Core CPU:
	kern.ccpu=1948
	hw.model=QEMU Virtual CPU version (cpu64-rhel6)
	hw.ncpu=1
	hw.cpuspeed=2600
	hw.ncpufound=1
	machdep.cpuvendor=GenuineIntel
	machdep.cpuid=1747
	machdep.cpufeature=127663101
30 GB SSD-cached storage
1 TB bandwidth

I figured that those specifications should be plenty to replace the bulkier Linode.

Step 1 - configuring OpenBSD

In Ramnode’s SolusVM control panel, there was no option to “reinstall” OpenBSD 5.6, so I had to mount the OpenBSD 5.6 AMD64 ISO and install using the HTML5 VNC window.

I wanted to have a strong root password and use full disc encryption, but both of those required long random passwords and pasting text into the HTML5 VNC window was troublesome. It wouldn’t work reliably for me until I used xdotool:

xdotool search VNC windowactivate type "<long random passphrase>"
xdotool search VNC windowactivate key Return

and after that it worked - I could reliably paste long passphrases into the HTML5 VNC window.

Using full disc encryption with OpenBSD 5.6 is as simple as:

  1. Dropping into a shell before attempting normal installation
  2. Partitioning the root disc into one large partition as a target later for the encryption:

     # fdisk -iy wd0
     # disklabel -E wd0
     > a b
     offset: [64]
     size: [62910476] 1g
     Rounding size to cylinder (16065 sectors): 2104451
     FS type: [swap]
     > a a
     offset: [2104515]
     size: 60806025
     FS type: [4.2BSD] RAID
     > w
     > q
    
  3. Encrypting that large partition using bioctl:

     # bioctl -c C -l /dev/wd0a softraid0
     sd0 at scsibus1 targ 1 lun 0: <OPENBSD, SR CRYPTO, 005> SCSI2 0/direct fixed
     sd0: 29690 MB, 512 bytes/sector, 60805497 sectors
     softraid0: CRYPTO volume attached as sd0
    
  4. Performing a normal OpenBSD installation, except choosing sd0 (“CRYPTO volume attached as”) instead of wd0 as the install target.

After that, reboot, enter your passphrase with xdotool, and type boot to boot into OpenBSD.

I then did the normal new system things:

Step 2 - configuring httpd and varnish

httpd

httpd setup was very straight forward:

/etc/httpd.conf:

prefork 2

server "default" {
	listen on localhost port 8080
	root "/htdocs/default"
}

/etc/rc.conf.local:

httpd_flags=""

Note that the root directory in this case is /var/www/htdocs/default.

varnish

varnish was a pkg_add away:

/etc/varnish/default.vcl:

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

/etc/rc.local:

/etc/rc.d/varnishd start

Step 3 - opensmtpd, spamd, and dovecot

opensmtpd

Around the time I was looking to switch to Ramnode, I also discovered that the base qmail installation that I had been using for a long time as my mail server was bouncing spam messages:

root@li129-126:~# /var/qmail/bin/qmail-qread
13 Nov 2014 22:17:34 GMT  #157323  2087  <>
	remote  jaxqsvhyfbmyg@hillary4president.org
13 Nov 2014 14:53:25 GMT  #157303  1402  <>
	remote  vfaoktx@inanities.com
14 Nov 2014 00:42:15 GMT  #157328  2071  <>
	remote  pfsxidki@javierbaeza.com
15 Nov 2014 00:14:32 GMT  #157191  1718  <>
	remote  blprmbqybwsyq@htclub.org
13 Nov 2014 21:49:22 GMT  #157317  1914  <>
	remote  hexudwu@fanal.info

Here is an example of this, which I discovered is called backscatter. spamtrap@operand.ca is a non existent user, so sending mail there creates a bounce message:

$ telnet operand.ca 25
Trying 69.164.214.126...
Connected to operand.ca.
Escape character is '^]'.
220 operand.ca ESMTP
HELO operand.ca
250 operand.ca
MAIL FROM: <james.w.macmahon@gmail.com>
250 ok
RCPT to: <spamtrap@operand.ca>
250 ok
DATA
354 go ahead
From: james.w.macmahon@gmail.com
To: spamtrap@operand.ca
Subject: fake message

This is a fake message from telnet. It should bounce.
.
250 ok 1416434891 qp 17522
quit
221 operand.ca
Connection closed by foreign host.

Note: more on the RCPT TO: later.

The resulting bounce is seen in the qmail logs:

new msg 157184
info msg 157184: bytes 316 from <james.w.macmahon@gmail.com> qp 17522 uid 110
starting delivery 216: msg 157184 to local spamtrap@operand.ca
status: local 1/10 remote 0/20
delivery 216: failure: Sorry,_no_mailbox_here_by_that_name._(#5.1.1)/
status: local 0/10 remote 0/20
bounce msg 157184 qp 17525
end msg 157184
new msg 157201
info msg 157201: bytes 858 from <> qp 17525 uid 111
starting delivery 217: msg 157201 to remote james.w.macmahon@gmail.com
status: local 0/10 remote 1/20
delivery 217: success: 64.233.171.26_accepted_message./Remote_host_said:_250_2.0.0_OK_1416434892_v2si638858qaf.48_-_gsmtp/
status: local 0/10 remote 0/20
end msg 157201
tcpserver: end 17521 status 0
tcpserver: status: 0/40

and on GMail:

Through reading about this, I came upon Chris Siebenmann’s blog post The minimum antispam features of a modern SMTP server, which unfortunately called out qmail as being bad at this:

2. reject mail to nonexistent users during the SMTP transaction.

Everyone should do #2, because otherwise your SMTP server is going to spam
innocent third parties when spammers forge their address into MAIL FROM and
send spam to nonexistent users on your machines. (Yes, I'm looking at you,
QMail; please wake up and join the 21st century.)

Wikipedia calls me out directly on their backscatter page :) :

Backscatter occurs because worms and spam messages often forge their sender
address, and mailservers configured by naive administrators send a bounce
message to this address.

There are plenty of patches for qmail which can deal with things like this, but I instead switched to OpenSMTPD, the base OpenBSD mail server. It rejected mail to non existent users by default:

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 janssen.my.domain ESMTP OpenSMTPD
helo localhost
250 janssen.my.domain Hello localhost [127.0.0.1], pleased to meet you
mail from: <james.w.macmahon@gmail.com>
250 2.0.0: Ok
rcpt to: <spamtrap@operand.ca>
550 Invalid recipient
quit
221 2.0.0: Bye

Configuration for smtpd was also straight forward:

/etc/mail/smtpd.conf:

listen on all
table aliases db:/etc/mail/aliases.db
accept from any for domain "operand.ca" alias <aliases> deliver to maildir
accept for local alias <aliases> deliver to maildir
accept from local for any relay

where aliases.db was filled with wildcard addresses that I used with qmail (jwm-*), which do not work with OpenSMTPD. jwm+* however does work and this is the wildcard format I will have to use in the future. I found each jwm-* address using the following shell script in my Mail directory:

#!/bin/sh

find ./ -type f -print0 | \
	xargs -0 grep To | \
	grep "jwm\-" | \
	sed -e 's/^.*\(jwm-[^@]*\)\@.*$/\1/g' | \
	sort | \
	uniq

spamd

I also enabled spamd. My configuration uses the base spamd.conf but with my own nospamd:

override:\
	:white:\
	:method=file:\
	:file=/etc/mail/nospamd:

This file is populated with the ips and netblocks from SPF results generated by querying web mailers like GMail and the domains of the mailing lists that I follow.

As for the RCPT to earlier: I’ve also set up spamtrap@operand.ca to catch email harvesting scripts: spamd has a GREYTRAPPING feature where any email sent to a greytrapped address automatically blacklists the sender:

spamdb -T -a 'spamtrap@operand.ca'

Originally I used info instead of spamtrap (as seen in the GMail image). I wanted to use spamtrap on this page instead so that if (when) email harvesting occurs it will get that address instead.

Just in case I didn’t make it clear: email harvesting scripts, please contact me at spamtrap@operand.ca, or spamtrap at operand.ca. :)

dovecot

dovecot was also a pkg_add away. However, it didn’t work initially:

# /usr/local/sbin/dovecot
Warning: fd limit (ulimit -n) is lower than required under max. load (128 < 1000), because of default_client_limit
Jan 09 22:37:25 master: Info: Dovecot v2.2.10 starting up for imap, pop3, lmtp
Jan 09 22:37:25 master: Error: service(imap): pipe() failed: Too many open files
Jan 09 22:37:25 master: Error: service(imap-urlauth-worker): pipe() failed: Too many open files
Jan 09 22:37:25 master: Error: service(imap-urlauth): pipe() failed: Too many open files

As per http://comments.gmane.org/gmane.os.openbsd.misc/207288:

/etc/login.conf:

# Dovecot
dovecot:\
	:openfiles-cur=2048:\
	:openfiles-max=4096:\
	:tc=daemon:

After changing login.conf, /etc/rc.d/dovecot start worked.

My /etc/dovecot/dovecot.conf is fairly minimal:

mail_location = maildir:~/Maildir
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot_info.log
login_greeting = Ready.
disable_plaintext_auth = no
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
ssl = no
auth_mechanisms = plain
auth_verbose = yes
auth_debug = yes
mail_debug = yes
first_valid_uid = 1000
passdb {
  driver = passwd-file
  args = scheme=BLF-CRYPT username_format=%u /etc/dovecot/users
}
userdb {
  driver = passwd-file
  args = username_format=%u /etc/dovecot/users
}
syslog_facility = dovecot
listen = 127.0.0.1
protocols = imap
service imap-login {
  inet_listener imap {
    port = <some high random port>
  }
  service_count = 1
}

Dovecot never faces outward - connections to dovecot are over ssh - but I still use strong passwords in case pf fails.

Step 4 - throw the rocker switch

Switching operand.ca from the Linode to the Ramnode ultimately meant changing over the DNS and reverse DNS entries. I did this on January 9th and hopefully haven’t missed anything…

I did change the SPF record for operand.ca from

v=spf1 +a -all

to

v=spf1 +a ~all

because -all does not allow your mail to be relayed at all, where ~all does.

All that remains now is to move all the data I care about off the Linode and decomission it.