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