rampke.de Archive

Running irssi as an interactive service

10 May 2014

I revamped my server-side IRC setup a bit. I run irssi there, mainly for logging, so I want it to always run, but only really use it interactively from time to time.

I used to have it running in a separate tmux session under my own user, started at boot-time through a crontab entry like

@reboot tmux -u new-session -d -s irssi /usr/local/bin/irssi

Now I wanted it to

  • run under the irc user
  • be controlled by runit
  • have all relevant files in /srv

This is on a new server running Debian Wheezy but should apply roughly on all UNIXoid systems.

Setting up a service with runit is quite simple, but a bit different to traditional (self-backgrounding) services: There is a run script that performs all necessary setup, and then execs the actual program. This is necessary to keep the same PID so the stop/restart functions work properly. Additionally, the service itself must not fork; it should just keep running. Optionally, stdout is piped into a dependent log service. Should either ever crash or exit, they will be restarted automatically.

The multi-user support in tmux is a bit weak, and it lacks any way to synchronously wait for the session to end without attaching to it. I settled on using screen instead– since they (by default) use different shortcuts it is quite convenient to attach to a screen session within my normal tmux.

The default Debian irc user has a home directory /var/run/ircd which does not exist unless ircd is installed (which I don’t need), so just symlink this:

ln -s /srv/irc /var/run/ircd

Install the packages:

apt-get install runit irssi screen

And create the scaffolding for the service:

mkdir -p /etc/sv/irssi /etc/sv/irssi/log/main /etc/sv/irssi/supervise /etc/sv/irssi/log/supervise
cat >/etc/sv/irssi/log/run <<EOF
exec svlogd -tt ./main
chmod +x /etc/sv/irssi/log/run

Finally, create the run script for irssi itself:


exec 2>&1

export HOME=/srv/irc
export LANG=en_US.UTF-8

echo "Starting irssi..."
exec chpst -uirc screen -S irssi -m -D irssi

Explanation of the steps:

  • exec 2>&1: fold stderr into stdout so it is captured in the logs (just in case; I do this in all run-scripts)
  • exports: the run script, and subsequently the service, have an almost empty environment. Set $HOME so screen can find .screenrc, and $LANG to work correctly with UTF-8 characters
  • echo: a marker to track restarts, as screen won’t produce any output
  • chpst: a tool that comes with runit to run the service in the context of another user. Easier to use than su and does not interfere with runit
  • screen -S irssi -m -D: set the session name to irssi so there is a fixed name to attach to, start detached but wait until the session finishes

Make it executable (chmod +x /etc/sv/irssi/run), and add /srv/irc/.screenrc to enable multiuser operation:

multiuser on
acladd <your username>

Then enable the service, it will start automatically:

ln -s ../sv/irssi /etc/service/irssi

and attach to it

screen -r irc/irssi

To detach without exiting, press ^A d.

OpenVPN with IPv6 and OpenBSD on a cheap VPS

02 January 2014

One day after the Kongress I finally finished my VPN setup. The problem with most “standard” VPN setups (including mine when I went to Hamburg) is that they are IPv4 only, leaving your IPv6 traffic unencrypted unless you block it completely. OpenVPN finally supports IPv6 over TUN devices as of 2.3.0.

I have a cheap VPS from Netcup. Since they moved to KVM installing any OS is relatively easy, for this machine I chose OpenBSD. The setup should be similar on FreeBSD and DragonFly since they also have PF, although their PF version may be older and the syntax therefore slightly different.

Netcup provide one IPv6 /64, but setting up IPv6 for OpenVPN requires a separate network block for the upstream internet connection and the VPN. One option is buying another /64, but this is relatively expensive (given the whole VPS is less than 10EUR/month) and requires a fax. Instead I used a SiXXS tunnel where IPv6 addresses are free. IPv6 traffic for the VPS itself uses the native IPv6.


  • a Netcup VPS with OpenBSD (5.4 or higher, otherwise OpenVPN is too old) and working networking
  • a client (tested with Debian Wheezy)

SiXXS setup

If you do not already have a SixXS account, sign up and request a tunnel and extra subnet. Let the subnet be routed to the tunnel. Note if you’re signing up new, your tunnel may need to be up for a while so you have sufficient ISK to request a subnet.

Set the tunnel to 6in4-static and enter the IPv4 address of your server. Set the MTU to 1480, 6in4 has less overhead than the other methods. On the server, add /etc/hostname.gif0:

tunnel <server IPv4> <PoP IP>
inet6 <Your IPv6> 128
dest <PoP IPv6>
mtu 1480
group egress

Bring it up with

# sh /etc/netstart gif0

your should now be able to ping6 <PoP IPv6>. Note that we did not add a default route to this interface, so normal IPv6 traffic will still use your VPS’ native connection (try ping6 sixxs.net).

VPN setup

DNS recursor

To send all DNS requests through the VPN, set up a DNS recursor. To install it

# pkg_add unbound

and make sure the VPN can access the DNS recursor. To do this, look for the access-control: lines in /var/unbound/unbound.conf and add

access-control: allow
access-control: <your SixXS subnet> allow

To have it started, add the following lines to /etc/rc.conf.local:

syslogd_flags="${syslogd_flags} -a /var/unbound/dev/log"
pkg_scripts="${pkg_scripts} unbound"

Then restart syslogd and start unbound

# /etc/rc.d/syslogd restart
# /etc/rc.d/unbound start

OpenVPN and system configuration

Install OpenVPN:

# pkg_add openvpn

Generate keys following the HOWTO. Create /etc/openvpn/tun0.conf:

port 1194
proto tcp # or udp, then change client config accordingly
dev tun0
# generate following the PKI howto
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh4096.pem # I use 4096-bit stuff
server # the IPv4 VPN range
server-ipv6 <your SixXS subnet>
push "route-ipv6 2000::/3" # route internet traffic through the VPN
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS"
keepalive 10 120
tls-auth ta.key 0 # This file is secret
user _openvpn
group _openvpn
status /var/log/openvpn-status.log
log-append  /var/log/openvpn.log
verb 3

Create /etc/hostname.tun0:

!cd /etc/openvpn; /usr/local/sbin/openvpn --config tun0.conf --daemon openvpn/tun0
group vpn

Enable IPv4 and IPv6 forwarding in /etc/sysctl.conf


and for the running system run

# sysctl net.inet.ip.forwarding=1
# sysctl net.inet6.ip6.forwarding=1

Set the following in /etc/pf.conf

set block-policy return
set skip on lo

# NAT for IPv4 VPN
match out on egress from to any nat-to egress:0

# default rules
block in
pass out

# normal traffic rules
block in on egress
# allow SSH
pass in on egress proto tcp from any to (egress) port 22
pass in proto icmp
pass in proto icmp6
pass in on vpn

# OpenVPN
pass in on egress proto { tcp udp } from any to (egress) port 1194

# IPv6 routing for VPN
pass in on vpn from <your SixXS IPv6 block> to ! (egress) route-to (gif0 <PoP IPv6>)

# allow incoming tunnel traffic
pass in on egress proto 41 from <PoP IPv4> to (egress)

Adjust the last lines to your SixXS blocks. It makes sure that IPv6 traffic from the VPN is routed out through SixXS. Incoming traffic is not allowed, if you want this add a line like

pass in on gif0 from any to <your IPv6 block> <further limits> route-to (tun0 <Your IPv6>)

(untested). Incoming Proto41 traffic on the other hand is explicitly allowed, otherwise the packets never make it to the gif interface unless there has been outgoing traffic recently which created an entry in the state table.

Load the firewall configuration with

# pfctl -f /etc/pf.conf

and bring the VPN up with

# sh /etc/netstart tun0

You should now be able to connect to it. The client configuration is nothing special:

dev tun
proto tcp
remote <your server> 1194
resolv-retry infinite
ca ca.crt
cert client.crt
key client.key
ns-cert-type server
tls-auth ta.key 1
verb 3

# Debian/Ubuntu: set name server
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

If your client has OpenVPN 2.3 or higher, IPv6 will be set up correctly now. Try

# ping6 sixxs.net

on the client.


  • Added the pass in proto 41 line. This is necessary so the tunnel can work even if the VPN is not in use.
  • removed redirection of port 443, it’s not relevant to this


14 November 2012

DailyBooth is going down. Here is the dump of my posts there.


19 June 2012

There’s a new BSD in town (via). The first snapshot doesn’t work out of the box, but there’s a workaround:

When booting from the installer CD you will get errors like uid 0 on /: file system full clogging up the screen right after the disk setup. Press ctrl+Z to get to the shell, then

mv /tmp/* /mnt/tmp
rm -r /tmp
ln -s /mnt/tmp /tmp

This has to be done after the disk setup so the filesystems are already created and mounted.

and installation will continue. Choose http as install source and enter the server name mirror1.us.bitrig.org. It complained about the SHA256 sums of the downloaded files not matching what is expected, but it worked anyway.

EDIT: Snapshots seem to be gone, can’t find any currently. Dunno what’s up with that…

DIY VPN with DragonFly, PF and OpenVPN

27 May 2012

I have a server running DragonFly that I wanted to use as a VPN endpoint so I no longer have to rely on third-party VPNs jsut to get out of an insecure WiFi. These instructions, as they stand, will probably only work on Dragonfly (NAT syntax changed in OpenBSD recently; DragonFly uses pf from OpenBSD 4.4, FreeBSD 9 uses pf from OpenBSD 4.5).

The first step was getting pf up and running. All in all, the following ruleset worked for me:

int_if= "{ tun0 tun1 }"

service_ports="{ http https xmpp-server xmpp-client auth ftp >49151 }"

#table <spamd> persist
#table <spamd-white> persist

# don't touch machine-local traffic
set skip on lo
set block-policy return

scrub in

nat on $ext_if inet from to any -> ($ext_if:0)

# filtering
block in
pass out quick inet keep state
pass out quick inet6 keep state

pass in on $ext_if proto tcp to ($ext_if) port ssh keep state

pass in on $ext_if proto tcp to ($ext_if) port $service_ports keep state

# allow ICMP
pass proto icmp keep state
pass proto icmp6 keep state

# OpenVPN
pass in on $ext_if proto udp to ($ext_if) port 1194:1195 keep state
pass in on $int_if keep state
pass on $int_if proto icmp keep state

This already includes the rules to make the two VPNs work later on. Also, this ruleset it very lenient when it comes to both outgoing traffic and ICMP – everything is allowed there. I may or may not restrict this further in the future, but for now I mostly needed the NAT capabilities of pf. For some reason I needed to specify IPv4 and IPv6 rules separately, otherwise I’d get no IPv6 traffic out and lists didn’t work either. Also, DragonFly’s pf seems to have no state as default.

To activate pf, set


in /etc/rc.conf and load it with

sudo /etc/rc.d/pf start

When changing the ruleset, update it with

sudo /etc/rc.d/pf reload

To get the server to actually do routing, set the sysctl net.inet.ip.forwarding=1 both in /etc/sysctl.conf (so it is persistent) and (to avoid rebooting) directly:

sudo sysctl net.inet.ip.forwarding=1

Next up is configuring the VPNs. I decided to create two separate networks, one being NATed through the server to the outside world, one just for connecting to services I don’t want to expose publicly on the server (or possibly in the future, other VPN clients).

First, install OpenVPN:

cd /usr/pkgsrc/net/openvpn; bmake install clean

assuming you have pkgsrc already set up. Copy /usr/pkg/share/examples/rc.d/openvpn to /usr/pkg/etc/rc.d and set openvpn_enable=”YES” in rc.conf.

Create the OpenVPN keys using easy-rsa. Copy /usr/pkg/share/openvpn/easy-rsa somewhere else, edit vars in that copy to your liking, then run

. ./vars
./build-key-server <server hostname>
./build-key <client hostname>

there to create a server and a client certificate. Also generate a TLS Auth key with openvpn –genkey –secret ta.key and copy the dh????.pem, _.crt_, _ca.crt_ and _ta.key_ to _/usr/pkg/etc/openvpn_. If your client is a Mac with [Tunnelblick](http://code.google.com/p/tunnelblick/), copy the client certificate, client key, _ta.key_ and _ca.crt_ into a folder called _.tblk_ along with this configuration file (call it _config.ovpn_):


dev tun
proto udp

remote grade.so 1194

resolv-retry infinite
ca ca.crt
cert <client name>.crt
key <client name>.key
ns-cert-type server

tls-auth ta.key 1

verb 3

The server-side side configuration goes into /usr/pkg/etc/openvpn/server.conf and contains:

local <server IP> #this is optional

port 1194

proto udp

dev tun0

ca ca.crt
cert <server name>.crt
key <server name>.key

dh dh2048.pem
;dh dh1024.pem # if you went for 1024 bit RSA

# this is the client IP range
# note that this is the same as the 'nat' line in pf.conf

ifconfig-pool-persist ipp.txt

# push default gateway to clients,
# telling them to redirect all traffic through the VPN
push "redirect-gateway def1 bypass-dhcp"

# push a good DNS server too
# if you don't the local, un-VPNed one might still be in use
push "dhcp-option DNS"

# we want clients to see each other

keepalive 10 120

tls-auth ta.key 0


user nobody
group nobody


status /var/log/openvpn-status.log

verb 3

Start OpenVPN with sudo /usr/pkg/etc/rc.d/openvpn start and you should be able to connect to the internet through the VPN (after you installed the client configuration of course).

The configuration for the second VPN is very simple – just change the port to 1195 in both client and server config (create copies), and in the server configuration file replace

# push default gateway to clients,
# telling them to redirect all traffic through the VPN
push "redirect-gateway def1 bypass-dhcp"

# push a good DNS server too
# if you don't the local, un-VPNed one might still be in use
push "dhcp-option DNS"


# push only routes to other VPN clients and server IPs
push "route"

so the clients know that everything in should go through the VPN. With this VPN you can connect to services bound e.g. to on the server which you don’t want to be reachable for outsiders.