20. November 2017 · Write a comment · Categories: Techie · Tags: , , , ,

Since the retirement of Google Reader, I had been itching for a RSS aggregator & feed reader for a while. While Vienna for OSX used to be a favorite when I had a desktop on close to 24-7, it could/would miss occasional posts once I started sleeping/powering down machines in their off-hours. I had been using Feedly for a year or two at this point, but was growing increasingly disenfranchised with their cloud-style model & push for pay-for services (accompanied with reduced free functionality).

Having surveyed some of the available open-source/self-hosting solutions, I finally settled on giving FreshRSS a try. Months ago, I attempted to set this up in a test jail on my FreeBSD sever to no avail, and abandoned the work until a couple weeks ago. About a month ago, I started experimenting with Linux (particularly Manjaro, an Arch derivative) as a potential desktop replacement.

With Arch running on a Raspberry Pi Zero W (to get more familiarized with the Arch/Manjaro ecosystem), I finally renewed my attempts to get this installed on a Linux platform (which had more documentation available). With substantially less problems, I was able to get it stably running & configured. Trialling it as a replacement for Feedly for a couple weeks, I was satisfied with its performance, even on the Pi Zero! Since I migrated my web hosting from Bluehost for this site and others to a VPS running FreeBSD, I now wanted to translate this self-hosted service from my private network to a production environment accessible from the Internet at large.

With WordPress on this host published atop nginx and php71, I wanted to get FreshRSS published atop these same web modules, ideally. Most of the installation instructions were aimed at providing FreshRSS atop Apache and php5, but I wanted to avoid stretching myself into other platforms when I could hopefully enrich my understanding of existing ones. Through some reasonable troubleshooting (mostly in identifying missing php modules), I finally got a production installation going. I will outline the steps below.

In either a FreeBSD installation (I am running in 11 presently) or a containerized jail (my personal preference for sandboxing and snapshots), you need to install some packages first. As I performed all this within the jail, assume all operations are executed as root.

  1. Necessary packages:
  2. pkg install git-lite \
      nginx \
      php71 \

  3. Pick a location to acquire & unpack the FreshRSS code from GitHub, and give the www user permission to work with it from nginx:
  4. cd /usr/local/share
    git clone https://github.com/FreshRSS/FreshRSS.git FreshRSS
    chown -R www:www FreshRSS
    chown -R g+rw FreshRSS

  5. Link just the publishable directory to /usr/local/www to avoid exposing some of the sensitive guts:
  6. ln -s /usr/local/share/FreshRSS/p /usr/local/www/freshrss

  7. OPTIONAL: If you want to generate a self-signed SSL certificate for encrypting communications with your installation, I used/condensed the instructions I found here. If you’re not concerned about HTTPS access, you can skip ahead to step 10.
  8. Create a location for the SSL cert, key, and associated nginx configuration snippets:
  9. mkdir -p /etc/ssl/{certs,private} /usr/local/nginx/snippets

  10. Generate the certificate with a duration (${CERT_LENGTH}) of your choosing with a key size rsa-2048 or greater (I use 4096 by default, personally), and save the private key & certificate in separate locations:
  11. openssl req -x509 \
      -nodes \
      -days ${CERT_LENGTH} \
      -newkey rsa:4096 \
      -keyout /etc/ssl/private/nginx-selfsigned.key \
      -out /etc/ssl/certs/nginx-selfsigned.crt

  12. Generate a strong Diffie-Hellman group. Don’t arbitrarily bump this up to 4096; that may take a long while to generate:
  13. openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

  14. Create a certificate snippet (e.g. /usr/local/etc/nginx/snippets/self-signed.conf) with the following contents:
  15. ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
    ssl_certificate_key /etc/ssl/private/nginx-selfsigned.crt;

  16. Create a configuration snippet (e.g. /usr/local/nginx/snippets/ssl-params.conf) for the SSL parameters:
  17. ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ecdh_curve secp384r1;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    resolver valid=300s;
    resolver_timeout 5s;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    ssl_dhparam /etc/ssl/certs/dhparam.pem;

  18. Create a relatively lean nginx configuration file (/usr/local/etc/nginx/nginx.conf by default on FreeBSD) for publishing:
  19. user www;
    worker_processes: 2;
    events {
      worker_connections 1024;
    http {
      include mime.types;
      default_type application/octet-stream;

      sendfile on;
      keepalive_timeout 65;

      server {
        listen 80; # http on port 80

        # Delete/comment out if not using self-signed cert configured earlier
        listen 443 ssl; # https on port 443
        include /usr/local/nginx/snippets/self-signed.conf
        include /usr/local/nginx/snippets/ssl-params.conf

        # your server's url(s)

        # the folder p of your FreshRSS installation
        root /usr/local/www/freshrss;

        index index.php index.html index.htm;

        # nginx log files
        access_log /var/log/nginx/rss.acc.log;
        error_log /var/log/nginx/rss.err.log;

        # php files handling
        # this regex is mandatory because of the API
        location ~ ^.+?\.php(/.*)?$ {
          fastcgi_pass unix:/var/run/php-fpm.sock;
          fastcgi_split_path_info ^(.+\.php)(/.*)$;
          fastcgi_param PATH_INFO $fastcgi_path_info;
          include fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

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

    • If you are already hosting other pages, or for the sake of simplicity/cleanness just want to import the configuration, you can just write the server{} block to the file as http{} should already be declared in the main nginx.conf file.
  20. Now for some trickier work: we need to configure php!
    • First, we will copy the production php.ini file into place. Edits should be unnecessary, as installing the php modules should automatically link them into the ini files:
    • cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

    • Second, we will lockdown php to just serve itself on a local socket, and bump up the maximum number of children threads (revert the last edit if it gives you trouble later on):
    • sed -i .backup \
       's/listen\ \=\\:9000/listen\ \=\ \/var\/run\/php-fpm.sock/' \
      sed -i ''\
       's/;listen.owner\ \=\ www/listen.owner\ \=\ www/'\
      sed -i ''\
       's/;listen.group\ \=\ www/listen.group\ \=\ www/'\
      sed -i ''\
       's/;listen.mode\ \=\ 0660/listen.mode\ \=\ 0660/'\
      sed -i ''\
       's/pm.max_children\ \=\ 5/pm.max_children\ \=\ 10/'\

  21. Everything should be configured, so let us commit them to startup:
  22. sysrc -f /etc/rc.conf.local php_fpm_enable="YES" nginx_enable="YES"

  23. Testing the configuration files for the services should be successful without consequence. If not, you will need to go back to steps 3–11 to resolve.
  24. php-fpm -t
    nginx -t

  25. If the configurations pass muster, then you are ready to fire the services up & test the site:
  26. service php-fpm start
    service nginx start

At this point, you should be able to browse to your box’s/instance’s address and be good to go for configuring FreshRSS from its web interface!

Leave a Reply

Your email address will not be published. Required fields are marked *