So sánh trình đọc RSS self-host trên VPS nhỏ
So sánh Miniflux, FreshRSS, CommaFeed, yarr và Tiny Tiny RSS về memory, database, API Fever, Google Reader và cách nâng cấp trên VPS.
Trình đọc RSS self-host nào phù hợp với VPS nhỏ
Miniflux là trình đọc RSS self-host phù hợp để chạy trên VPS nhỏ. Nó chỉ gồm một binary Go và PostgreSQL. Miniflux hỗ trợ API Fever và Google Reader, nên các ứng dụng điện thoại của bên thứ ba có thể kết nối. Khi nâng cấp, bạn chỉ cần một docker compose pull. Hãy chọn FreshRSS nếu bạn cần extension và muốn chạy mọi thứ trong một container có SQLite bên trong.
Có 5 trình đọc đáng dành dung lượng đĩa trên VPS: Miniflux, FreshRSS, CommaFeed, yarr và Tiny Tiny RSS. Trang này so sánh những điểm thực sự khác nhau giữa chúng: mỗi stack cần bao nhiêu memory, mỗi ứng dụng bắt buộc bạn dùng database nào, ứng dụng điện thoại cần API đồng bộ nào và quá trình nâng cấp diễn ra ra sao. Mỗi con số ở đây đều do project công bố hoặc được tính bằng phép tính đơn giản, và nội dung sẽ nói rõ nguồn nào được dùng. Đây không phải benchmark cho phần cứng của bạn, vì vậy hãy đo trên máy của bạn bằng docker stats.
Năm trình đọc, mỗi trình một đoạn
Miniflux được viết bằng Go và phát hành dưới dạng một binary duy nhất đã được biên dịch tĩnh. Tài liệu của dự án nêu rõ dependency bắt buộc duy nhất: nó "chỉ hoạt động với PostgreSQL". Không có chế độ SQLite. Miniflux cung cấp REST API, API tương thích với Fever và API tương thích với Google Reader, cùng chức năng import và export OPML. PostgreSQL đảm nhiệm full-text search. Đây là một trong những lý do database không phải là tùy chọn.
FreshRSS là ứng dụng PHP và chạy trong một container chứa cả web server lẫn ứng dụng. SQLite là database mặc định và không cần service thứ hai. PostgreSQL và MySQL cũng được hỗ trợ cho các cài đặt lớn hơn. FreshRSS hỗ trợ Google Reader API và Fever API. Cách cài đặt đã được trình bày trong hướng dẫn FreshRSS trên VPS của chúng tôi, nên trang này chỉ so sánh thay vì lặp lại phần cài đặt.
CommaFeed là ứng dụng Java chạy trên Quarkus, với giao diện mô phỏng Google Reader. Database được chọn tại thời điểm build, không phải lúc runtime. Vì vậy, dự án phát hành một image cho mỗi database: athou/commafeed:latest-h2 cho database H2 nhúng sẵn, athou/commafeed:latest-postgresql cho PostgreSQL, cùng các biến thể khác cho MySQL và MariaDB. CommaFeed cung cấp REST API và API tương thích với Fever.
yarr (yet another rss reader) là một binary Go duy nhất, nhúng SQLite và không cần container. Lệnh ./yarr mặc định lắng nghe trên 127.0.0.1:7070. Các flag khá ngắn: -addr 0.0.0.0:7070 -auth alice:secret mở dịch vụ cho network phía sau password, còn -db /data/yarr.db đặt database vào vị trí bạn muốn. yarr có API tương thích với Fever. Bản release được tag mới nhất là v2.8, phát hành vào tháng 7 năm 2024 và được kiểm tra vào tháng 8 năm 2026, nên hãy xem đây là phần mềm đã hoàn thiện thay vì đang được phát triển tích cực.
Tiny Tiny RSS là dự án lâu đời nhất trong năm trình đọc và cũng là dự án nặng nhất khi vận hành. Cấu hình Docker chính thức gồm 4 service: một PostgreSQL container, một PHP-FPM application container, một updater container riêng để fetch feed và một nginx container ở phía trước. Tài liệu nêu rõ: "cấu hình này sử dụng PostgreSQL". Tiny Tiny RSS có JSON API riêng, được client Android của dự án và một số app bên thứ ba sử dụng. Nó không hỗ trợ Fever.
Mỗi stack cần bao nhiêu memory
Các con số dưới đây là ngân sách, không phải số đo thực tế: đây là mức trần memory mà mỗi stack nên nằm dưới khi chạy trên một VPS nhỏ. Con số của CommaFeed là ví dụ do chính dự án công bố, trong đó container bị giới hạn ở mức 256 MB. Các stack còn lại dùng mức trần có chừa headroom cho feed fetcher, vì thành phần này tăng memory đột biến khi bắt đầu một chu kỳ refresh.
The data behind this chart
[
{
"label": "yarr (SQLite)",
"containers": 1,
"mem_limit_mb": 128
},
{
"label": "FreshRSS (SQLite)",
"containers": 1,
"mem_limit_mb": 256
},
{
"label": "CommaFeed (H2)",
"containers": 1,
"mem_limit_mb": 256
},
{
"label": "Miniflux + Postgres",
"containers": 2,
"mem_limit_mb": 320
},
{
"label": "Tiny Tiny RSS",
"containers": 4,
"mem_limit_mb": 640
}
]yarr dùng ít memory nhất, ở mức 128 MB, vì nó chỉ gồm một binary và một file SQLite, không có database server hay language runtime bên dưới. Miniflux cần 320 MB cho 2 container, trong đó phần lớn thuộc về PostgreSQL chứ không phải Miniflux. Tiny Tiny RSS là trường hợp khác biệt, ở mức 640 MB cho 4 container, vì application, updater, database và web server là 4 process riêng biệt với 4 heap riêng biệt.
Hãy đặt đây là các giới hạn thực tế, thay vì chỉ hy vọng. Giới hạn memory trong Docker Compose giải thích cú pháp và điều gì xảy ra khi container chạm mức trần. Container không có giới hạn sẽ không dừng một cách an toàn khi máy đã hết memory: kernel sẽ chọn một process để kill, và process đó thường không phải container gây ra tình trạng thiếu memory.
Mỗi reader buộc bạn dùng database nào
Database là khác biệt lớn nhất về vận hành giữa 5 lựa chọn này. Đây là quyết định quan trọng hơn mọi khác biệt về giao diện người dùng, vì nó quyết định quy trình backup và rủi ro khi upgrade.
Miniflux và bộ cài Tiny Tiny RSS chính thức yêu cầu PostgreSQL. PostgreSQL cung cấp full-text search thực sự và hỗ trợ ghi đồng thời an toàn. Đổi lại, bạn phải chạy thêm một container, dùng thêm một volume và xử lý một vấn đề lặp lại: các image PostgreSQL chính thức không thể migrate dữ liệu giữa các major version ngay tại chỗ. Tài liệu Tiny Tiny RSS nói rõ điều này và cảnh báo rằng “official PostgreSQL containers have no support for migrating data between major versions”. Các lựa chọn thực tế của bạn là giữ cố định major version cũ, hoặc dump rồi restore bằng pg_dump và pg_restore. Hãy chuẩn bị thực hiện việc này 1 lần mỗi 1 hoặc 2 năm.
SQLite là lựa chọn mặc định của FreshRSS và yarr. Chỉ cần 1 file, không cần server, port hay password. SQLite hoạt động tốt với 1 người dùng và vài trăm feed. Nó chậm lại khi nhiều người dùng ghi dữ liệu cùng lúc. Đây là lúc tùy chọn PostgreSQL của FreshRSS bắt đầu phát huy tác dụng. yarr bổ sung hỗ trợ PostgreSQL tùy chọn trong v2.7, nhưng file nhúng vẫn là cách chạy thông thường.
H2 là database nhúng mặc định của CommaFeed. Bạn nên cân nhắc việc này trước khi bắt đầu, vì CommaFeed chọn database khi build image. Chuyển từ H2 sang PostgreSQL về sau không phải là thay đổi cấu hình. Đây là việc dùng một image khác và tự thực hiện data migration. Vì vậy, hãy quyết định trước khi database có 1 năm lịch sử đọc trên máy.
Ứng dụng trên điện thoại của bạn có hoạt động không
Câu hỏi này quyết định nhiều hơn mọi người thường nghĩ, vì giao diện web chỉ là một nửa cách người dùng sử dụng feed reader.
Miniflux cung cấp API tương thích với Fever và API tương thích với Google Reader, nên hầu hết client iOS và Android đều kết nối được với nó. FreshRSS cũng cung cấp hai API này và tài liệu riêng của nó đánh giá thứ tự ưu tiên: Google Reader API là "tốt nhất" với hỗ trợ đầy đủ tính năng, còn Fever API có hành vi "tính năng hạn chế và kém hiệu quả hơn". FreshRSS cũng cần thực hiện 2 bước trước khi bất kỳ ứng dụng nào có thể đăng nhập. Bật "Cho phép truy cập API (bắt buộc cho ứng dụng di động)" trong mục Authentication, rồi tạo API password trong user profile. Nếu bỏ qua API password, ứng dụng sẽ báo lỗi xác thực trong khi đăng nhập qua web vẫn hoạt động. Điều này dễ gây nhầm lẫn nếu bạn chưa biết cần kiểm tra ở đâu.
CommaFeed và yarr đều chỉ cung cấp API tương thích với Fever, không cung cấp API nào khác. Vì vậy, chúng hoạt động với các client hỗ trợ Fever nhưng không hoạt động với những ứng dụng chỉ hỗ trợ Google Reader. Tiny Tiny RSS có API riêng, nên bạn cần client được viết cho nó. Hãy kiểm tra ứng dụng bạn muốn dùng có hỗ trợ reader đó hay không trước khi import 300 feed vào.
Tệp compose dùng được cho máy 1 GB
Đây là stack Miniflux, được điều chỉnh từ ví dụ Docker của chính dự án vào tháng 8 năm 2026. Cổng được publish chỉ bind vào loopback, địa chỉ listen được đặt rõ ràng, và cả hai container đều có giới hạn bộ nhớ.
services:
miniflux:
image: miniflux/miniflux:latest
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://miniflux:CHANGE_ME@db/miniflux?sslmode=disable
- LISTEN_ADDR=0.0.0.0:8080
- BASE_URL=https://rss.example.com/
- RUN_MIGRATIONS=1
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=CHANGE_ME_TOO
- POLLING_FREQUENCY=60
healthcheck:
test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
mem_limit: 128m
db:
image: postgres:18
restart: unless-stopped
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=CHANGE_ME
- POSTGRES_DB=miniflux
volumes:
- miniflux-db:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "miniflux"]
interval: 10s
start_period: 30s
mem_limit: 192m
volumes:
miniflux-db:Có 3 dòng trong tệp này thường bị cấu hình sai. LISTEN_ADDR=0.0.0.0:8080 được đặt vì giá trị mặc định được tài liệu của binary ghi là 127.0.0.1:8080. Một process bind vào loopback bên trong container không thể được truy cập qua cổng đã publish, nên kết nối sẽ bị reset dù container vẫn có vẻ đang hoạt động. Đường dẫn volume /var/lib/postgresql khớp với PostgreSQL 18. PostgreSQL 17 trở về trước lưu dữ liệu tại /var/lib/postgresql/data. Mount sai đường dẫn nghĩa là data directory không nằm trên volume, nên mọi dữ liệu sẽ biến mất khi container được tạo lại lần tiếp theo. 127.0.0.1:8080:8080 giữ cho cổng không public ra Internet, vì publish cổng mà không chỉ định địa chỉ sẽ ghi một rule vào chain mà ufw không quản lý. Docker bỏ qua ufw khi publish cổng giải thích cơ chế này, còn reverse proxy Traefik là cách đặt TLS phía trước dịch vụ.
docker compose up -d
docker compose ps
docker compose logs -f miniflux
docker stats --no-streamdocker compose ps phải liệt kê cả hai service đang chạy, trong đó database được đánh dấu healthy. Lần đầu Miniflux khởi động, log sẽ ghi các schema migration. Đây là việc RUN_MIGRATIONS=1 kích hoạt. docker stats --no-stream in ra cột bộ nhớ thực tế, và đó là con số cần so sánh với các giới hạn trong bảng phía trên. Nếu container Miniflux restart liên tục, hãy đọc log của container: connect: connection refused có nghĩa là Miniflux khởi động trước khi PostgreSQL sẵn sàng nhận kết nối. Đây chính xác là tình huống mà điều kiện service_healthy ngăn chặn, vì vậy hãy kiểm tra xem điều kiện này còn nguyên sau khi bạn chỉnh sửa tệp hay không. Nếu bạn chưa quen với Compose, Những điều cơ bản về Docker Compose trên VPS trước tiên trình bày bố cục tệp.
Những gì không phù hợp với máy 1 GB
Tiny Tiny RSS là lựa chọn nên bỏ qua. Stack 4 service chính thức của nó chạy được trên VPS 1 GB nếu VPS đó không làm gì khác. Nhưng nó không chạy được cùng một ứng dụng dùng database và một reverse proxy trên cùng máy. 4 service nghĩa là 4 phần overhead, trong đó có PostgreSQL.
CommaFeed có thể chạy được, nhưng chỉ với image H2 và giới hạn 256 MB mà ví dụ của dự án đặt ra. Tổ hợp khiến máy nhỏ bị quá tải là JVM chạy cùng một database server riêng, vì JVM sẽ dùng toàn bộ headroom bạn để lại. Tài liệu CommaFeed chỉ ra -Xmx256m là giới hạn cứng và gọi OpenJ9 là “một lựa chọn tiết kiệm memory hơn HotSpot JVM”. Điều này cho thấy memory được sử dụng ở đâu.
Khi máy hết memory, kernel out of memory killer sẽ chọn một process và terminate process đó. dmesg -T hiển thị một dòng như Out of memory: Killed process 1234 (java), còn container đơn giản biến mất khỏi docker compose ps mà không có message nào trong application log, vì application chưa kịp ghi log.
Cách nâng cấp hoạt động trên từng ứng dụng
- Miniflux:
docker compose pull && docker compose up -d, các migration schema được áp dụng khi khởi động trong lúcRUN_MIGRATIONS=1được bật. Rủi ro khi nâng cấp không nằm ở Miniflux. Rủi ro nằm ở phiên bản major của PostgreSQL bên dưới nó. - FreshRSS: pull image mới. Với SQLite, không có database engine nào cần nâng cấp, nên lỗi thường do các extension bên thứ ba chưa được cập nhật tương ứng.
- CommaFeed: pull biến thể image phù hợp với database của bạn. Chuyển từ
latest-h2sanglatest-postgresqlkhông chuyển dữ liệu theo. - yarr: thay binary và giữ lại file database. Tính đến tháng 8 năm 2026, yarr chưa có release nào kể từ v2.8 vào tháng 7 năm 2024, nên thường không có gì để nâng cấp.
- Tiny Tiny RSS:
docker compose pull && docker compose up -d. Schema migration chạy tự động. Khi cần xác nhận, giao diện sẽ chuyển hướng bạn đến màn hình migration.
Hãy tạo database dump trước khi thực hiện bất kỳ thao tác nào trong số này, không phải sau đó.
docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gzChi phí băng thông của chu kỳ làm mới
Các con số dưới đây là phép tính, không phải số đo thực tế. Chúng giả định có 100 feed, mỗi feed nhận một request trong mỗi chu kỳ và mỗi response có kích thước 40 KB. Lưu lượng thực tế sẽ thấp hơn khi server hỗ trợ conditional request, và cao hơn khi feed chứa toàn bộ nội dung bài viết.
The data behind this chart
[
{
"label": "Every 5 minutes",
"fetches_per_month": "864,000",
"gb_per_month": 34.6
},
{
"label": "Every 15 minutes",
"fetches_per_month": "288,000",
"gb_per_month": 11.5
},
{
"label": "Every 30 minutes",
"fetches_per_month": "144,000",
"gb_per_month": 5.8
},
{
"label": "Every 60 minutes",
"fetches_per_month": "72,000",
"gb_per_month": 2.9
}
]Chu kỳ 5 phút với 100 feed tạo ra 864,000 request và tiêu thụ khoảng 34.6 GB mỗi tháng. Polling mỗi giờ tạo ra 72,000 request và tiêu thụ khoảng 2.9 GB. Miniflux mặc định đặt POLLING_FREQUENCY là 60 phút, tương ứng với dòng cuối trong biểu đồ đó. Giá trị mặc định này phù hợp với gần như mọi trường hợp. Bài viết không xuất hiện sớm hơn chỉ vì bạn yêu cầu thường xuyên hơn.
Conditional request là yếu tố giữ lưu lượng thực tế thấp hơn phép tính. Reader lưu các header ETag và Last-Modified do feed trả về sẽ gửi lại chúng dưới dạng If-None-Match và If-Modified-Since. Khi không có nội dung mới, server trả về 304 Not Modified mà không có body. Kết nối vẫn tốn chi phí handshake, nhưng không phải tải payload. Những feed không hỗ trợ conditional request sẽ gửi toàn bộ tài liệu trong mỗi lần request. Vì vậy, chỉ vài feed lớn cũng có thể tự chiếm phần lớn dung lượng transfer của bạn.
Polling quá thường xuyên cũng khiến bạn bị chặn. Server phát hiện bạn đang gửi request quá dồn dập sẽ trả về 429 Too Many Requests, còn một số site sẽ trả về 403. Miniflux ghi lại lỗi gần nhất ngay trên feed. Vì vậy, danh sách feed là nơi đầu tiên cần kiểm tra khi một feed ngừng cập nhật trong khi các feed khác vẫn hoạt động.
Feed có thể ngừng hoạt động, và file OPML không phải là bản sao lưu
Feed hỏng nhanh hơn bạn nghĩ. Domain hết hạn, website chuyển sang nền tảng không có feed, và URL từng trả về XML bắt đầu trả về trang lỗi HTML với status 200 OK. Trường hợp cuối khó phát hiện hơn: quá trình fetch thành công, quá trình parse thất bại, và reader ghi nhận lỗi parse thay vì lỗi network. Mỗi năm một lần, hãy sắp xếp danh sách feed theo thời điểm cập nhật gần nhất rồi xóa những feed đã im lặng.
Bản export OPML là danh sách đăng ký của bạn. Nó chứa URL của feed và tên thư mục. Nó không chứa trạng thái đã đọc, bài viết được đánh dấu sao, cài đặt riêng cho từng feed, rule lọc hoặc nội dung bài viết bạn đã lưu. Khi import OPML đó vào một bản cài đặt mới, bạn lấy lại được các feed, nhưng mọi bài viết từng đọc sẽ lại bị đánh dấu là chưa đọc.
Bản sao lưu quan trọng là database. Với PostgreSQL, lệnh pg_dump ở trên là toàn bộ quy trình. Với reader dùng SQLite như FreshRSS hoặc yarr, hãy dừng tiến trình ghi rồi copy file, hoặc tạo một bản copy nhất quán trong khi nó đang chạy bằng sqlite3 yarr.db ".backup '/tmp/yarr-backup.db'". Một lệnh cp thông thường trên database đang được ghi có thể tạo ra file không mở được sau này, vì bản copy ghi lại một lần ghi chưa hoàn tất. Sau đó, hãy định kỳ đẩy các file đó ra khỏi máy chủ. Đây là mục đích của backup restic trên VPS. Ít nhất một lần, hãy restore một bản vào container tạm để xác nhận quy trình hoạt động.
Feed reader là một trong những service rẻ nhất để tự chạy. Vì vậy, nó xuất hiện trong mọi danh sách những thứ đáng tự host trong 2026. Đặt một instance SearXNG tự host bên cạnh nó để cả việc đọc và tìm kiếm đều chạy trên phần cứng do bạn kiểm soát.
FAQ
Trình đọc RSS tự host nào dùng ít memory nhất?
yarr. Đây là một binary Go đơn có tích hợp SQLite, nên không cần database server hoặc language runtime riêng, và giới hạn 128 MB là đủ. Đổi lại, bạn phải chấp nhận hạn chế về bảo trì và tính năng: bản release mới nhất là v2.8 từ tháng 7 năm 2024, và nó chỉ hỗ trợ Fever API. Nếu muốn một project vẫn đang được phát triển với mức sử dụng tài nguyên tương tự, Miniflux cùng PostgreSQL ở mức 320 MB là lựa chọn phù hợp hơn.
Có thể chạy trình đọc RSS tự host trên VPS 1 GB không?
Có. Miniflux cùng PostgreSQL chạy trong khoảng 320 MB khi bạn đặt mem_limit cho cả hai container, còn FreshRSS cùng SQLite chạy trong một container. Trên VPS 1 GB, nên tránh stack Tiny Tiny RSS chính thức vì stack này có 4 service, bao gồm cả PostgreSQL riêng. Luôn đặt memory limit, vì container không giới hạn trên máy đã đầy memory có thể bị kernel kill một process, và process bị chọn thường là database thay vì application đang gây lỗi.
Những project nào trong số này hoạt động với app RSS trên iOS và Android?
Miniflux và FreshRSS hỗ trợ cả API tương thích với Fever và API tương thích với Google Reader, nên gần như mọi mobile client đều kết nối được. CommaFeed và yarr chỉ cung cấp Fever API. Tiny Tiny RSS dùng API riêng, nên bạn cần client được xây dựng cho nó. Trên FreshRSS, bạn cũng phải bật API access trong mục Authentication và đặt API password riêng trong profile. Nếu không, app sẽ không đăng nhập được dù website vẫn hoạt động.
OPML export có phải là bản backup của trình đọc RSS không?
Không. OPML lưu URL của feed và các folder, nên chỉ khôi phục được danh sách subscription, không khôi phục được dữ liệu khác. Read state, item đã đánh dấu sao, filter rule và nội dung bài viết đều nằm trong database. Hãy backup chính database bằng pg_dump cho PostgreSQL hoặc bằng lệnh .backup cho SQLite, rồi copy kết quả ra ngoài server.
Miniflux có hỗ trợ SQLite không?
Không. Tài liệu của project nói rằng nó “chỉ hoạt động với PostgreSQL”, và full-text search được triển khai bằng các tính năng của PostgreSQL, nên không có mode nhẹ hơn để chuyển sang. Nếu muốn dùng feed reader không cần database container, hãy chạy FreshRSS với SQLite backend mặc định hoặc yarr với file được tích hợp sẵn.