Tự host Chaptarr quản lý audiobook trên VPS
Readarr đã dừng ngày 27/6/2025. Dựng Chaptarr bằng Docker Compose, đặt đúng PUID và PGID, rồi xử lý lỗi metadata khi quản lý audiobook, ebook.
Chaptarr là gì và vì sao người dùng Readarr cần nó
Chaptarr là một fork của Readarr, dùng để quản lý audiobook và ebook trong cùng một instance. Nó theo dõi các bản phát hành mới, gửi chúng đến download client, sau đó đổi tên kết quả và sắp xếp chúng vào library. Chaptarr không phát nội dung, vì vậy bạn cần kết hợp nó với một player như Audiobookshelf.
Readarr đã ngừng hoạt động vào ngày 27 June 2025. Thông báo của chính nhóm Servarr nêu rõ lý do: metadata của dự án đã không còn sử dụng được, còn nỗ lực của cộng đồng nhằm chuyển sang Open Library đã đình trệ. Repository đã được lưu trữ. Vì vậy, các bộ sưu tập ebook và audiobook không còn một trình quản lý được duy trì, và Chaptarr đã tiếp nhận nhiệm vụ này. Nó vẫn giữ cách tổ chức mà bạn đã quen thuộc từ Sonarr và Radarr (indexer, download client, quality profile, root folder), đồng thời bổ sung khả năng xử lý audiobook: sắp xếp theo narrator, quản lý nhiều edition của cùng một tựa sách, hỗ trợ M4B và MP3 theo chapter, và chuyển đổi MP3 sang M4B.
Bài hướng dẫn này sử dụng image tag chaptarr/chaptarr:0.9.925, là bản phát hành mới nhất vào ngày 9 August 2026. Chaptarr tự xác định là beta software. Hãy đọc phần bảo trì ở gần cuối trước khi trỏ nó vào một library mà bạn không thể khôi phục.
Những gì cần chuẩn bị trước khi bắt đầu
Một VPS đang chạy Docker và Compose plugin, cùng đủ dung lượng đĩa cho thư viện. Audiobook thường có dung lượng lớn. Nếu quá trình import không thể dùng hardlink, hệ thống sẽ giữ hai bản sao của một file trong một thời gian. Phần volume bên dưới sẽ giải thích điều này. Nếu Docker chưa được cài trên máy, hãy bắt đầu với Cài đặt và chạy Docker trên VPS rồi quay lại.
Hiện tại Chaptarr chỉ được phát hành dưới dạng Docker image. Bản build native cho Windows đang được phát triển và chưa có package cho bản phân phối nào. Container lưu database mặc định dưới dạng SQLite tại /config. Nếu đã có PostgreSQL server đang chạy, bạn có thể dùng server đó thông qua các biến môi trường Chaptarr__Postgres__*. SQLite là lựa chọn phù hợp cho một người dùng trên một máy chủ.
Service Compose cho Chaptarr
Service này được thêm vào một stack hiện có. Cấu hình cố định theo một tag đã phát hành, chỉ publish web UI trên loopback và tham gia network mà download client của bạn đang dùng.
services:
chaptarr:
image: chaptarr/chaptarr:0.9.925
container_name: chaptarr
environment:
- PUID=1000
- PGID=1000
- UMASK=002
- TZ=Europe/Berlin
volumes:
- ./config:/config
- /srv/media/audiobooks:/audiobooks
- /srv/media/ebooks:/ebooks
- /srv/media/downloads:/downloads
ports:
- 127.0.0.1:8789:8789
restart: unless-stopped
networks:
- arr
networks:
arr:
external: trueDòng external: true có nghĩa là “network này đã tồn tại, hãy kết nối service vào đó”. Dùng cấu hình này khi Prowlarr và torrent client nằm trong một Compose project khác, vì nếu không, file Compose thứ hai sẽ tự tạo một network riêng biệt. Khi đó Chaptarr sẽ không thể resolve qbittorrent bằng tên. Lấy tên thực tế bằng docker network ls. Nếu stack của bạn đã nằm trong cùng một file, hãy thêm service chaptarr: vào file đó và xóa toàn bộ block networks:. Bố cục đầy đủ được trình bày trong một arr stack đầy đủ với Docker Compose, còn quy tắc đặt tên được trình bày trong cách Compose resolve network và tên service.
Tự tạo thư mục config, sau đó khởi động service.
mkdir -p ./config
sudo chown 1000:1000 ./config
docker compose up -d
docker compose ps
docker compose logs -f chaptarrdocker compose ps phải hiển thị container ở trạng thái Up. Container có trạng thái Restarting đã khởi động thất bại và đang được thử lại. Nguyên nhân gần như luôn nằm ở thư mục config. Log sẽ dừng cuộn khi ứng dụng bắt đầu lắng nghe trên port 8789.
PUID, PGID và thư mục Docker tạo bằng root
Chaptarr mặc định dùng PUID=99 và PGID=100 nếu bạn không đặt các giá trị này. Đây là các giá trị của unRAID. Trên Ubuntu VPS thông thường, chúng thuộc về một user không có ích cho bạn, nên các file được tạo với owner mà tài khoản đăng nhập của bạn không thể ghi. Đọc các giá trị của bạn bằng id -u và id -g, rồi đặt chúng vào file.
Mọi container cùng thao tác với một nhóm file phải dùng cùng một cặp giá trị. Download client ghi vào /srv/media/downloads, Chaptarr chuyển file vào /srv/media/audiobooks, rồi player đọc file tại đó. Nếu download client ghi với 1000:1000 còn Chaptarr chạy với 99:100, thao tác import sẽ fail vì Chaptarr không thể xóa hoặc di chuyển file mà nó không sở hữu. UMASK=002 làm cho các file mới có quyền ghi ở cấp group, đúng với trường hợp nhiều container dùng chung một media group. Toàn bộ ánh xạ được trình bày trong cách PUID và PGID ánh xạ user của container vào các file trên host.
README cảnh báo một lỗi cụ thể và điều này đáng được nhắc lại. Nếu ./config chưa tồn tại khi bạn chạy docker compose up, Docker sẽ tự tạo nó với owner là root:root. Sau đó container chạy dưới UID 1000 và không thể ghi database của chính nó, nên thoát rồi restart liên tục. Kiểm tra bằng ls -ln ./config. Lệnh này in owner ở dạng số thay vì tên. Hai số 0 có nghĩa là root sở hữu thư mục. Sửa bằng sudo chown -R 1000:1000 ./config rồi khởi động lại container.
Vì sao tách volume audiobook và ebook làm hardlink không hoạt động
Bố cục trên mount /audiobooks, /ebooks và /downloads thành các bind riêng, đúng với lệnh chạy của project. Cách này dễ đọc, nhưng có một chi phí thực tế: hardlink không còn hoạt động.
Hardlink là tên thứ hai trỏ đến cùng một dữ liệu trên disk. Nó không dùng thêm dung lượng và được tạo ngay lập tức, nên họ arr ưu tiên hardlink thay vì copy. Hardlink chỉ hoạt động trong cùng một filesystem. Bên trong container, đây là ba mount point riêng biệt, nên kernel từ chối tạo link ngay cả khi các path trên host nằm trên cùng một disk. Bạn có thể tự kiểm tra.
docker exec chaptarr sh -c 'touch /downloads/linktest && ln /downloads/linktest /audiobooks/linktest'Lệnh sẽ fail với lỗi kết thúc bằng Invalid cross-device link. Đây là kernel từ chối tạo link giữa các mount point, và cũng là lý do chính xác khiến Chaptarr chuyển sang copy file. Bản copy vẫn đúng nhưng chậm hơn, và audiobook sẽ tồn tại hai lần cho đến khi bạn xóa torrent. Bạn sẽ không làm vậy khi vẫn đang seed torrent. Xóa /srv/media/downloads/linktest sau đó.
Để giữ hardlink, hãy mount một thư mục cha duy nhất:
volumes:
- ./config:/config
- /srv/media:/dataSau đó đặt các root folder trong Chaptarr thành /data/audiobooks và /data/ebooks, đồng thời cấp cho download client cùng mount /srv/media:/data để cả hai container nhìn thấy một path giống hệt nhau. Trước tiên, xác nhận phía host chỉ dùng một filesystem: df -h /srv/media/downloads /srv/media/audiobooks phải in cùng một giá trị trong cột Filesystem cho cả hai path. Các giá trị khác nhau nghĩa là hai disk khác nhau, và không có bố cục mount nào có thể tạo hardlink giữa chúng. Phần so sánh bind mount với named volume cho media trình bày trade-off giữa cách này và named storage.
Truy cập giao diện web mà không public ra Internet
Dòng port bind vào 127.0.0.1 có lý do. ufw deny 8789 không bảo vệ được port Docker đã publish, vì Docker tự ghi các rule NAT (network address translation) vào một chain mà kernel xử lý trước chain của ufw. Vì vậy, traffic được forward trước khi rule của bạn được kiểm tra. Hành vi này thường gây nhầm lẫn, và được giải thích trong lý do port Docker đã publish bỏ qua rule ufw. Bind vào loopback sẽ loại bỏ hoàn toàn vấn đề này.
Truy cập UI qua SSH tunnel từ máy của bạn:
ssh -N -L 8789:127.0.0.1:8789 you@your-serverGiữ tunnel đang chạy rồi mở http://127.0.0.1:8789 trong trình duyệt. Thiết lập authentication ngay lần chạy đầu tiên. Chỉ sau đó bạn mới nên cân nhắc đặt reverse proxy có TLS (transport layer security) phía trước. Khi phải tunnel vào ba hoặc bốn công cụ như vậy và dùng một password riêng cho từng công cụ, cách gọn hơn là đặt proxy phía sau một server single sign-on tự host như Authentik, để một lần đăng nhập áp dụng cho mọi app và một lần revoke sẽ vô hiệu hóa tất cả.
Kết nối indexer và download client
Chaptarr sử dụng các giao thức chuẩn của hệ sinh thái arr cho indexer và download client. Vì vậy, Prowlarr đẩy indexer vào Chaptarr giống như với Sonarr, còn các client torrent và usenet thông thường kết nối mà không cần xử lý đặc biệt.
Có một thiết lập khiến gần như mọi người đều gặp lỗi. Khi Chaptarr yêu cầu hostname của download client, không nhập localhost hoặc 127.0.0.1. Bên trong container, địa chỉ đó trỏ về chính container hiện tại. Vì vậy, Chaptarr sẽ cố kết nối đến port 8080 của chính nó và báo lỗi không thể kết nối. Hãy dùng tên container qbittorrent cùng port 8080. Xác nhận cả hai container nằm trên cùng một network bằng docker network inspect arr. Lệnh này liệt kê tên của mọi container đang được kết nối.
Nếu download client chạy qua một VPN container bằng network_mode: "service:gluetun", nó không có tên riêng trên network vì dùng chung network namespace của Gluetun. Hãy truy cập nó qua gluetun trên port mà Gluetun expose. Cách thiết lập này và cấu hình routing tương ứng được trình bày trong định tuyến download client qua Gluetun.
Chi phí thực sự khi chuyển từ Readarr
Chaptarr không tương thích với các nguồn metadata của Readarr. Chaptarr phân giải tên sách, tác giả và các ấn bản qua pipeline riêng trên nhiều provider, nên các identifier mà Readarr đã lưu không có ý nghĩa ở đây. Không có cách import database hoặc nâng cấp trực tiếp.
Với library hiện có, các file vẫn an toàn nhưng settings thì không được giữ lại. Quy trình này không tác động đến dữ liệu đã có trên disk. Bạn thêm một root folder, chạy library import, rồi Chaptarr đối chiếu các file tìm được với metadata riêng của nó. Những phần bạn phải tự dựng lại gồm quality profile, naming format, settings của indexer và client, cùng mọi kết quả đối chiếu sai mà Chaptarr đưa ra. Library lớn sẽ cần kiểm tra và sửa thủ công, vì vậy hãy dành cả buổi tối thay vì chỉ mười phút.
Hãy thực hiện theo thứ tự này. Dừng container Readarr nhưng giữ lại config volume để vẫn có thể xem settings cũ trong lúc nhập lại. Trỏ Chaptarr vào một folder nhỏ trước và kiểm tra kết quả đối chiếu rồi mới import toàn bộ. Chỉ xóa container cũ sau khi bạn đã thấy mọi thứ ổn.
Có một chi tiết về quyền riêng tư bạn nên biết trước khi quét toàn bộ library: các truy vấn metadata được gửi đến api2.chaptarr.com. README cho biết những request này có thể chứa provider ID, nội dung tìm kiếm, loại media, tag và tên file, đồng thời không chứa full path, danh tính người dùng hoặc credential. Tên file rời khỏi server của bạn. Đây là hành vi bình thường của metadata service, nhưng bạn vẫn nên chủ động quyết định có chấp nhận hay không.
Audiobook phát cho trình phát
Chaptarr quản lý file. Việc phát file là nhiệm vụ của chương trình khác. Audiobookshelf thường được dùng cùng vì nó theo dõi vị trí đang nghe trên nhiều thiết bị và có ứng dụng cho điện thoại. Image chính thức của nó là ghcr.io/advplyr/audiobookshelf:latest. Ví dụ Compose trong tài liệu của Audiobookshelf publish host port 13378 vào container port 80.
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
ports:
- 127.0.0.1:13378:80
volumes:
- ./abs/config:/config
- ./abs/metadata:/metadata
- /srv/media/audiobooks:/audiobooks
environment:
- TZ=Europe/Berlin
restart: unless-stoppedMount cùng host path mà Chaptarr ghi file vào, rồi thêm /audiobooks làm library trong web UI. Bản import mới sẽ xuất hiện sau lần scan tiếp theo.
Nếu bạn đã chạy Jellyfin, có thể thêm folder này làm library trong đó để phát file. Tuy nhiên, chức năng resume với một file audiobook dài thường kém hơn so với audiobook server chuyên dụng. Cách cấu hình Jellyfin được trình bày trong chạy Jellyfin làm media server trên VPS. Với phần ebook, chuyển /srv/media/ebooks cho một ứng dụng đọc. Chaptarr hoàn tất nhiệm vụ khi file đã được đặt tên và lưu đúng thư mục.
Rủi ro bảo trì: giấy phép, runtime và tag thay đổi nhanh
Chaptarr được cấp phép theo GPL-3.0. Bản quyền thuộc về các contributor của Chaptarr, với một phần mã từ team Servarr. Vì vậy, mã nguồn vẫn mở và bất kỳ ai cũng có thể fork lại nếu maintainer này dừng dự án. Chaptarr dùng .NET 10, là bản long term support hiện tại của runtime tính đến tháng 8 năm 2026. Điều này có nghĩa nền tảng được hỗ trợ trong nhiều năm thay vì chỉ vài tháng. Cả hai yếu tố đều quan trọng khi bạn đánh giá liệu dự án còn tồn tại vào năm sau hay không.
Số phiên bản thay đổi nhanh. Các bản release được phát hành dưới dạng pre-release, và 0.9.925 được phát hành đúng vào ngày bài hướng dẫn này được viết. Hãy pin một tag cụ thể. Dùng latest có thể khiến một docker compose pull không cần giám sát tự động nâng bạn qua vài phiên bản trong một tuần. Một fork còn mới như vậy cũng có thể thay đổi API giữa các bản release, làm hỏng mọi script hoặc dashboard bạn đã viết để sử dụng với nó. Pin version là thói quen nên áp dụng cho mọi dự án còn mới mà bạn self-host. Vì lý do tương tự, bài hướng dẫn chạy openGym làm workout tracker self-host cũng deploy từ một git tag cố định.
Hãy backup trước mỗi lần upgrade, sau đó chủ động thực hiện upgrade.
docker compose stop chaptarr
sudo tar czf chaptarr-config-backup.tgz ./config
docker compose start chaptarrdocker compose pull chaptarr
docker compose up -d chaptarrDự án báo cáo không có sự cố mất dữ liệu nào trong khoảng sáu tháng và với hơn mười một nghìn người dùng. Tuy vậy, dự án vẫn khuyến nghị duy trì backup và không trỏ ứng dụng vào một library mà bạn không thể chấp nhận bị mất. Hãy xem nghiêm túc cả hai điểm này. Sao chép archive cấu hình ra khỏi server, vì backup nằm trên cùng một disk với dữ liệu mà nó bảo vệ thì không phải là backup. Một tarball duy nhất là đủ chỉ vì Chaptarr lưu state trong một file SQLite tại /config; mọi dữ liệu nằm trên database server riêng đều cần được dump thêm. Đây cũng là cấu trúc của bước backup khi tự host Chatwoot trên VPS cùng với dữ liệu Postgres và các file đã upload.
Các tình huống lỗi và chuỗi bạn sẽ thấy
Container khởi động lại liên tục. docker compose ps hiển thị Restarting. Chạy ls -ln ./config. Hai số 0 trong các cột owner có nghĩa là Docker đã tạo thư mục dưới quyền root, nên user của container không thể ghi database của nó. Chạy sudo chown -R 1000:1000 ./config.
Import không bao giờ hoàn tất và file vẫn nằm trong thư mục downloads. Chaptarr có thể đọc file đã tải xuống nhưng không thể ghi vào library. So sánh ls -ln /srv/media/audiobooks với PUID và PGID của bạn. Thư mục thuộc về một UID khác, hoặc thuộc về group của bạn nhưng không cho phép group ghi, sẽ khiến thao tác di chuyển thất bại. UMASK=002 ngăn trường hợp thứ hai đối với file mới.
Dung lượng disk tăng gấp đôi sau mỗi lần import. Không tạo được hardlink nên file đã bị sao chép. Chạy phép kiểm tra ln trong phần volumes. Lỗi kết thúc bằng Invalid cross-device link xác nhận nguyên nhân này; dùng một mount point chung là cách khắc phục.
Download client không kết nối được. Bạn đã nhập localhost làm host. Bên trong container, đó chính là Chaptarr. Hãy dùng tên container và kiểm tra docker network inspect arr để xác nhận cả hai container đều được liệt kê.
Compose từ chối khởi động service. Bind for 127.0.0.1:8789 failed: port is already allocated có nghĩa là một tiến trình khác đang giữ cổng này. Tìm tiến trình đó bằng sudo ss -lntp | grep 8789.
Trình duyệt hoàn toàn không hiển thị gì. Khi cổng được bind vào 127.0.0.1, laptop của bạn không có gì để kết nối qua Internet. Đây là hành vi đúng theo thiết kế. Trước tiên hãy mở SSH tunnel.
FAQ
Tôi có thể migrate thư viện Readarr sang Chaptarr không?
Không thể import trực tiếp. Chaptarr không tương thích với các nguồn metadata của Readarr và sử dụng pipeline provider riêng, nên các identifier được Readarr lưu trữ không có ý nghĩa và không có cách chuyển đổi database. Các file trên disk của bạn không bị thay đổi. Bạn thêm các path tương tự làm root folder, chạy library import và để Chaptarr tự match các file. Quality profile, naming format, cài đặt indexer và các kết quả match sai đều phải xử lý thủ công, vì vậy hãy bắt đầu với một folder nhỏ trước khi import toàn bộ.
Tại sao Chaptarr không thể ghi vào folder audiobook của tôi?
User trong container không sở hữu các file. Khi các biến này chưa được set, Chaptarr dùng PUID=99 và PGID=100 làm giá trị dự phòng. Đây là các giá trị của unRAID và không đúng trên Ubuntu VPS thông thường. Hãy set chúng thành id -u và id -g của bạn, dùng cùng cặp giá trị đó trên download client và set UMASK=002 để các file mới vẫn cho phép group ghi. Kiểm tra ownership bằng ls -ln trên thư mục library, vì lệnh này in ra các số thay vì tên nên bạn không thể đối chiếu theo tên.
Tại sao dung lượng disk của tôi tăng gấp đôi sau khi import?
Chaptarr đã copy file vì không thể tạo hardlink cho file đó. Mount /downloads và /audiobooks dưới dạng các bind riêng khiến chúng trở thành các mount point riêng bên trong container, và kernel từ chối tạo hardlink giữa các mount point với lỗi Invalid cross-device link. Hãy mount một thư mục cha như /srv/media:/data, rồi dùng /data/downloads và /data/audiobooks bên trong app. Cả hai path cũng phải nằm trên cùng một filesystem của host; df -h sẽ xác nhận điều này.
Chaptarr có phát audiobook của tôi không?
Không. Chaptarr tìm, download, đổi tên và sắp xếp các file. Playback do một chương trình riêng đảm nhiệm. Audiobookshelf là lựa chọn thường dùng cùng Chaptarr vì nó ghi nhớ vị trí phát trên nhiều thiết bị. Hãy dùng image chính thức ghcr.io/advplyr/audiobookshelf:latest và mount cùng path audiobook của host. Jellyfin cũng phát được các file nếu bạn thêm folder đó làm library, nhưng khả năng resume kém hơn với audiobook dài chỉ có một file.
Chạy Chaptarr trên library quan trọng với tôi có an toàn không?
Chaptarr là beta software từ một fork còn mới. Chính project cũng nêu rõ điều này, đồng thời báo cáo không có sự kiện mất dữ liệu nào trong khoảng sáu tháng với hơn mười một nghìn user. Các điểm đáng tin cậy gồm giấy phép GPL-3.0, cho phép tiếp tục fork code, và nền tảng .NET 10, là runtime hỗ trợ dài hạn tính đến tháng 8 năm 2026. Hãy pin một image tag chính xác như 0.9.925 thay vì latest, backup /config trước mỗi lần upgrade và lưu archive đó ngoài server.