Self Hosting FreshRSS on Ubuntu

If you’re like me, you just want to consume your RSS without any adverts or fancy recommendations. After dabbling into multiple RSS readers like Tiny Tiny RSS and Stringer, I think I’ve found the RSS feed aggregator to rule them all, FreshRSS is lightweight, yet …

If you’re like me, you just want to consume your RSS without any adverts or fancy recommendations.

After dabbling into multiple RSS readers like Tiny Tiny RSS and Stringer, I think I’ve found the RSS feed aggregator to rule them all, FreshRSS is lightweight, yet powerful, and customizable.

FreshRSS has a clean, responsive UI that can be used even on phones without any native apps, it supports multiple users and has an anonymous reading mode.

In this tutorial, I’ll be using an Ubuntu VM on Vultr to host FreshRSS, the steps will be the same for any other distros as we’ll be using Docker.

Step1: Creating a Virtual Machine

Any basic virtual machine running Ubuntu 20.04 or any other distro will suffice:

  • 1 GB of RAM
  • 1 CPU cores

Although, you might need to increase your resources depending on the number of users and articles, pick a server location that’s closest to you for low latency.

Step 2: Updating the DNS Entry

Note down the IP address of the virtual machine, and go to your domain registrar and add an A record with the IP address of the VM.

I’ll be using rss.example.com as an example in the tutorial from now on, we’ll also be configuring a reverse proxy on our server to secure connections to our FreshRSS instance via a trusted SSL certificate from Let’s Encrypt.

Step 3: Configuring the Virtual Machine for FreshRSS

Now, let’s configure our server:

Step 3.1: Connect to the Server via SSH

Open up the terminal on your device, and run this command:

ssh root@123.45.67.89

If you chose a username while creating the virtual machine, use that instead of root, and replace 123.45.67.89 with the IP address of your VM.

You’ll be prompted with “The authenticity of host…”, just type yes, and then enter the password.

Step 3.2: Configure Automatic Updates

Let’s update packages and configure automatic updates so that our server gets patched automatically.

# Update packages
sudo apt update && apt upgrade

# Install unattended-upgrades
sudo apt install unattended-upgrades

# Configure unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Test unattended-upgrades
sudo unattended-upgrades --dry-run --debug

Step 3.3: Creating a “sudo” user

If your cloud provider didn’t ask you to choose a username while creating it, you are given root access to your server; it is recommended to not use the “root” user, which has unlimited privileges and can execute any command, even ones that could potentially disrupt your server.

Let’s create a new user on a server that can use “sudo” to do day-to-day administration tasks.

# Create a new user
adduser username

# Add user to the "sudo" group
usermod -aG sudo username

# Check user's group
groups username

# Switching users
su - username
su - root

Step 3.4: Configure SSH Keys

Using SSH keys instead of passwords provides you with better security, as SSH keys are far more long and complex than any password could ever be; you can also add an extra password to the SSH keys, requiring both the SSH key and the password to access the server.

Log out of the server or just open up a new terminal on your computer to create SSH keys:

# Create ssh keys
ssh-keygen -b 4096 

# View ssh keys
ls -l ~/.ssh

# Add public key to server
ssh-copy-id -i ~/.ssh/keyname.pub username@123.45.67.89

# Switch ssh keys on client
ssh-add ~/.ssh/keyname

During the ssh-keygen process, you’ll be prompted for file location, use the default one or give a new location by typing in /home/username/.ssh/keyname, and enter a strong password for the SSH key.

In the .ssh folder, there’ll be two files, the one with “.pub” extension is your public key, the other one is your private key, never share the private key with anyone.

You might get a message like Could not open a connection to your authentication agent when switching SSH keys, you’ll need to start ssh-agent first using:

eval `ssh-agent`

Once done, you can log in to the server by just using the ssh username@123.45.67.89 command without entering the user password, although you will need to enter the password of your SSH key.

Step 3.5: Disable root login

Now that we have a new user with limited privileges that can run “sudo” commands and can access the server via SSH keys; let’s lock down our root user, as it is usually the most targeted account by hackers.

To do so, type in sudo nano /etc/ssh/sshd_config, and update PermitRootLogin to no and add AllowUsers username as shown below:

Disable root login via SSH

Optionally, you can also go ahead and disable password-based login via SSH for all users, including the new user account we just created, by updating these values in the same sshd config file:

# Disable password-based login via ssh for all users [optional]
PasswordAuthentication no
ChallengeResponseAuthentication no

Once done, save the file using Ctrl + O & Ctrl + X, and restart the sshd service using this command:

sudo systemctl restart sshd

Now, your server is ready to install our FreshRSS instance, let’s get into it.

Step 4: Installing FreshRSS

We’ll be using the official Docker image to install FreshRSS on our server.

Step 4.1: Installing Docker

1. Uninstalling any previously installed older Docker packages:

sudo apt remove docker docker-engine docker.io containerd runc

Follow the next step if you got an output like this:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package docker-engine

2. Installing Docker using the convenience script at get.docker.com:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

If all goes well, you’ll see something like this:

# Executing docker install script, commit: 93d2499759296ac1f9c510605fef85052a2c32be
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sh -c curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" | gpg --dearmor --yes -o /usr/share/keyrings/docker-archive-keyring.gpg
+ sh -c echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu focal stable" > /etc/apt/sources.list.d/docker.list
+ sh -c apt-get update -qq >/dev/null
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends  docker-ce-cli docker-scan-plugin docker-ce >/dev/null
+ version_gte 20.10
+ [ -z  ]
+ return 0
+ sh -c DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker-ce-rootless-extras >/dev/null
+ sh -c docker version
Client: Docker Engine - Community
 Version:           20.10.14
 API version:       1.41
 Go version:        go1.16.15
 Git commit:        a224086
 Built:             Thu XXX XX XX:XX:XX 2022
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.14
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       87a90dc
  Built:            Thu XXX XX XX:XX:XX 2022
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.5.11
  GitCommit:        3df54a852345ae127d1fa3092b95168e4a88e2f8
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

================================================================================

To run Docker as a non-privileged user, consider setting up the
Docker daemon in rootless mode for your user:

    dockerd-rootless-setuptool.sh install

Visit https://docs.docker.com/go/rootless/ to learn about rootless mode.


To run the Docker daemon as a fully privileged service, but granting non-root
users access, refer to https://docs.docker.com/go/daemon-access/

WARNING: Access to the remote API on a privileged Docker daemon is equivalent
         to root access on the host. Refer to the 'Docker daemon attack surface'
         documentation for details: https://docs.docker.com/go/attack-surface/

================================================================================

3: Creating an isolated network:

sudo docker network create freshrss-network

Step 4.2: Installing & Configuring Træfik reverse proxy

1. Creating volumes:

sudo docker volume create traefik-letsencrypt
sudo docker volume create traefik-tmp

2. Installing Træfik reverse proxy:

Just change the e-mail address in the last line.

docker run -d --restart unless-stopped --log-opt max-size=10m \
  -v traefik-letsencrypt:/etc/traefik/acme \
  -v traefik-tmp:/tmp \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --net freshrss-network \
  -p 80:80 \
  -p 443:443 \
  --name traefik traefik:1.7 --docker \
  --loglevel=info \
  --entryPoints='Name:http Address::80 Compress:true Redirect.EntryPoint:https' \
  --entryPoints='Name:https Address::443 Compress:true TLS TLS.MinVersion:VersionTLS12 TLS.SniStrict:true TLS.CipherSuites:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' \
  --defaultentrypoints=http,https --keeptrailingslash=true \
  --acme=true --acme.entrypoint=https --acme.onhostrule=true --acme.tlsChallenge \
  --acme.storage=/etc/traefik/acme/acme.json --acme.email=mail@example.com

Step 4.3: Installing & Configuring FreshRSS

1. Creating volumes:

sudo docker volume create freshrss-data
sudo docker volume create freshrss-extensions

2. Installing FreshRSS:

Just change rss.example.com to your domain, you can also configure the default timezone for your server by adding -e TZ=yourservertimezone \

sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
  -v freshrss-data:/var/www/FreshRSS/data \
  -v freshrss-extensions:/var/www/FreshRSS/extensions \
  -e 'CRON_MIN=4,34' \
  --net freshrss-network \
  --label traefik.port=80 \
  --label traefik.frontend.rule='Host:rss.example.com' \
  --label traefik.frontend.headers.forceSTSHeader=true \
  --label traefik.frontend.headers.STSSeconds=31536000 \
  --name freshrss freshrss/freshrss

This above configuration uses the built-in SQLite database, although you can use MySQL, MariaDB, or PostgreSQL, just attach it to the FreshRSS network.

For MySQL or MariaDB:

# If you already have a MySQL or MariaDB instance running, just attach it to the FreshRSS network:
sudo docker network connect freshrss-network mysql

# Otherwise, start a new MySQL instance, and then attach it to the FreshRSS network, be sure to change the passwords:
sudo docker volume create mysql-data
sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=freshrss \
  -e MYSQL_USER=freshrss \
  -e MYSQL_PASSWORD=pass \
  --net freshrss-network \
  --name mysql mysql

For PostgreSQL:

# If you already have a PostgreSQL instance running, just attach it to the FreshRSS network:
sudo docker network connect freshrss-network postgres

# Otherwise, start a new PostgreSQL instance, and then attach it to the FreshRSS network, be sure to change the passwords:
sudo docker volume create pgsql-data
sudo docker run -d --restart unless-stopped --log-opt max-size=10m \
  -v pgsql-data:/var/lib/postgresql/data \
  -e POSTGRES_DB=freshrss \
  -e POSTGRES_USER=freshrss \
  -e POSTGRES_PASSWORD=pass \
  --net freshrss-network \
  --name postgres postgres

And, that is it, you can now go to https://rss.example.com/ to complete the installation via the FreshRSS Web interface.

Step 5: Accessing FreshRSS

Now, when you visit your FreshRSS url, you’ll be greeted with the FreshRSS installation page:

FreshRSS Installation Page

In the second step, you should see all checks are “Okay!”, in the next one, leave the database configuration to the default SQLite if you haven’t configured a different database.

In the fourth step, you’ll be asked to create a username and password, leave the authentication method to default:

Create FreshRSS Username & Password

In the next step, you’ll be greeted installation complete message.

Next up, just visit your FreshRSS URL, use the username and password you created, and you’ll be greeted with the FreshRSS dashboard from where you can add and manage your feeds:

FreshRSS Dashboard

Step 6: FreshRSS Maintenance & Update

To update FreshRSS, we’ll need to first rebuild the image with the new online version:

# Rebuild an image (see build section above) or get a new online version:
docker pull freshrss/freshrss

# And then
docker stop freshrss
docker rename freshrss freshrss_old

# See the run section above for the full command
docker run ... --name freshrss freshrss/freshrss

# If everything is working, delete the old container
docker rm freshrss_old

Here are a few more useful commands:

# View FreshRSS data if you use Docker volume
docker volume inspect freshrss-data
sudo ls /var/lib/docker/volumes/freshrss-data/_data/

# View Web server logs
docker logs -f freshrss

# Enter inside FreshRSS docker container
docker exec -it freshrss sh

# View FreshRSS root inside the container
ls /var/www/FreshRSS/

That’s all folks!

Take a look at the FreshRSS documentation and FreshRSS CLI for more commands.

Leave a Comment