My RSS feed reader setup#
I run a CommaFeed instance on a free-tier Google Cloud Platform virtual machine. It’s a Google Reader-inspired self-hosted personal RSS reader.
I’m not using Docker, in part because the VM has only 0.25 CPU and, in part, because I like simple things.
Setup#
CommaFeed service runs under a SystemD Unit using a separate system user with a home directory:
sudo useradd -rms /sbin/nologin commafeed
sudo -u commafeed wget -O /home/commafeed/commafeed \
https://github.com/Athou/commafeed/releases/download/5.12.1/commafeed-5.12.1-h2-linux-x86_64-runner
sudo chmod +x /home/commafeed/commafeed
(Check the releases page to get the latest native binary for your operating system).
Reverse proxy#
Nginx has a section dedicated to proxy pass feed subdomain to a localhost port:
/etc/nginx/sites-available/default:
server {
server_name feed.demin.dev;
location / {
proxy_pass http://127.0.0.1:8082;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $http_host;
}
}
Make sure you configure TLS certificates, using certbot, for example.
SystemD Unit#
/etc/systemd/system/commafeed.service:
[Unit]
Description=A bloat-free feed reader
After=local-fs.target network.target
[Service]
User=commafeed
Group=commafeed
WorkingDirectory=/home/commafeed
ExecStart=/home/commafeed/commafeed
SyslogIdentifier=commafeed
Restart=always
[Install]
WantedBy=multi-user.target
(Check out the hardened version below.)
User registration#
By default, CommaFeed doesn’t allow user registration, which is sensible for a public, self-hosted service. To add a user for yourself, launch it with registration enabled:
sudo -u commafeed /bin/sh -c 'cd ~commafeed; COMMAFEED_USERS_ALLOW_REGISTRATIONS=true ./commafeed'
Then open the CommaFeed Web UI in your browser (in my case, https://feed.demin.dev) and create an account. Now stop the service (By pressing Ctrl+C), and launch it through the SystemD Unit:
sudo systemctl daemon-reload
sudo systemctl enable commafeed.service
sudo systemctl start commafeed.service
Backup#
I wouldn’t want to lose the extensive library of feeds I aggregated over many years. My solution is to export the OPML file whenever I think about how I don’t want to lose it. That’s a standard format that is easy to inspect and migrate to another service. I wish CommaFeed maintained a copy of this file in its data directory so I can back it up.
The treasure#
Here’s the list of feeds from the OPML file in alphabetical order:
Peter Demin (that’s me!)
Hardened SystemD Unit#
As a usual best practice, we should apply the principle of least privilege. The hardened version, which won’t let CommaFeed process do any harm even if it gets hacked:
[Unit]
Description=A bloat-free feed reader
Wants=network-online.target
After=local-fs.target network-online.target
[Service]
Type=simple
User=commafeed
Group=commafeed
WorkingDirectory=/home/commafeed
ExecStart=/home/commafeed/commafeed
SyslogIdentifier=commafeed
Restart=always
RestartSec=2
# Baseline safety
NoNewPrivileges=yes
UMask=0077
RemoveIPC=yes
CapabilityBoundingSet=
AmbientCapabilities=
# Filesystem sandbox
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/commafeed/data
# Stop it from seeing other processes' details
ProtectProc=invisible
ProcSubset=pid
# Kernel / namespace / device isolation
PrivateTmp=yes
PrivateDevices=yes
PrivateUsers=yes
PrivateMounts=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectClock=yes
ProtectHostname=yes
LockPersonality=yes
RestrictSUIDSGID=yes
RestrictRealtime=yes
RestrictNamespaces=yes
MemoryDenyWriteExecute=yes
# Syscall filtering
SystemCallArchitectures=native
SystemCallFilter=@system-service @network-io
SystemCallErrorNumber=EPERM
# Only allow the socket families it likely needs
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
# Optional resource limits
LimitNOFILE=4096
[Install]
WantedBy=multi-user.target