How to Install FreshRSS for Ubuntu VPS with Apache
Set up FreshRSS 1.30.1 for Ubuntu 24.04 VPS with Apache, PHP 8.3 and MariaDB, then fix cron refresh, encoded slashes and mobile API access.
Wetin you dey build
Self-hosted RSS reader na feed reader wey dey run for server wey you own, so nobody fit shut am down or change wetin e dey show you. This guide go install FreshRSS for Ubuntu 24.04 VPS: Apache go dey front, PHP go dey behind am, MariaDB go handle storage, and one cron job go fetch new articles. RSS (really simple syndication) na file format wey website dey publish so software fit read the articles. FreshRSS na PHP application wey dey collect those files, keep the articles, and give you web interface plus API (application programming interface) wey phone apps dey use.
The installation itself small: unpack one release, create database, write one virtual host, run command line installer, then create the account with cli/create-user.php. Most of the work wey follow na the parts people dey usually get wrong afterwards: refresh job, encoded slashes for mobile API, and file ownership.
FreshRSS 1.30.4, wey dem publish on October 21, 2026, na the current release as of October 29, 2026, and e need PHP 8.1 or newer. Ubuntu 24.04 dey ship PHP 8.3, so distribution packages dey enough and you no need third party PHP repository.
Start with LAMP stack wey dey work
FreshRSS na normal PHP application, so e need the same base like any other one. If you never build this base yet, follow LAMP stack setup for Ubuntu 24.04 first, then come back here. The short version na:
sudo apt update
sudo apt install -y apache2 mariadb-server php libapache2-mod-php
sudo systemctl enable --now apache2 mariadbsystemctl status apache2 suppose report active (running). If Apache no gree start, the common cause na another process wey already dey hold port 80, and sudo ss -ltnp | grep :80 go show the process name.
PHP extensions wey FreshRSS need
FreshRSS dey treat libxml, cURL, JSON, PDO_MySQL, PCRE and ctype as mandatory. E still need mbstring, iconv, Zlib and ZipArchive, plus GMP for 32 bit system. For Ubuntu, distribution packages dey provide dem:
sudo apt install -y php-curl php-mbstring php-xml php-zip php-mysql php-intl php-gmp
sudo systemctl restart apache2Use php -m check wetin PHP really load. If extension dey miss, installer no go stop from starting. E go stop for requirements screen and show red line wey name the extension. E fit confuse person to discover the problem for there, so confirm am now. Restarting Apache matter because libapache2-mod-php dey keep PHP inside Apache process. So, newly installed extension no go visible to web server until you restart am.
Download the release
Install FreshRSS outside the default web root, then point Apache go am. If application directory dey separate from document root, na only the public folder go ever reachable through HTTP.
cd /tmp
curl -fsSLO https://github.com/FreshRSS/FreshRSS/archive/refs/tags/1.30.4.tar.gz
tar xzf 1.30.4.tar.gz
sudo mv FreshRSS-1.30.4 /srv/freshrssNow make we set permissions. FreshRSS documentation strict for this matter: web server user go own the whole tree, group fit read every file, and group fit write to ./data/.
sudo chown -R www-data:www-data /srv/freshrss
sudo chmod -R g+r /srv/freshrss
sudo chmod -R g+w /srv/freshrss/dataIf you skip this, installer go fail when e dey write configuration, because PHP dey run as www-data and www-data no fit write inside directory wey root own.
Create the database
FreshRSS support SQLite, MariaDB, MySQL and PostgreSQL. SQLite need the php-sqlite3 extension but e no need database server setup, and e dey store each user data for separate data/users/_user_/db.sqlite file. Adding users no mean say dem writes go enter one shared SQLite file; this guide dey use MariaDB as part of the LAMP stack.
sudo mariadb -e "CREATE DATABASE freshrss CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER 'freshrss'@'localhost' IDENTIFIED BY 'ReplaceThisPassword';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON freshrss.* TO 'freshrss'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"Use utf8mb4, no be utf8. Feeds fit carry emoji and non-Latin scripts, but the old three byte utf8 encoding no fit store four byte characters. Unsupported characters go cause error under MariaDB default strict mode; whether data go truncate depend on SQL mode and statement options like IGNORE.
The Apache virtual host
The public directory na p/, no be the top of the tree. Everything else, including the configuration file wey hold your database password, dey above the document root where Apache no go ever serve am.
<VirtualHost *:80>
ServerName rss.example.com
DocumentRoot /srv/freshrss/p/
<Directory /srv/freshrss/p>
AllowOverride AuthConfig FileInfo Indexes Limit
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/freshrss_error.log
CustomLog ${APACHE_LOG_DIR}/freshrss_access.log combined
AllowEncodedSlashes On
</VirtualHost>Save am as /etc/apache2/sites-available/freshrss.conf, then enable am:
sudo a2enmod rewrite
sudo a2ensite freshrss
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2configtest suppose print Syntax OK. AllowEncodedSlashes On fit look optional, but e no be optional: the Google Reader API dey send feed identifiers wey contain %2F, and without this directive Apache go reject dem. Because of this, mobile apps no go sync while the web interface still dey work perfectly.
Add HTTPS before you log in
You wan type password for this site now, so first get certificate. Point an A record to the server, then follow Certbot setup for Apache on Ubuntu and run sudo certbot --apache -d rss.example.com. Certbot go rewrite the virtual host for port 443 and add the redirect. Confirm am with curl -I https://rss.example.com/, wey suppose return 200 or redirect go the login page.
Run installer from command line
FreshRSS get browser installer, but command line version fit repeat and e dey leave record of exactly wetin you choose.
sudo -u www-data php /srv/freshrss/cli/do-install.php \
--default-user admin --auth-type form --environment production \
--base-url https://rss.example.com --language en --api-enabled \
--db-type mysql --db-host localhost --db-user freshrss \
--db-password 'ReplaceThisPassword' --db-base freshrss
sudo -u www-data php /srv/freshrss/cli/create-user.php \
--user admin --password 'a-long-passphrase' --api-password 'a-different-passphrase'Run both as www-data. If you run dem as root, e go create configuration files wey root own, and web interface go later fail to save any setting. --environment production matter too, because development setting dey print PHP notices inside the page.
Load https://rss.example.com/ and log in as admin.
Why feeds no dey refresh by themselves
Nothing go poll your feeds until you tell am to. Opening FreshRSS no dey schedule feed fetching; if scheduler no dey, use the update link for the navigation menu to fetch articles manually. The fix na the script wey the project ships for this, app/actualize_script.php, run from cron.
sudo crontab -u www-data -eAdd one line:
*/20 * * * * php /srv/freshrss/app/actualize_script.php > /tmp/FreshRSS.log 2>&1Twenty minutes na sensible schedule, but each feed refresh interval still apply: the default na one hour, and individual feeds support intervals down to fifteen minutes. Run am by hand once first:
sudo -u www-data php /srv/freshrss/app/actualize_script.phpHealthy output go report the refresh run and end without PHP error; feed names go show when articles dey added or updated. If e print nothing at all, check PHP error output and the FreshRSS logs; silence by itself no identify cron user as the cause. Permission error for data/ mean say you need check ownership and write permissions.
Add your first feeds
Click the plus button for top left of the interface, paste the site address, and FreshRSS go discover the feed link for you. Most sites still publish one even when dem no advertise am, usually for /feed, /rss or /atom.xml. Categories na folders, and to move feed between dem na just drag am.
If you dey come from another reader, export OPML file there and import am under the subscription management page. OPML (outline processor markup language) na the standard format for feed list, and every reader wey worth leaving support am. Big import fit slow for the first refresh because every feed go fetch once, so give the first cron run time before you judge the speed.
Read am for your phone
FreshRSS dey support Google Reader API, and plenty RSS apps support am too. Two things must dey correct. For authentication settings, "Allow API access" must dey on; the --api-enabled flag wey dey above don already set am. For your profile, API password field must get value. E dey separate from your login password on purpose because phone na device wey person fit lose more easily.
Visit https://rss.example.com/api/ to make the server configuration checks run automatically. Working setup go return PASS. If the check fail, check the virtual host AllowEncodedSlashes On setting and the error wey e report. For the app, enter server address as https://rss.example.com/api/greader.php, username as your FreshRSS user, and API password as the password.
Docker alternative
If you no want maintain PHP and Apache by hand, the project publish official freshrss/freshrss image, and one compose file go give you the application and its database together. The trade-off na the usual one: fewer moving parts for the host, but one extra layer to debug when something break. You still need reverse proxy for TLS (transport layer security). If this arrangement suit you better, Docker Compose basics for VPS explain the file format, and the cron line go become docker exec --user www-data freshrss php ./app/actualize_script.php.
Backups and upgrades
Two things dey hold your state: the database, and /srv/freshrss/data/. Use sudo mysqldump freshrss > freshrss.sql dump the first one, copy the second one, and keep both for somewhere wey no be this server. Your subscription list too dey worth occasional OPML export, because that file fit transfer your feed list go other readers wey support OPML. E no preserve FreshRSS-specific settings like refresh frequency, credentials, user agent or XPath web scraping rules; use SQLite export preserve those ones too.
Upgrade na to unpack newer release over the same directory, then run the ownership commands again. Follow the project's version-by-version upgrade path and verify FreshRSS after every step. FreshRSS go apply its own database migrations for the next page load. Make backup first, because if migration fail for database wey you no fit restore, you no fit recover from the problem. If you install from older tarball like 1.29.1, move go 1.30.4: the 1.30.x security releases include session ID rotation when authentication changes and limits for ZIP imports, while 1.30.4 also updates the alternative Alpine Docker images for serious PHP vulnerabilities. Reader na low-risk service to run, and e good as first candidate if you dey work through list of things wey worth self-hosting.
FAQ
Why my feeds dey only update when I open FreshRSS?
Opening the page no dey schedule feed fetching; without scheduler, use the update link to refresh am manually. Add the cron line wey dey call app/actualize_script.php as www-data user, then run the script by hand one time and read wetin e output. If e no show anything, check PHP error output and FreshRSS logs, then confirm say cron user get write access to data/.
My mobile app no fit connect, but the website dey work. Why?
Google Reader API dey put encoded slashes (%2F) inside request paths, and Apache dey reject dem by default. Add AllowEncodedSlashes On inside the virtual host and reload Apache. Confirm the fix by opening https://rss.example.com/api/, where automatic configuration check suppose report PASS. Also check say API password dey set for your profile, because e different from your login password.
Make I use SQLite or MariaDB?
SQLite need php-sqlite3 extension, but you no need manage database server or database password. Each user get separate SQLite database file, so adding second user no create contention for one shared file or require MariaDB. Use MariaDB if you want use database server for your LAMP stack. You fit move between dem later through export and import commands, so this no be permanent decision.
Installer dey fail when e dey write configuration. Wetin dey wrong?
PHP dey run as www-data under Apache, and that user no fit write inside directory wey root own. Run sudo chown -R www-data:www-data /srv/freshrss and sudo chmod -R g+w /srv/freshrss/data again, then start installer again. If you don already run command line installer as root, correct ownership of the files wey e create under data/ before you try again.
How much server self-hosted RSS reader need?
E need very little. FreshRSS na software wey fit run for modest hardware, but resource use depend on your feeds, article sizes, and retention settings. Disk space dey grow with retention, so set article purge policy for archiving settings instead of keeping everything forever.