Just one more self-hosted application, then I’ll stop, I promise

Self-Hosting FreshRSS is kind of pointless as a single user but I’m going to do it anyway.

Why though?

Whilst not quite as straightforward as self-hosting a music streaming server , running your own RSS server is eminently do-able.

However you will end up with a very pretty and usable interface.

This, and the ability to synchronise the feeds across multiple devices using an API are the main reasons I chose to do this.

It’s a learning exercise as a single user though (unless you care deeply about having thousands of articles archived on your server for posterity).

Self-Hosting FreshRSS: Screenshot of the FreshRSS ‘Main stream’ screen. It shows list of RSS articles, sorted by date and time. When self-hosting FreshRSS this is the screen that is seen first when browsing the streams that have been subscribed to. FreshRSS Main Stream Screenshot

Create a sub-domain

Not strictly a requirement as I could access it locally but I want to be able to sync the feeds with multiple devices (phone, tablet etc.) so a dedicated URL is preferred (by me).

Create a MySQL database and user

I already have MariaDB installed and running as it is the DB behind this WordPress site.

PostgreSQL is recommended, although as the installation is just for me and I already had MariaDB installed I went with that.

If needed, install by running the following in a Terminal:

sudo apt install mariadb-server -y

However if this is the first time MariaDB has been installed it is a good idea to run through an initial setup in a Terminal:

sudo mysql_secure_installation

To check that it’s running and to start on a reboot, run the following in a Terminal:

sudo systemctl start mariadb

sudo systemctl enable mariadb

sudo systemctl status mariadb

To add the Gitea database run the following in a Terminal:

sudo mysql -u root -p

Then run:

CREATE DATABASE `freshrss`;
CREATE USER 'freshrss'@'localhost' IDENTIFIED BY 'super_long_password';
GRANT ALL PRIVILEGES ON `freshrss`.* TO 'freshrss'@localhost;
FLUSH PRIVILEGES;
QUIT;

Self-Hosting FreshRSS – Installing

https://github.com/FreshRSS/FreshRSS?tab=readme-ov-file#installation

https://freshrss.github.io/FreshRSS/en/admins/03_Installation.html

https://freshrss.github.io/FreshRSS/en/admins/06_LinuxInstall.html

To download and install, first, navigate to:

cd /usr/share/

Then, clone the git repository:

sudo git clone https://github.com/FreshRSS/FreshRSS.git

Set the installation permissions

Move to the ‘FreshRSS‘ directory:

cd FreshRSS

Then run the permissions script:

sudo cli/access-permissions.sh

Self-Hosting FreshRSS – nginx

https://freshrss.github.io/FreshRSS/en/admins/10_ServerConfig.html

nginx part I – pre Certbot

Create an nginx conf file:

sudo nano /etc/nginx/sites-available/rss

Then paste in something similar to the below:

server {
	listen 80;
	#listen 443 ssl;

	# HTTPS configuration
	#ssl on;
	#ssl_certificate /etc/nginx/server.crt;
	#ssl_certificate_key /etc/nginx/server.key;

	# your server’s URL(s)
	server_name rss.example.net;

	# the folder p of your FreshRSS installation
	root /srv/FreshRSS/p/;

	index index.php index.html index.htm;

	# nginx log files
	access_log /var/log/nginx/rss.example.net_access.log;
	error_log /var/log/nginx/rss.example.net_error.log;

	# php files handling
	# this regex is mandatory because of the API
	location ~ ^.+?\.php(/.*)?$ {
		fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
		fastcgi_split_path_info ^(.+\.php)(/.*)$;
		# By default, the variable PATH_INFO is not set under PHP-FPM
		# But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var!
		# NOTE: the separate $path_info variable is required. For more details, see:
		# https://trac.nginx.org/nginx/ticket/321
		set $path_info $fastcgi_path_info;
		fastcgi_param PATH_INFO $path_info;
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}

	location / {
		try_files $uri $uri/ index.php;
	}
}

Ensure it has the right PHP version:

fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;

First, check that nginx is configured correctly and return no errors:

sudo nginx -t

Then, symlink the newly created file:

sudo ln -s /etc/nginx/sites-available/rss /etc/nginx/sites-enabled/

Finally, re-check and re-load nginx:

sudo nginx -t && sudo systemctl reload nginx

Certbot

sudo certbot

The result (i.e. successful) should look something like this:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/rss.example.net/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/rss.example.net/privkey.pem

nginx part II – post Certbot

Certbot should have taken care of adding the HTTPS settings.

However for completeness here is mine.

server {
    # HTTPS configuration
    listen                  443 ssl; # managed by Certbot
    listen                  [::]:443 ssl;
    http2                   on;

    # Server
    server_name rss.example.net;
    root /usr/share/FreshRSS/p/;

    # index pages
    index index.php index.html index.htm;

    # SSL
    ssl_certificate /etc/letsencrypt/live/rss.example.net/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/rss.example.net/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # logging
    access_log /var/log/nginx/rss.example.net_access.log;
    error_log /var/log/nginx/rss.example.net_error.log;

    # php files handling
    # this regex is mandatory because of the API
    location ~ ^.+?\.php(/.*)?$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        # By default, the variable PATH_INFO is not set under PHP-FPM
        # But FreshRSS API greader.php need it. If you have a “Bad Request” error, double check this var!
        # NOTE: the separate $path_info variable is required. For more details, see:
        # https://trac.nginx.org/nginx/ticket/321
        set $path_info $fastcgi_path_info;
        fastcgi_param PATH_INFO $path_info;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location / {
            try_files $uri $uri/ index.php;
    }
}

# HTTP redirect
server {
    if ($host = rss.example.net) {
        
    } # managed by Certbot

        listen 80;
        server_name rss.example.net;
    return 404; # managed by Certbot
}

Check and reload nginx

sudo nginx -t && sudo systemctl reload nginx

FreshRSS – initial setup

Go to:

rss.example.net

Go through the setup

Host = localhost

Remember that the first user created will have ‘admin’ rights.

Then, log in and create new users as needed.

Self-Hosting FreshRSS: Screenshot of the FreshRSS ‘Subscription management’ screen. It shows list of RSS streams that have been subscribed to, arranged into Categories or Groups. This page is where the majority of the initial FreshRSS setup takes place. FreshRSS Subscription Management Screenshot

Self-Hosting FreshRSS – API access

At this point it might be useful to set up API access, especially if your plan is to use an external client.

Go to (and tick):

Administration | Authentication | Allow API access

Refresh feeds with cron

https://freshrss.github.io/FreshRSS/en/admins/08_FeedUpdates.html

FreshRSS is updated by the actualize_script.php script.

This can be triggered to run at set times using cron.

Not normal cron, the www-data user cron.

Swap to www-data user and open a sh prompt:

sudo -u www-data sh

First, see if the command works:

/usr/bin/php /usr/share/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1;

nano /tmp/FreshRSS.log

Then, setup www-data cron:

Run the following in a Terminal:

crontab -e

Then add something like the below (choose your preferred run frequency):

# Refresh all of the FreshRSS feeds, every 10 minutes
*/10 * * * * /usr/bin/php /usr/share/FreshRSS/app/actualize_script.php > /tmp/FreshRSS.log 2>&1;
#

To exit the sh Terminal press:

shift - ctrl - d

Self-Hosting FreshRSS – Extensions

FreshRSS extensions are added to the following directory:

cd /usr/share/FreshRSS/extensions

Auto-Refresh-Extension

https://github.com/Eisa01/FreshRSS—Auto-Refresh-Extension

Whilst having a browser tab log-out after a period of time is good security I would prefer my session to stay alive as long as my browser window is open.

That is what the ‘Auto-Refresh-Extension’ achieves.

First, download the zip to a local machine and extract.

Then, rsync to the /TEMP/ folder on the server (assuming there is a /TEMP/ obviously):

rsync -av -e ssh /home/foo/Downloads/FreshRSS---Auto-Refresh-Extension-master/xExtension-AutoRefresh/* foo@server:/home/foo/TEMP/AutoRefresh/

Now, on the remote machine, create the ‘extension’ directory and then copy the files and folders.

Run the following in a Terminal to make a directory for the extension to live in:

sudo mkdir /usr/share/FreshRSS/extensions/AutoRefresh

Then, copy the extracted files to the newly created directory:

sudo cp -R /home/foo/TEMP/AutoRefresh/* /usr/share/FreshRSS/extensions/AutoRefresh/

Finally, refresh the web page and ‘enable’ the new extension.

Other extensions are available.

Self-Hosting FreshRSS – Clients

I’m using the FreshRSS Android Client from F-Droid (link seems broken):

f-droid.org/packages/fr.chenry.android.freshrss

(Hence why API access was activated earlier.)

Other clients on other platforms are available:

https://github.com/FreshRSS/FreshRSS#apis–native-apps

Finally

Whilst it might have been a bit of a drawn out process; self-hosting FreshRSS does mean that I am no longer exporting and importing OPML files across devices.

Also, the server side works perfectly, although I’m not sure I’m ever going to read those thousands of archives links that are building up.

The Client works perfectly too with a whole bunch of settings to tinker with.

Overall 10/10 would do again.