2021-10-23

vger/inetd/nginx on alpineLinux

#gemini

#software

Today I got somewhat adventureous and decided to try the vger/inetd/nginx trick on alpineLinux, too. Of course, I got reminded quite soon, that alpineLinux is built on musl and busybox rather than glibc and GNU userland. But I do like the fact that I can have a Linux system without python and perl and translations and a whole lot of other geek and automatic things. YMMV.

I'll list the commands below. I'm not sure, if everything is right. Replacing /etc/nginx/nginx.conf wholesale is not elegant --- but this is a "does it work?" experiment.

Install some more packages. This list is probably incomplete:

# as root
apk add git clang gcc g++ libstdc++6 libc6-compat libbsd-dev linux-headers

clone the vger git repo and compile the code:

# as user
git clone https://tildegit.org/solene/vger.git
cd vger
make CC=clang

This produces three warnings, the severity of them is unclear to me.

Add a user under which vger shall run (this might be irrelevant after all, possibly changing user is completely ignored):

# as root
adduser -S -s /bin/false  vger

Create a minimal gemini capsule:

# as root
mkdir -p /var/gemini
cat <<EOF > /var/gemini/index.gmi
# vger on alpineLinux

Just to say: yes, I can!
~ew
EOF
chown -R vger: /var/gemini

Install vger

# as root
cp /home/user/vger/vger /usr/local/bin/vger
chmod 0755 /usr/local/bin/vger
mkdir -p /usr/local/man/man8
cp /home/user/vger/vger.8 /usr/local/man/man8/
chmod 0644 /usr/local/man/man8/vger.8

Install and configure inetd to listen on port 11965 and call vger on requests, start inetd:

# as root
apk add busybox-extras
cat <<EOF >>/etc/inetd.conf
11965           stream  tcp     nowait  vger /usr/local/bin/vger vger -d /var/gemini
EOF
openrc --service inetd start

At this point one can ask netcat to reqeust the page:

# as user
printf "gemini://127.0.0.1/index.gmi\r\n" | nc 127.0.0.1 11965
20 text/gemini; 
# vger on alpinelinux

Just to say: yes, I can!
~ew

Very nice! Inetd/vger do their trick!

Create a cert (no garantees that this is really good, it just happen to work):

# I did this as root
mkdir cert
cd cert/
openssl req -x509 -newkey rsa:2048 -keyout key-ceres:1965.rsa -out cert-ceres:1965.pem -days 3655 -nodes -subj "/CN=alpine.standalone"
cp cert-ceres\:1965.pem /etc/ssl/
chmod 0644 /etc/ssl/cert-ceres\:1965.pem
cp key-ceres\:1965.rsa  /etc/ssl/private/
chmod 0640 /etc/ssl/private/key-ceres\:1965.rsa

Configure nginx to accept TLS requests and forward the plain text request to inetd.

apk add nginx nginx-mod-stream
cd  /etc/nginx/
cp nginx.conf nginx.conf.dist
cat <<EOF > /etc/nginx/nginx.conf
# 2021-10-23 ew

worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
load_module "modules/ngx_stream_module.so";

worker_rlimit_nofile 1024;

events {
    worker_connections  5;
}

stream {
    log_format basic '$remote_addr $upstream_addr [$time_local] '
                     '$protocol $status $bytes_sent $bytes_received '
                     '$session_time';

    access_log /var/log/nginx/gemini-access.log basic;
    error_log  /var/log/nginx/gemini-error.log;

    upstream backend {
        hash $remote_addr consistent;
        server 127.0.0.1:11965;
    }
    server {
        listen 1965 ssl;
        ssl_certificate /etc/ssl/cert-ceres:1965.pem;
        ssl_certificate_key /etc/ssl/private/key-ceres:1965.rsa;
        proxy_pass backend;
    }
}
EOF
openrc --service nginx start

As mentioned, this is not elegant. The default nginx.conf is distributed over several files, and I'm sure the configuration can be fit into this structure. But that is not the point here.

I checked with netstat whether everyone involved is listening. And yes, they are:

alpine:~# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:11965           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:1965            0.0.0.0:*               LISTEN
tcp        0      0 :::ssh                  :::*                    LISTEN
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     SEQPACKET  LISTENING        487 /run/udev/control

So, I point a client on my Debian GNU/Linux workstation to the gemini capsule:

gcat gemini://192.168.10.206/index.gmi
20 text/gemini; 
# vger on alpinelinux

Just to say: yes, I can!
~ew

And yes indeed, the text appears as hoped for. Not bad for half an afternoon of fiddling!

There might be dragons!

~ew

Home