Tutorial: zero-resource D web backends for occassionally-used services

WebFreak001 d.forum at webfreak.org
Mon Apr 5 23:03:14 UTC 2021


Hi all, I'm currently moving my server to new hardware and with 
that I'm porting some of my D applications to be more efficient. 
For this I have found one cool thing: SystemD .socket files.

SystemD .socket files are basically wrapping any program in a 
CGI, which is a lot like just having a server running the entire 
time. You then put the port you assigned to the socket behind a 
reverse proxy like caddy or nginx and it effectively always 
spawns the D program whenever there is a request with the raw 
HTTP request as stdin and expecting an output in stdout.

[My last 
post](https://forum.dlang.org/thread/dkabudjgyqcwnbfnwjxc@forum.dlang.org) is an example of something using this.

It requires manual parsing of HTTP, but 
[arsd.cgi](https://github.com/adamdruppe/arsd/blob/master/cgi.d) 
could be used to do this task (with the plain CGI version set) - 
however for simple endpoints like basic loggers this can be 
really well working.

To set it up you have to create 4 things: a one-shot SystemD 
service which is executed on every request, a SystemD socket 
which handles the networking, the CGI app, a reverse proxy 
handling HTTPS and stuff.

SystemD example files: (with hardened security)

> /etc/systemd/system/http-org-webfreak-completion.socket

```ini
[Unit]
Description = Completion suggestion logger

[Socket]
ListenStream = 2141
Accept = yes

[Install]
WantedBy = sockets.target
```

> /etc/systemd/system/http-org-webfreak-completion at .service

```ini
[Unit]
Description=Completion server accepter script

[Service]
User=http
Group=http

ExecStart=/srv/http/org.webfreak.completion/log
WorkingDirectory=/srv/http/org.webfreak.completion
StandardInput=socket

InaccessiblePaths=/opt/ /etc/opt/ /boot/ /mnt/ /media/
ProtectSystem=strict
ProtectHome=true
TemporaryFileSystem=/var:ro
BindPaths=/srv/http/org.webfreak.completion

# Device resrictions
PrivateDevices=true
DevicePolicy=closed
#DeviceAllow=/dev/sda r

# Security/permissions
NoNewPrivileges=true
CapabilityBoundingSet=
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
# Note: PrivateUsers prevents bind on privileged ports!
PrivateUsers=true

# System call filter
SystemCallArchitectures=native
SystemCallFilter=@system-service
LockPersonality=true
RestrictNamespaces=true
RestrictRealtime=true
#RestrictSUIDSGID=true

# Various restrictions (mix of filesystem access and system call 
restrictions)
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
#ProtectKernelLogs=true
#ProtectClock=true
#ProtectHostname=true
#ProtectProc=invisible

# Enforce W^X
# Note: Add /tmp/ if not mounted noexec!
InaccessiblePaths=/dev/shm/ /dev/mqueue/ /dev/pts/ /dev/hugepages/
MemoryDenyWriteExecute=true
SystemCallFilter=~memfd_create

# Cleanup leftover IPC objects
RemoveIPC=true
```

> Caddyfile
```
completion.webfreak.org {
         root * /srv/http/org.webfreak.completion/public
         file_server
         push /index.html /completion.png

         reverse_proxy /submit [::1]:2141
}
```

> log.d

`curl https://completion.webfreak.org/log.d`


More information about the Digitalmars-d mailing list