Eric Radman : a Journal

Run Your Own Server

Configuring your own box on the Internet is a lot of fun, and provides an opportunity to experiment with Internet services in general.

Service Cost Provider
Domain registration $11/yr. name.com
OpenBSD VPS hosting $9/mo. bsdvm.com
Secondary DNS $10/yr donation buddyns.com

VPS Hosting

Initial Setup

Getting started with a service like bsdvm.com is easy, after you select a plan and enter your data an e-mail will be sent with your initial login information. First login and change your login credentials.

ssh sshadmin@65.49.80.28
useradd -m eradman
vi /etc/group
userdel sshadmin
rm -rf /home/sshadmin

Out of the gate you may also want to prevent password authentication for anyone not in the weel group.

# Require keys for regular users
Match Group !wheel
    PasswordAuthentication no

Then set the hostname and timezone

echo "vm.eradman.com" > /etc/myname
ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime

Partition Layout

Entry-level VPS plans may only have 5GB of disk. Since I'm running a web server don't need a lot of space for /usr and /home, so I'll move things about so that ample storage for logs and www content. This is the initial layout

Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a      938M   46.8M    844M     5%    /
/dev/sd0e      817M   16.0K    776M     0%    /home
/dev/sd0d      2.9G    534M    2.3G    19%    /usr

First I'll move everything from /usr to the partition presently used for /home

cd /home
dump 0af - /usr | restore rf -

Then edit /etc/fstab to reflect the new location of /usr

cd /etc/
sed -e 's:^/dev/wd0e:#/dev/wd0d:' -e 's:^/dev/wd0d:/dev/wd0e:' fstab > fstab.new
mv fstab.new fstab
reboot

Now the partition layout should now look like this

Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a      938M   46.9M    844M     5%    /
/dev/sd0e      817M    536M    240M    69%    /usr

Now make the new /var partition, and move /var into it. If UUIDs are used instead of driver letters like rwd0d might look like 877b52f265379d61.d .

newfs /dev/rwd0d
mkdir /mnt/var
mount /dev/wd0d /mnt/var
cd /mnt/var
dump 0af - / | restore rf -
ls | grep -v var | xargs rm -r
mv var/* .
rmdir var
echo "/dev/wd0d /var ffs rw,nodev,nosuid 1 2" >> /etc/fstab
rm /var/log/*.gz
reboot

Optionally, free up some space

rm -r /usr/X11R6
rm -r /etc/X11
rm -r /usr/games
find /usr/share/man -type f -name *.[1-9] -exec rm {} \;
/usr/libexec/locate.updatedb

The final partition layout now looks something like this; plenty of space for log messages and www content.

Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a      938M   45.8M    845M     5%    /
/dev/sd0d      2.9G    7.7M    2.8G     0%    /var
adev/sd0e      817M    536M    240M    69%    /usr

Now is a good time to disable root logins

#/etc/sshd/sshd_config

PermitRootLogin no

Services - HTTP

chown eradman:users /var/www/htdocs
rm /var/www/htdocs/*

Nginx

If you like Nginx that's easy as well

http {
    access_log   /var/www/logs/access.log main;
    sendfileon;
    gzip  on;
    index index.html;

    server {
        server_name  eradman.com www.eradman.com;
        root/var/www/htdocs/eradman.com;
        location /posts {
            autoindex on;
        }
    }
}

Nginx provides an easy way to exclude some content from it's web logs which saves on a lot of space an noise.

    server {
        ...
        location ~* \.(css|png|js|ico)$ {
            access_log off;
            expires max;
        }
    }

Services - DNS

Primary Nameserver

echo 'named_flags=""' >> /etc/rc.conf.local
#/var/named/etc/named.conf

zone "eradman.com" {
        type master;
        file "master/eradman.com";
};
;/var/named/master/eradman.com
$ORIGIN eradman.com.
$TTL 6h

@IN SOA vm.eradman.com. hostmaster.eradman.com. (
    2     ; serial
    1h    ; refresh
    30m   ; retry
    7d    ; expiration
    1h )  ; minimum

    NS      vm.eradman.com.
    A       65.49.80.28
www     IN  CNAME eradman.com.
vm      IN  CNAME eradman.com.

After restarting named verify like so

$ host eradman.com
eradman.com has address 65.49.80.28
eradman.com mail is handled by 50 mail.freeshell.org.

Secondary Nameservers

There are two rules to running your own nameserver

  1. There must be at least two
  2. They must not have the same IP address

All registrars that I'm aware have an awkward JavaScript-only user interface, but I recommend name.com because they provide very quick e-mail support.

This is why a secondary nameservice is required , and buddyns.com provides an excellent solution. Once you create an account update your nameserver config to answer client queries so that they can keep the nameservers in sync.

#/var/named/etc/named.conf
options {
    allow-transfer {
        173.244.206.26;     # a.transfer.buddyns.com
        88.198.106.11;      # b.transfer.buddyns.com
    };
}

Next add them as secondary authority for each zone file.

;/var/named/master/eradman.com

        NS      b.ns.buddyns.com.
        NS      d.ns.buddyns.com.

Once this works locally, use a DNS health check such as intodns.com to verify that your configuration is correct.

E-mail

First write your hosting provider and ask them to add a PTR record for your IP address, then add an MX record for your domain

$ORIGIN entrproject.org.

                MX      50 vm.eradman.com.

Then stop sendmail and enable smtpd by following the instructions in the smtpd(8) man page.

Confirm that local relays are working by tailing /var/log/maillog or by running smtpd in the foreground with -dv

Now proceed to create rules in /etc/mail/smtpd.conf for virtual domains and SMTP relay

home_network = "74.65.88.110"

listen on lo0
listen on egress port 25
listen on egress port 587 tls certificate vm.eradman.com enable auth

map "aliases" { source db "/etc/mail/aliases.db" }

accept for local alias aliases deliver to mbox
accept from $home_network for all relay
accept from local for all relay

OpenSMTPd supports SSL/TLS and STARTTLS modes using the keyword https (normally port 465), and tls (normally port 587). Both of these protocols are SSL connections, but the latter switches to secure mode after connecting. If the client sends a username and password the connection is considered local and passes the last rule, allowing relay. The smtpd.conf(5) mage page suggests a means of generating your own certificate.

Mapping virtual users is as easy as defining a map and then adding a delivery rule

echo "eradman@entrproject.org eradman" >> /etc/mail/virtual
echo "ericshane@eradman.com eradman" >> /etc/mail/virtual
makemap /etc/mail/virtual

Then add a filter to smtpd.conf using the new hash

map "virtual" { source db "/etc/mail/virtual.db" }
accept from all for domain "entrproject.org" alias "virtual" deliver to mbox
accept from all for domain "eradman.com" alias "virtual" deliver to mbox

Other computers that are permitted to relay mail can simply add a relay via rule to their smtpd configuration

accept for any relay via "smtp://vm.eradman.com"

What next? Now that you have e-mail running, you can use the sendbug(1) utility to submit a PR!

Mail Retrieval over SSL

Nginx includes a very nice set of proxy modules for common mail protocols that provides a very nice mans of proving an SSL-gateway to simple clear-text protocols such as pop3d. These modules are not compiled in the Nginx base install, but they are enabled if you install Nginx from ports. The following addition to nginx.conf will enable the pop3s to pop proxy:

mail {
    server_name       vm.eradman.com;
    auth_http         localhost:9000;

    proxy               on;
    ssl_protocols           TLSv1 SSLv3;
    ssl_certificate         /etc/mail/certs/vm.eradman.com.crt;
    ssl_certificate_key     /etc/mail/certs/vm.eradman.com.key;

    pop3_auth         plain apop cram-md5;

    server {
        protocol    pop3;
        listen      995;
        ssl         on;
        pop3_auth   plain;
    }
}

While debugging the following line may also prove useful information

error_log /var/log/nginx-error.log info;

The only manual assembly required is to establish a mechanism for auth_http to use. Nginx will issue an HTTP GET to this service to request the parameters for the backend connection. Unfortunately Nginx doesn't have CGI support, so I resorted to writing a short script to be launched by inetd

#!/bin/sh
# mailauth - Nginx mail director for inetd

server=127.0.0.1

while read header
do
    line="$(echo $header | tr -d '\r')"
    case $line in
        "Auth-Protocol: pop3") port=110;;
        "Auth-Protocol: imap") port=143;;
        "Auth-Protocol: smtp") port=25;;
        "") break
    esac
done

print "HTTP/1.1 200 OK\r"
print "Content-type: text/plain\r"
print "Auth-Status: OK\r"
print "Auth-Server: ${server}\r"
print "Auth-Port: ${port}\r"
print "\r"
echo OK

This shell script returns 127.0.0.1 as the authentication server and a port number appropriate for each local service. Run it from inetd by making the following config changes

# /etc/services
mailauth        9000/tcp                # nginx mail proxy
# /etc/inetd.conf
pop3            stream  tcp     nowait  root    /usr/sbin/popa3d        popa3d
mailauth        stream  tcp     nowait  root    /var/www/cgi-bin/mailauth mailauth

Backups

Now that everything is in working order set up a small script to make a copy of each file system.

#/bin/sh

host=eradman@backups.eradman.com
df -h
/sbin/dump -0af - /home | ssh $host "cat > /vm/eradman.com/home.dump"
/sbin/dump -0af - /var  | ssh $host "cat > /vm/eradman.com/var.dump"
/sbin/dump -0af - /     | ssh $host "cat > /vm/eradman.com/root.dump"

See also Why's and When's of Backup and Restore by Gerhard Mourani for more information about backup levels and rotation.

$ 2013-06-11 12:56:50 -0400 $