Feb 192017
HAProxy, docker-compose and Let's Encrypt

Linode started to offer US$5 VMs and they are available in Tokyo (9ms ping as opposed to 122ms ping to California), so I could not resist to get another one and use it for some experimenting which I simply don’t dare to do on this very blog page (and my wife is using it for work too).



  • 2 web servers serving web server stuff (a simple static index.html serves here)
  • 3 virtual web addresses:
    • first web server
    • second web server
    • round-robin web server which serves data from the first and second web server
  • Everything with SSL without any warning from web browsers


  • 1 VM with a public IP address
  • 3 FQDNs pointing all to above IP address
    • www1.qw2.org
    • www3.qw2.org
    • www4.qw2.org
  • 2 web servers (www1, www3)
  • 1 load-balancer (www4)
  • 3 certificates for above FQDNs

Let’s Encrypt Certificates

I use acme.sh for my few certificate needs. This is how to get a new certificate issued:

./acme.sh --issue --dns dns_linode --dnssleep 1200 -d www4.qw2.org

This is using the DNS API from Linode (who hosts my DNS records). See more details here. It creates the required TXT record and removes it later again. I found that 1200 seconds wait time works. 900 does not always. I end up using 10 seconds, suspend the acme.sh command (shell ^Z), and use “dig -t TXT _acme-challenge.www4.qw2.org” until it returns some TXT record. Then continue the suspended acme.sh command.

You should then have a new directory www4.qw2.org in your acme.sh directory with those files:

harald@blue:~/.acme.sh$ ls -la www4.qw2.org/ 
total 36 
drwxr-xr-x  2 harald users 4096 Feb 19 10:16 . 
drwx------ 17 harald users 4096 Feb 19 00:26 .. 
-rw-r--r--  1 harald users 1647 Feb 19 10:16 ca.cer 
-rw-r--r--  1 harald users 3436 Feb 19 10:16 fullchain.cer 
-rw-r--r--  1 harald users 1789 Feb 19 10:16 www4.qw2.org.cer 
-rw-r--r--  1 harald users  517 Feb 19 10:16 www4.qw2.org.conf 
-rw-r--r--  1 harald users  936 Feb 19 00:26 www4.qw2.org.csr 
-rw-r--r--  1 harald users  175 Feb 19 00:26 www4.qw2.org.csr.conf 
-rw-r--r--  1 harald users 1675 Feb 19 00:26 www4.qw2.org.key

You’ll need the fullchain.cer and the private key www4.qw2.org.key later.

Repeat for www1 and www3 too.

Note that the secret key is world readable. the .acme.sh directory is therefore secured with 0700 permissions.

Setting up the Web Servers

Using lighttpd herte. The full directory structure:

harald@lintok1:~$ tree lighttpd 
├── 33100 
│   ├── etc 
│   │   ├── lighttpd.conf 
│   │   ├── mime-types.conf 
│   │   ├── mod_cgi.conf 
│   │   ├── mod_fastcgi.conf 
│   │   ├── mod_fastcgi_fpm.conf 
│   │   └── www1.qw2.org 
│   │       ├── combined.pem 
│   │       └── fullchain.cer 
│   └── htdocs 
│       └── index.html 
├── 33102 
│   ├── etc 
│   │   ├── lighttpd.conf 
│   │   ├── mime-types.conf 
│   │   ├── mod_cgi.conf 
│   │   ├── mod_fastcgi.conf 
│   │   ├── mod_fastcgi_fpm.conf 
│   │   └── www3.qw2.org 
│   │       ├── combined.pem 
│   │       └── fullchain.cer 
│   └── htdocs 
│       └── index.html 
└── docker-compose.yml

Using the lighttpd.conf is simple and can be done in 5 or 10 minutes. The part for enabling https is this:

$SERVER["socket"] == ":443" { 
ssl.engine    = "enable" 
ssl.pemfile   = "/etc/lighttpd/www1.qw2.org/combined.pem" 
ssl.ca-file   = "/etc/lighttpd/www1.qw2.org/fullchain.cer" 

fullchain.cer is the one you get from the Let’s Encrypt run. “combined.pem” is created via

cat fullchain.cer www1.qw2.org.key > combined.pem

Here the content of docker-compose.yml:

  image: sebp/lighttpd 
    - /home/harald/lighttpd/33100/htdocs:/var/www/localhost/htdocs 
    - /home/harald/lighttpd/33100/etc:/etc/lighttpd 
    - 33100:80 
    - 33101:443
  restart: always
  image: sebp/lighttpd 
    - /home/harald/lighttpd/33102/htdocs:/var/www/localhost/htdocs 
    - /home/harald/lighttpd/33102/etc:/etc/lighttpd 
    - 33102:80 
    - 33103:443
  restart: always

To start those 2 web servers, use docker-compose:

docker-compose up

If you want to have a reboot automatically restart the service, then use do “docker-compose start” afterwards which installs a service.

To test, access: http://www1.qw2.org:33100, https://www1.qw2.org:33101, http://www3.qw2.org:33102, https://www3.qw2.org:33103

They all should work, and the https pages should find a proper security status (valid certificate, no name mismatch etc.).

Adding HAProxy

HAProxy (1.7.2 as of the time of writing) can be the SSL termination and forwarded traffic between the web server and HAProxy is unencrypted (resp. can be encrypted via another method), or HAProxy can simply forward traffic. Which one is preferred depends on the application. In my case it makes most sense to let HAProxy handle SSL.

First the full directory structure:

├── docker-compose.yml 
└── etc 
    ├── errors 
    │   ├── 400.http 
    │   ├── 403.http 
    │   ├── 408.http 
    │   ├── 500.http 
    │   ├── 502.http 
    │   ├── 503.http 
    │   ├── 504.http 
    │   └── README 
    ├── haproxy.cfg 
    └── ssl 
        └── private 
            ├── www1.qw2.org.pem 
            ├── www3.qw2.org.pem 
            └── www4.qw2.org.pem

The www{1,3}.qw2.org.pem were copied from the lighttpd files.


harald@lintok1:~/haproxy/etc$ cat haproxy.cfg  
        user nobody 
        group users 
        # Admin socket 
        stats socket /var/run/haproxy.sock mode 600 level admin 
        stats timeout 2m 
        # Default SSL material locations 
        #ca-base /usr/local/etc/haproxy/ssl/certs 
        #crt-base /usr/local/etc/haproxy/ssl/private 
        # Default ciphers to use on SSL-enabled listening sockets. 
        # For more information, see ciphers(1SSL). 
        tune.ssl.default-dh-param 2048 
        ssl-default-bind-options no-sslv3 no-tls-tickets 
        ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA
        ssl-default-server-options no-sslv3 no-tls-tickets 
        ssl-default-server-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-R
    log     global 
    mode    http 
    option  dontlognull 
    timeout connect 5000 
    timeout client  50000 
    timeout server  50000 
    errorfile 400 /usr/local/etc/haproxy/errors/400.http 
    errorfile 403 /usr/local/etc/haproxy/errors/403.http 
    errorfile 408 /usr/local/etc/haproxy/errors/408.http 
    errorfile 500 /usr/local/etc/haproxy/errors/500.http 
    errorfile 502 /usr/local/etc/haproxy/errors/502.http 
    errorfile 503 /usr/local/etc/haproxy/errors/503.http 
    errorfile 504 /usr/local/etc/haproxy/errors/504.http 
    stats enable 
    stats uri /stats 
    stats realm Haproxy\ Statistics 
    stats auth admin:SOME_PASSWORD 
frontend http-in 
    bind *:80 
    acl is_www1 hdr_end(host) -i www1.qw2.org 
    acl is_www3 hdr_end(host) -i www3.qw2.org 
    acl is_www4 hdr_end(host) -i www4.qw2.org 
    use_backend www1 if is_www1 
    use_backend www3 if is_www3 
    use_backend www4 if is_www4 
frontend https-in 
    bind *:443 ssl crt /usr/local/etc/haproxy/ssl/private/ 
    reqadd X-Forward-Proto:\ https 
    acl is_www1 hdr_end(host) -i www1.qw2.org 
    acl is_www3 hdr_end(host) -i www3.qw2.org 
    acl is_www4 hdr_end(host) -i www4.qw2.org 
    use_backend www1 if is_www1 
    use_backend www3 if is_www3 
    use_backend www4 if is_www4 
backend www1 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s1 www1.qw2.org:33100 maxconn 32 
backend www3 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s3 www3.qw2.org:33102 maxconn 32 
backend www4 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s4-1 www1.qw2.org:33100 maxconn 32 
    server s4-3 www3.qw2.org:33102 maxconn 32 
listen admin 
    bind *:1936 
    stats enable 
    stats admin if TRUE

Replace “SOME_PASSWORD” with an admin password for the admin user who can stop/start backends via the Web UI.

Here the docker-compose.yml file to start HAProxy:

harald@lintok1:~/haproxy$ cat docker-compose.yml  
  image: haproxy:1.7 
    - /home/harald/haproxy/etc:/usr/local/etc/haproxy 
    - 80:80 
    - 443:443 
    - 1936:1936
  restart: always

To start haproxy, do:

docker-compose up

The Result

Now http://www1.qw2.org as well as https://www1.qw2.org works. No need for specific ports like 33100 or 33101 anymore. Same for www3.qw2.org. www4.qw2.org is a round-robin of www1 and www3, but it’s using the www4 certificate when using https. In all cases HAProxy terminates the SSL connections and it’s presenting the correct certificates.

Related: on http://www4.qw2.org:1936/haproxy?stats you can see the statistics of HAProxy.

Connecting it all all

Running 2 web servers plus the load-balancer with all of them internally connected and only the load-balancer visible on port 80 resp. 443 needs a new docker-compose.yml (changed to version 3 syntax) and a slight matching change haproxy.conf file:

harald@lintok1:~/three$ cat docker-compose.yml 
version: '3' 
    image: sebp/lighttpd 
      - /home/harald/lighttpd/33100/htdocs:/var/www/localhost/htdocs 
      - /home/harald/lighttpd/33100/etc:/etc/lighttpd 
      - 80 
    restart: always 
    image: sebp/lighttpd 
      - /home/harald/lighttpd/33102/htdocs:/var/www/localhost/htdocs 
      - /home/harald/lighttpd/33102/etc:/etc/lighttpd 
      - 80 
    restart: always 
    image: haproxy:1.7 
      - /home/harald/three/haproxy/etc:/usr/local/etc/haproxy 
      - 80:80 
      - 443:443 
      - 1936:1936 
    restart: always

No need for lighttpd to handle SSL anymore (no more port 443 needed to be exposed at all). Only the HAProxy is visible from outside. Small changes are needed on haproxy.conf, but only in the backend section:

backend www1 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s1 lighttpd-33100:80 maxconn 32 
backend www3 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s3 lighttpd-33102:80 maxconn 32 
backend www4 
    balance roundrobin 
    option httpclose 
    option forwardfor 
    server s4-1 lighttpd-33100:80 maxconn 32 
    server s4-3 lighttpd-33102:80 maxconn 32

And with “docker ps” we can see what’s happening under the hood of docker-compose:

harald@lintok1:~/three$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS         
     PORTS                                                              NAMES 
742a2e5388f2        sebp/lighttpd       "lighttpd -D -f /e..."   4 minutes ago       Up 3 minutes   
     80/tcp                                                             three_lighttpd-33100_1
9d4c61e6c162        sebp/lighttpd       "lighttpd -D -f /e..."   4 minutes ago       Up 3 minutes   
     80/tcp                                                             three_lighttpd-33102_1 
2e41dfa26ac9        haproxy:1.7         "/docker-entrypoin..."   4 minutes ago       Up 3 minutes>80/tcp,>443/tcp,>1936/tcp   three_haproxy_1 




Jan 092017

One problem for using HTTPS was in the past that sharing DNS names with one web server was not supported. HTTP can handle this for longer.

However HTTPS also supports virtual HTTPS servers: SNI does that.

And here is how to use it with HAProxy:

frontend https-in 
        bind *:443 ssl crt /etc/haproxy/ssl/private/ 
        reqadd X-Forward-Proto:\ https 
        acl is_site1 hdr_end(host) -i www1.qw2.org 
        acl is_site2 hdr_end(host) -i www2.qw2.org 
        use_backend site1 if is_site1 
        use_backend site2 if is_site2

All the magic is in the bind line where a directory with PEM certificates (concat of fullchain.cer and the key)

Now you can have https for everything and HAProxy will handle all the secure connectivity for you.

Sep 222016

I like my switch/routers from Mikrotik. While not flawless, they are working well, have a descent command line interface and a usable web (and Windows) GUI. They got all features I need and are stable.

One missing feature however was that DHCP leses did not get a DNS entry. The simple workaround was that stuff which should get DNS gets a static IP. Anything else doesn’t and thus is not reachable by DNS. Was not a big deal until I used Vagrant which can build VMs (via VirtualBox). Now I got plenty VMs which I simply bridge on the normal LAN. But in order to connect to them outside of “vagrant ssh nodeX”, I needed to have their IP. Vagrant can tell me, as can the VM itself when I connect via “vagrant ssh”, but all this is way more complex than simply using DNS. dnsmasq does that automatically, but not the DHCP/DNS combo on RouterOS.

Scripts to the rescue!

https://www.tolaris.com/2014/09/27/synchronising-dhcp-and-dns-on-mikrotik-routers/ has a nice one which does what it’s supposed to do. Relying on the TTL to be different from static DNS entries, it’ll create or delete DNS records which according to DHCP leases should or should not exist.


One important hint: you need to allow the script to read/write “things”. And the scheduler when running the script.


TTL for DHCP is set to 15min. TTL for static enteries is 1d. The script runs every 5min.

Apr 072016

Today we got an email from our Internet provider that we seem to attack an IP address within the provider’s network. Seemed to attack port 53. They ask us to check for viruses etc. The provider is Japanese, so the email was naturally Japanese too. Did not make it easier to understand for me.

Everyone knows, port 53 is DNS. Why would we or a virus try to connect port 53 on a non-server?

I checked all computers (the Windows machines was a natural first suspect), but all was clean. And then it dawned me: DNS Amplification attack! Using our router.
A quick check on the router showed more activity than normal, so it was confirmed that the router is the culprit.
The NAT connection table then promptly showed about 2000 connections with more and more being created while old ones were closed due to inactivity.

How to fix this? Disable remote DNS requests! Except remote is anything non-local to the router which also disabled the internal network from using DNS as all machines in our LAN use our router as DNS server (resp. relay).

The next attempt was better: set up the firewall to drop incoming DNS requests which come from the ppp interfaces.
Now I got about 50 active connections again (that’s normal), no odd DNS requests, and fw-dns-amp about 500 packets per second are being dropped. That accumulates quite fast. 280k packets dropped while writing this article.

The magic fix looks like this:

/ip firewall filter add chain=input action=drop protocol=udp in-interface=all-ppp dst-port=53 log=yes log-prefix=Ext-Incoming-DNS

That was interesting. Relatively easy to defeat. I’m surprised this is not configured by default, but then, I have a rather non-user-oriented router where it’s expected that the admin knows what he’s doing…
I’ll have to look a bit more into security of the router in regards to DoS attacks and logging and notifications for unusual traffic.

Feb 282016
SoftEther - Part 2

Wanted to put a VPN gateway into a Docker container. Turned out to be difficult since the container needs to accept ESP traffic for IPSec, which I could not make work.

However running a SoftEther VPN server turns out to be easier than expected: Have the binaries, and a vpn_server.config file, and off you go. To create the config file, use the Windows management utility.

On the client side it’s rather simple. Windows client software is neat and straightforward. Linux is not much harder:

# Download softether-vpnclient-v4.19-9599-beta-2015.10.19-linux-arm_eabi-32bit.tar.gz to e.g. /var/tmp/
cd /usr
tar xfv /var/tmp/ softether-vpnclient-v4.19-9599-beta-2015.10.19-linux-arm_eabi-32bit.tar.gz
cd vpnclient
make i_read_and_agree_the_license_agreement
./vpnclient start
2 (Management of VPN Client)
ENTER (picks localhost)
NicCreate VIRTUALNIC (e.g. box2)
AccountCreate ACCOUNTNAME (e.g. box2)
vpn.domain.org:443 (VPN Server Host Name and Port Number)
USERNAME (e.g. harald)
box2 (Virtual NIC)
AccountPasswordSet ACCOUNTNAME
PASSWORD (password for USERNAME)
PASSWORD (repeat)
standard (standard or Radius)
# Autostart:
AccountStartupSet ACCOUNTNAME
# Connect:
AccountConnect ACCOUNTNAME
# Check
AccountStatusGet ACCOUNTNAME

And that’s it. It’ll create a virtual NIC vpn_box2 and whenever you start vpnclient, it’ll create it and connect.

E.g. have this in /etc/rc.local:

( /usr/bin/vpnclient start ; sleep 10 ; ifconfig vpn_box2 netmask up ) &

or alternatively if you can take any IP address:

( /usr/vpnclient/vpnclient start ; sleep 10 ; dhclient vpn_box2 ) &

In case of slow connection/computers, increase the 10s delay to more. I use 20s for my AllWinner A20 CPUs.

Mar 222015
Toggling LEDs

Here was a great start and given that I did not know Lua a lot (and I am sure I don’t still), it was a nice little challenge to expand the example to include all 6 LEDs.

Here the result:


myled={ 4, 3, 2, 1, 5, 0, 6, 7, 8 }

start_init = function()
local i
for i=1,6 do
 gpio.mode(myled[i], gpio.OUTPUT)
sendFileContents = function(conn, filename) 
    if file.open(filename, "r") then 
        --conn:send(responseHeader("200 OK","text/html"))
        local line=file.readline()  
        if line then  
        until not line  
        conn:send(responseHeader("404 Not Found","text/html"))
        conn:send("Page not found")
responseHeader = function(code, type) 
    return "HTTP/1.1 " .. code .. "\nConnection: close\nServer: nunu-Luaweb\nContent-Type: " .. type .. "\n\n";  
httpserver = function () 
        conn:send(responseHeader("200 OK","text/html")); 
        fflag, findex, pin=string.find(request, "gpio=(%d+)")
        if fflag and pin>=1 and pin<=6 then
          print("Changing pin "..pin.." to ")
          if mystate[pin]==0 then
               gpio.write(myled[pin], gpio.LOW)
            local i
            for i=1,6 do
             if mystate[i]==0 then
             conn:send("<div><input type=\"checkbox\" id=\"chbox"..i.."\" name=\"chbox"..i.."\" class=\"switch\" onclick=\"loadXMLDoc("..i..")\" "..preset.." />")
             conn:send("<label for=\"chbox"..i.."\">GPIO "..i.."</label></div>\n")
        conn = nil  


  1. I use only the 6 red LEDs on the dev board I have
  2. I had to shorten the text sent to the web client from “checkbox2” to “chbox2” as otherwise the last characters of those 6 lines were missing. That showed when some LEDs were on and I reloaded the page. Then toggle 6 went missing. Thus don’t send too much too fast.


Mar 222015
ESP8266 - IoT, here we come

The Internet of Things was for the longest time limited to bigger things. Costs of US$100 and more for a IP connected device was a given.

Arduino boards like this Ethernet Shield with a W5200 chip still needed a separate CPU. And it was not wireless, so add in a cable and a fraction of a switch. Newer possibilities are Raspberry Pi + USB WLAN stick (<US$40). Those were a bit expensive and quite large if all you want is switch on/off something small like a lamp.

Then came solutions like Spark Core which were relatively cheap (<US$40) and small. Slowly getting there.

And then the ESP8266 showed up, making most other solutions oversized and overpriced: About US$3 for the naked module (ESP-12) and US$11 for a small dev module. And you can program it in C or Lua or JavaScript. And not only is it cheap and quite capable, but it is also small, low-power and it’s easy to work with and connect it to various interfaces: GPIO, I2C, SPI, RS232, PWM etc.

Here an example of the blinking LED in Lua:

gpio.mode(4, gpio.OUTPUT)

function switchled4()
 if led4==0 then
  gpio.write(4, gpio.LOW)
  gpio.write(4, gpio.HIGH)


This leds the LED connected to GPIO4 (internal numbering, just like Arduino does) blink. And here a link to an example which uses a web page with AJAX to toggle 2 LEDs.

All in all, there is no reason to NOT allow pretty much anything to be connected to your WiFi network.


Feb 112014

SoftEther works (see my previous post), but it needs an extra install of software, while PPTP is pretty much standard for many operating systems. So we’ll set this up.

It’s actually very easy too

Server side

Debian server: install some packges:

aptitude install pptpd

/etc/pptpd.conf (I removed all comments here):

option /etc/ppp/pptpd-options

/etc/ppp/pptpd-options (again, no comments):

mtu 1490
mru 1490

Add this to /etc/rc.local:

/sbin/iptables-restore </etc/iptables.save

Setting up routing and firewall:

iptables -A FORWARD -s -d -j ACCEPT
iptables -A FORWARD -s -j REJECT

Edit /etc/sysctl.conf to enable IP fording:


Enable sysctl.conf changes:

sysctl -p

Edit /etc/ppp/chap.secrets to have all accounts, e.g.:



Client side

Debian: install some packages

 aptitude install pptp-linux

Create /etc/ppp/peers/BoxPPTP (BoxPPTP is the name of the connection):

pty "pptp PPTPSERVERNAME --nolaunchpppd"
name harald
remotename BoxPPTP
file /etc/ppp/options.pptp
ipparam BoxPPTP is the IP the client wants to have.



Add your account in /etc/ppp/chap-secrets:


Add this to /etc/network/interfaces:

auto ppp0
iface ppp0 inet ppp
  provider BoxPPTP
  post-up sleep 2 ; route add -net netmask gw

To enable the PPTP connection, do:

ifup ppp0

Check via:

# ip addr list ppp0
20: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1486 qdisc pfifo_fast state UNKNOWN qlen 3
    inet peer scope global ppp0
# ip route list
default via dev eth0 dev eth0  proto kernel  scope link  src via dev ppp0 dev ppp0  proto kernel  scope link  src

At this point you can ping the PPTP server ( in this case) as well as all other clients as long as they are not firewalled.


Mar 232012
Synology DS212j

Finally got a small NAS. Although it was tempting to get a bigger/faster one with 5 or  4 disk slots and a fast CPU, it’s way overkill for my purpose, so in the end, I went for a small DS212j plus a (for now) 3TB disk.

It’s plenty fast (75MB/s read via NFS), the GUI is awesome, the capabilities more than sufficient. It has some kinks though:

  • The OS is on the disk and not in flash memory.
  • If you have 2 different size disks, then if you create a mirrored volume, the rest of the space goes unused instead of being able to use it as a non-mirrored volume.
  • Volumes always take full disks (or what is left after the OS is copied on them)
  • To enable NFS, you need to first enable it, and then create shares (which are usually for Samba shares), and there enable NFS sharing too.
  • To enable home directories, click on the user modules and click there on “User Home” and enable it and say which volume to use.
  • Disk groups names are hardcoded: Disk group 1, Disk group 2 etc.
  • Volume names are hardcoded: Volume 1, Volume 2 etc. They map to mount points called /volume1, /volume2 etc.
  • The media server does not ask for the location of files. It defines it to be on a volume you pick.

If you have only 2 disks, do yourself a favor and get 2 of identical size and use a RAID-1 (or their hybrid volumes). Alternatively expect no mirroring whatsoever. If you have more disks (4 would be a good start), then this is much less of a problem.

Nov 052011
GLANTANK - Resurrected

I have not used my GLANTANK for quite a while. Now it has a new purpose: I use as a server for lsync. lsyncd is what I was looking for for a while: it synchronizes directories a la rsync (it’s actually using rsync for that), but it is using the inotify feature of the Linux kernel which informs a process that a file has changed. So instead of scanning every (say) 1h thousand of files, it copies the ones which are modified much sooner and does not need a full scan of all files except on startup.

The old Debian installation was outdated, so I wanted to re-install Debian Linux on the GLANTANK first. I used the same instructions in the past and it worked as expected. So I was hopeful this time too. ssh never started up though.

The only way to see something happening then is to use a serial console. See also here for some pictures. Pins are 1:3.3V,  2:RxD, 3:TxD, 4:GND. 115200 bps and 8N1.

And the problem is that the latest kernel 2.6.32-5-iop32x has no driver for the GLANTANK disk interface, and that stops the installation process. The fix is on the Debian bug list and that solves it.

Next problem are the not-so-quiet fans. There’s a program to control them called fanctld. Needs kernel header files and gcc-4.3 to create a working fandrv.ko kernel module.

Update: Plugging in and out of disks with a cable which is soldered to the mainboard is a bad idea: the cable broke and no disk worked afterwards. Well, it was fun while it lasted.  Which was until now.