Jak zainstalować FreshRSS na własnym serwerze VPS
Instrukcja instalacji FreshRSS na Ubuntu 24.04 z Apache, PHP 8.3 i MariaDB. Dowiedz się, jak poprawnie skonfigurować zadania cron, uprawnienia plików oraz API dla aplikacji mobilnych.
Co budujesz
Własny czytnik RSS to aplikacja działająca na serwerze, nad którym masz pełną kontrolę, dzięki czemu nikt nie może go wyłączyć ani zmienić wyświetlanych treści. Ten przewodnik opisuje instalację FreshRSS na serwerze VPS z systemem Ubuntu 24.04: Apache jako serwer frontowy, PHP jako silnik, MariaDB jako baza danych oraz zadanie cron pobierające nowe artykuły. RSS (Really Simple Syndication) to format pliku publikowany przez witryny, umożliwiający oprogramowaniu odczyt artykułów. FreshRSS to aplikacja PHP, która gromadzi te pliki, przechowuje artykuły i udostępnia interfejs WWW oraz API (Application Programming Interface), z którego korzystają aplikacje mobilne.
Sama instalacja jest niewielka: rozpakowanie wydania, utworzenie bazy danych, przygotowanie wirtualnego hosta i uruchomienie instalatora wiersza poleceń. Większość poniższych prac dotyczy etapów, w których często popełniane są błędy: konfiguracji odświeżania, obsługi ukośników w API mobilnym oraz uprawnień do plików.
FreshRSS 1.29.1 to aktualne wydanie na lipiec 2026 roku, wymagające PHP 8.1 lub nowszego. Ubuntu 24.04 dostarcza PHP 8.3, więc pakiety systemowe są wystarczające i nie ma potrzeby korzystania z zewnętrznych repozytoriów PHP.
Rozpoczęcie od działającego stosu LAMP
FreshRSS jest standardową aplikacją PHP, dlatego wymaga takiego samego środowiska bazowego jak każda inna. Jeśli to środowisko nie zostało jeszcze przygotowane, należy najpierw wykonać konfigurację stosu LAMP dla Ubuntu 24.04, a następnie powrócić do tego miejsca. Wersja skrócona:
sudo apt update
sudo apt install -y apache2 mariadb-server php libapache2-mod-php
sudo systemctl enable --now apache2 mariadbsystemctl status apache2 powinno zwrócić active (running). Jeśli Apache nie uruchamia się, najczęstszą przyczyną jest inny proces zajmujący port 80, a sudo ss -ltnp | grep :80 wskaże jego nazwę.
Rozszerzenia PHP wymagane przez FreshRSS
FreshRSS wymaga obecności bibliotek libxml, cURL, JSON, PDO_MySQL, PCRE oraz ctype. Wymaga również mbstring, iconv, Zlib, ZipArchive, a w systemach 32-bitowych także GMP. W systemie Ubuntu pakiety te są dostępne w oficjalnych repozytoriach:
sudo apt install -y php-curl php-mbstring php-xml php-zip php-mysql php-intl php-gmp
sudo systemctl restart apache2Sprawdź, które rozszerzenia PHP zostały załadowane, używając polecenia php -m. Brakujące rozszerzenie nie blokuje uruchomienia instalatora. Powoduje ono zatrzymanie procesu na ekranie wymagań z czerwonym komunikatem wskazującym nazwę brakującego elementu. Jest to nieczytelny sposób diagnozy, dlatego warto zweryfikować stan przed rozpoczęciem instalacji. Restart serwera Apache jest konieczny, ponieważ libapache2-mod-php utrzymuje PHP wewnątrz procesu Apache, co sprawia, że nowo zainstalowane rozszerzenie pozostaje niewidoczne dla serwera WWW do momentu jego ponownego uruchomienia.
Pobieranie wydania
Zainstaluj FreshRSS poza domyślnym katalogiem głównym serwera WWW i skieruj na niego Apache. Przechowywanie katalogu aplikacji oddzielnie od głównego katalogu dokumentów sprawia, że przez HTTP dostępny jest wyłącznie folder public.
cd /tmp
curl -fsSLO https://github.com/FreshRSS/FreshRSS/archive/refs/tags/1.29.1.tar.gz
tar xzf 1.29.1.tar.gz
sudo mv FreshRSS-1.29.1 /srv/freshrssTeraz uprawnienia, co do których dokumentacja FreshRSS jest rygorystyczna: użytkownik serwera WWW musi być właścicielem drzewa katalogów, grupa musi mieć możliwość odczytu każdego pliku, a grupa musi mieć możliwość zapisu do ./data/.
sudo chown -R www-data:www-data /srv/freshrss
sudo chmod -R g+r /srv/freshrss
sudo chmod -R g+w /srv/freshrss/dataPominięcie tego kroku spowoduje błąd instalatora podczas zapisu konfiguracji, ponieważ PHP działa jako www-data, a www-data nie posiada uprawnień do zapisu w katalogu, którego właścicielem jest root.
Tworzenie bazy danych
FreshRSS obsługuje SQLite, MariaDB, MySQL oraz PostgreSQL. SQLite nie wymaga konfiguracji i sprawdza się w przypadku jednego użytkownika z kilkuset kanałami. MariaDB jest lepszym wyborem, gdy z instancji korzysta kilka osób, ponieważ jednoczesne zapisy z zadania odświeżania i interfejsu WWW nie powodują rywalizacji o blokadę pojedynczego pliku.
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;"Należy używać utf8mb4, a nie utf8. Kanały zawierają emoji oraz znaki spoza alfabetu łacińskiego, a stare, trzybajtowe kodowanie utf8 powoduje ucięcie tytułu artykułu przy pierwszym czterobajtowym znaku.
Wirtualny host Apache
Katalog publiczny to p/, a nie najwyższy poziom drzewa katalogów. Cała reszta, w tym plik konfiguracyjny zawierający hasło do bazy danych, znajduje się powyżej katalogu głównego dokumentów, skąd Apache nigdy nie udostępni plików.
<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>Zapisz to jako /etc/apache2/sites-available/freshrss.conf i aktywuj konfigurację:
sudo a2enmod rewrite
sudo a2ensite freshrss
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2configtest powinno zwrócić Syntax OK. Dyrektywa AllowEncodedSlashes On wydaje się opcjonalna, lecz w rzeczywistości taka nie jest: API Google Reader wysyła identyfikatory kanałów zawierające %2F. Bez tej dyrektywy Apache odrzuca takie żądania, co powoduje, że aplikacje mobilne nie synchronizują danych, podczas gdy interfejs WWW działa poprawnie.
Dodaj HTTPS przed zalogowaniem
Wprowadzisz hasło w tej witrynie, więc najpierw uzyskaj certyfikat. Skieruj rekord A na serwer, a następnie wykonaj konfigurację Certbot dla Apache na Ubuntu i uruchom sudo certbot --apache -d rss.example.com. Certbot zmodyfikuje wirtualny host dla portu 443 i doda przekierowanie. Potwierdź działanie za pomocą curl -I https://rss.example.com/, co powinno zwrócić 200 lub przekierowanie do strony logowania.
Uruchomienie instalatora z poziomu wiersza poleceń
FreshRSS posiada instalator przeglądarkowy, jednak wersja wiersza poleceń jest powtarzalna i pozwala zachować dokładny zapis dokonanych wyborów.
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'Oba polecenia należy uruchomić jako www-data. Uruchomienie ich z uprawnieniami root powoduje, że pliki konfiguracyjne stają się własnością użytkownika root, co uniemożliwia późniejszy zapis ustawień przez interfejs WWW. Parametr --environment production jest również istotny, ponieważ ustawienie deweloperskie powoduje wyświetlanie powiadomień PHP na stronie.
Załaduj https://rss.example.com/ i zaloguj się jako admin.
Dlaczego kanały nie odświeżają się automatycznie
Żaden proces nie pobiera kanałów, dopóki nie zostanie to skonfigurowane. FreshRSS odświeża dane tylko wtedy, gdy otwarta jest przeglądarka z aktywną instancją, co oznacza, że przy logowaniu dwa razy dziennie artykuły mogą być nieaktualne o dwanaście godzin. Rozwiązaniem jest skrypt dostarczany przez projekt, app/actualize_script.php, uruchamiany za pomocą cron.
sudo crontab -u www-data -eNależy dodać jedną linię:
*/20 * * * * php /srv/freshrss/app/actualize_script.php > /tmp/FreshRSS.log 2>&1Dwudziestominutowy interwał jest rozsądnym minimum, ponieważ skrypt odrzuca próby odświeżania pojedynczego kanału częściej niż raz na dwadzieścia minut, więc częstsze uruchamianie jedynie niepotrzebnie obciąża procesor. Najpierw należy uruchomić skrypt ręcznie:
sudo -u www-data php /srv/freshrss/app/actualize_script.phpPoprawne wyjście zawiera nazwy pobranych kanałów i kończy się bez błędów PHP. Brak jakiegokolwiek wyjścia oznacza błędnego użytkownika cron, natomiast błąd uprawnień w data/ wskazuje na pominięcie kroku chmod -R g+w.
Dodawanie pierwszych kanałów
Użyj przycisku plusa w lewym górnym rogu interfejsu, wklej adres strony, a FreshRSS automatycznie wykryje link do kanału. Większość witryn publikuje kanał, nawet jeśli nie jest on jawnie promowany; zazwyczaj znajduje się on pod adresem /feed, /rss lub /atom.xml. Kategorie pełnią funkcję folderów, a przenoszenie między nimi kanałów odbywa się metodą przeciągnij i upuść.
W przypadku migracji z innego czytnika, wyeksportuj plik OPML z poprzedniego narzędzia i zaimportuj go na stronie zarządzania subskrypcjami. OPML (outline processor markup language) to standardowy format listy kanałów, obsługiwany przez każdy czytnik godny uwagi. Import dużej liczby subskrypcji powoduje spowolnienie przy pierwszym odświeżeniu, ponieważ każdy kanał jest pobierany jednorazowo. Przed oceną wydajności należy pozwolić na zakończenie pierwszego uruchomienia zadania cron.
Odczyt na urządzeniu mobilnym
FreshRSS obsługuje API Google Reader, z którym współpracuje niemal każda aplikacja RSS. Muszą zostać spełnione dwa warunki. W ustawieniach uwierzytelniania opcja "Allow API access" musi być włączona, co zostało już zapewnione przez flagę --api-enabled powyżej. W profilu użytkownika pole API password musi zawierać wartość; jest ono celowo oddzielone od hasła logowania, ponieważ urządzenie mobilne łatwiej zgubić.
Odwiedź https://rss.example.com/api/ i wybierz "Check full server configuration". Poprawna konfiguracja zwraca PASS. Błąd w tym miejscu prawie zawsze wynika z brakującej linii AllowEncodedSlashes On. W aplikacji jako adres serwera podaj https://rss.example.com/api/greader.php, jako nazwę użytkownika swojego użytkownika FreshRSS, a jako hasło – hasło API.
Alternatywa w postaci Docker
Jeśli użytkownik woli nie zarządzać ręcznie PHP oraz Apache, projekt udostępnia oficjalny obraz freshrss/freshrss, a jeden plik compose pozwala uruchomić aplikację wraz z bazą danych. Wiąże się to z typowym kompromisem: mniej komponentów na hoście, ale dodatkowa warstwa do debugowania w razie awarii, przy czym nadal wymagany jest reverse proxy do obsługi TLS (transport layer security). Jeśli takie rozwiązanie jest bardziej odpowiednie, podstawy Docker Compose na VPS opisują format pliku, a wpis w cron zmienia się na docker exec --user www-data freshrss php ./app/actualize_script.php.
Kopie zapasowe i aktualizacje
Stan usługi przechowują dwa elementy: baza danych oraz /srv/freshrss/data/. Wykonaj zrzut pierwszej za pomocą sudo mysqldump freshrss > freshrss.sql, skopiuj drugi element i przechowuj oba w lokalizacji innej niż bieżący serwer. Warto również okresowo eksportować listę subskrypcji do formatu OPML, ponieważ plik ten pozwala odtworzyć konfigurację czytnika w dowolnym oprogramowaniu RSS.
Aktualizacja polega na rozpakowaniu nowszego wydania w tym samym katalogu i ponownym wykonaniu poleceń nadania uprawnień. FreshRSS automatycznie przeprowadza migrację bazy danych przy pierwszym załadowaniu strony po aktualizacji. Zawsze wykonuj kopię zapasową przed rozpoczęciem procesu, ponieważ nieudana migracja bazy danych bez możliwości jej przywrócenia prowadzi do utraty danych. Czytnik RSS jest usługą o niskim stopniu ryzyka i stanowi dobry pierwszy projekt, jeśli realizujesz listę usług wartych samodzielnego hostowania.
FAQ
Dlaczego moje kanały aktualizują się tylko po otwarciu FreshRSS?
Ponieważ harmonogram zadań nie istnieje, dopóki go nie utworzysz. FreshRSS odświeża kanały, gdy sesja przeglądarki jest otwarta, i nie wykonuje żadnych działań po zamknięciu karty. Dodaj wpis cron wywołujący app/actualize_script.php jako użytkownik www-data, a następnie uruchom skrypt ręcznie i sprawdź jego wynik. Brak komunikatów zazwyczaj oznacza, że cron uruchamia skrypt z niewłaściwym uprawnieniem, przez co PHP nie może zapisać danych w data/.
Moja aplikacja mobilna nie może się połączyć, mimo że strona WWW działa. Dlaczego?
API Google Reader umieszcza zakodowane ukośniki (%2F) w ścieżkach żądań, a Apache domyślnie je odrzuca. Dodaj AllowEncodedSlashes On wewnątrz konfiguracji wirtualnego hosta i przeładuj Apache. Potwierdź poprawność poprawki, otwierając https://rss.example.com/api/ i uruchamiając "Check full server configuration", co powinno zwrócić PASS. Sprawdź również, czy hasło do API zostało ustawione w profilu, ponieważ jest ono niezależne od hasła logowania.
Czy powinienem użyć SQLite czy MariaDB?
SQLite dla jednego użytkownika, ponieważ nie wymaga instalacji ani zarządzania hasłami. MariaDB, gdy z instancji korzysta więcej niż jedna osoba lub gdy liczba kanałów przekracza kilkaset, ponieważ zadanie odświeżania i interfejs WWW zapisują dane jednocześnie, a blokada pojedynczego pliku staje się wąskim gardłem. Migracja między nimi jest możliwa później za pomocą poleceń eksportu i importu, więc nie jest to decyzja ostateczna.
Instalator kończy się błędem podczas zapisu konfiguracji. Co jest nie tak?
PHP działa jako www-data w środowisku Apache, a ten użytkownik nie ma uprawnień do zapisu w katalogu należącym do root. Wykonaj ponownie sudo chown -R www-data:www-data /srv/freshrss oraz sudo chmod -R g+w /srv/freshrss/data, a następnie uruchom instalator ponownie. Jeśli instalator wiersza poleceń został już uruchomiony jako root, usuń pliki utworzone w data/ przed ponowną próbą, ponieważ to ich właściciel stanowi rzeczywisty problem.
Jakich zasobów serwera wymaga własny czytnik RSS?
Bardzo niewielkich. Kilkaset kanałów na małym planie działa płynnie, ponieważ obciążenie to krótkie serie zapytań HTTP co dwadzieścia minut, a baza danych pozostaje mała po usunięciu starych artykułów. Wykorzystanie dysku rośnie wraz z retencją, dlatego ustaw politykę usuwania artykułów w ustawieniach archiwizacji, zamiast przechowywać wszystko bezterminowo.