cách cài Nextcloud trên VPS dùng Docker
Hướng dẫn cài Nextcloud trên VPS bằng Docker Compose, Postgres và Redis. Cách thiết lập TLS và backup dữ liệu an toàn để tránh mất file khi nâng cấp hệ thống.
Những gì bạn thực sự đang xây dựng
Hướng dẫn này chạy Nextcloud trên một VPS bằng Docker Compose, thiết lập Let's Encrypt TLS ở phía trước, và thiết lập một hệ thống backup có khả năng restore thực tế. Hệ thống gồm bốn container và một proxy: image nextcloud chính thức chạy trên loopback, Postgres lưu trữ toàn bộ metadata của file, Redis lưu trữ file locks, một bản sao thứ hai của image Nextcloud chỉ chạy cron loop, và nginx trên host để terminate TLS cho toàn bộ hệ thống. Quá trình cài đặt mất khoảng hai mươi phút, nhưng đó không phải là phần quan trọng nhất. Hai quyết định trong giờ đầu tiên sẽ quyết định việc bạn có còn giữ được file sau một năm hay không: sử dụng một database thực thụ thay vì SQLite, và một bản backup bao gồm directory chứa data, database và config.php thành một tập hợp nhất quán.
Hướng dẫn này giả định bạn dùng Ubuntu 24.04 LTS hoặc Debian 13, Docker Engine đã cài plugin Compose v2 từ repository của Docker, và một DNS A record (cùng với AAAA nếu bạn dùng IPv6) đã trỏ cloud.example.com về VPS. Bạn cần một server do chính bạn kiểm soát — không có cách nào để thực hiện TLS termination và database dump trên một dịch vụ SaaS của bên thứ ba.
Sizing: yếu tố nào thực sự tiêu tốn bộ nhớ
Mức tiêu thụ bộ nhớ của Nextcloud chủ yếu do ba yếu tố gây ra, và không có yếu tố nào là do bản thân "Nextcloud".
PHP workers. Image -apache xử lý mỗi request đồng thời từ một worker process có chứa PHP interpreter. Mỗi worker có thể tăng lên tới PHP_MEMORY_LIMIT trước khi PHP ngắt request đó. Mức tiêu thụ bộ nhớ (resident memory) trong trường hợp xấu nhất xấp xỉ bằng số lượng request đồng thời × giới hạn bộ nhớ, trong khi desktop sync client sẽ mở nhiều kết nối song song cho mỗi user. Số lượng request đồng thời, chứ không phải số lượng user, mới là yếu tố quyết định giới hạn trên.
The database. Postgres fork một backend cho mỗi kết nối và giữ các shared buffers trong bộ nhớ. Working set của nó tăng theo số lượng file, chứ không phải số lượng byte: oc_filecache lưu trữ một row cho mỗi file của mỗi user. Một trăm nghìn file nhỏ sẽ khiến database nặng hơn là một trăm file lớn.
Preview generation. Việc tạo thumbnail sẽ giải mã (decode) ảnh gốc vào bộ nhớ ở độ phân giải đầy đủ. Preview video sẽ gọi shell đến ffmpeg. Chạy occ preview:generate-all sẽ lặp lại các đợt tăng vọt bộ nhớ này liên tục, và là nguyên nhân phổ biến nhất khiến một VPS nhỏ bị dính OOM killer.
Redis tiêu tốn ít tài nguyên hơn. Bất kỳ thứ gì bạn cài thêm sau này — Collabora, full-text search, hay trình quét antivirus — đều là các service riêng biệt với mức chiếm dụng tài nguyên riêng, và bạn cần tính toán chúng vào kế hoạch sizing trước khi kích hoạt.
Các giải pháp nếu bạn bị thiếu RAM: giảm PHP_MEMORY_LIMIT, giới hạn preview_max_x / preview_max_y / preview_max_filesize_image, thu hẹp enabledPreviewProviders chỉ còn các định dạng bạn thực sự xem, và thiết lập trashbin_retention_obligation cùng versions_retention_obligation để thư mục data không tự động tăng lên gấp nhiều lần kích thước file thực tế. Hãy thêm một swap file. Swap thì chậm, nhưng bị OOM kill khi đang upgrade còn tệ hơn.
Tại sao SQLite bị lỗi
Nextcloud có hỗ trợ SQLite và image chính thức sẽ sử dụng nó mặc định. Đừng làm vậy. SQLite thực hiện tuần tự hóa các lệnh ghi bằng cách khóa toàn bộ database: tại một thời điểm chỉ có một writer cho toàn bộ file. Nextcloud ghi dữ liệu liên tục — file locks, các dòng activity, cache entries, trạng thái job — và một desktop client đang sync một cây thư mục sẽ gửi rất nhiều request song song. Với mô hình đó, bạn sẽ gặp lỗi SQLSTATE[HY000]: General error: 5 database is locked và lỗi HTTP 500, lỗi này thường xuất hiện ngay khi instance bắt đầu được sử dụng thực tế.
Bạn có thể chuyển đổi sau này bằng occ db:convert-type, nhưng đây là một quá trình migration dài và yêu cầu phải thành công hoàn toàn trên dataset đang chạy. Hãy bắt đầu với Postgres hoặc MariaDB.
File Compose
Đặt nội dung này vào /srv/nextcloud/compose.yaml, kèm theo các secrets trong một file .env nằm cùng cấp ở mode 600.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
app:
image: nextcloud:31-apache
restart: unless-stopped
depends_on: [db, redis]
ports:
- "127.0.0.1:8080:80"
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.example.com
APACHE_DISABLE_REWRITE_IP: "1"
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
cron:
image: nextcloud:31-apache
restart: unless-stopped
entrypoint: /cron.sh
depends_on: [db, redis]
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
volumes:
db:
html:Hãy chốt tag chính và kiểm tra tag hiện tại trên Docker Hub trước khi bạn copy nguyên văn 31. latest có thể khiến bạn nhảy qua một phiên bản major khác trong tương lai docker compose pull, và Nextcloud không hỗ trợ việc đó.
Thư mục data được thiết lập là bind mount thay vì named volume vì một mục đích cụ thể: một đường dẫn mà bạn có thể trỏ trực tiếp công cụ backup vào sẽ có giá trị hơn sự gọn gàng. Hãy tạo nó với UID www-data của image và các quyền (permissions) mà Nextcloud yêu cầu:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataLưu ý phần publish port: 127.0.0.1:8080:80. Docker publish các port bằng cách viết các rule DNAT, các rule này được xử lý trước khi chain INPUT của ufw nhìn thấy packet — một port 8080:80 để trống sẽ đẩy Nextcloud không mã hóa lên internet công cộng bất kể ufw thiết lập thế nào. Binding vào loopback giúp giữ nó tách biệt khỏi interface công cộng. Khi đó, firewall chỉ cần cho phép proxy — và nếu bạn không muốn mở SSH cho toàn bộ internet, truy cập VPS qua WireGuard VPN tự host sẽ giúp bạn xóa hoàn toàn port 22 khỏi các rule công cộng:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableKhởi chạy bằng docker compose up -d, sau đó theo dõi docker compose logs -f app. Lần boot đầu tiên sẽ copy toàn bộ cây ứng dụng vào volume và chạy trình cài đặt; container sẽ không phản hồi cho đến khi quá trình đó hoàn tất.
TLS và reverse proxy
Cài đặt nginx và certbot từ distro, tạo một server block port-80 thông thường với server_name chính xác, sau đó để certbot tự động rewrite nó. Cơ chế của HTTP-01 challenge, bộ đếm thời gian gia hạn (renewal timer) và các lỗi thường gặp được giải thích chi tiết trong cấp phát chứng chỉ Let's Encrypt bằng certbot và nginx trên Ubuntu 24.04:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comCertbot sẽ thêm các dòng ssl_certificate và lệnh redirect :80 → :443, đồng thời cài đặt một systemd timer để tự động gia hạn chứng chỉ mỗi 90 ngày. Kiểm tra bằng lệnh systemctl list-timers | grep certbot — nếu bộ đếm thời hạn gia hạn không được kích hoạt, chứng chỉ của bạn sẽ hết hạn sau 90 ngày.
Nội dung proxy block:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name cloud.example.com;
# certbot manages ssl_certificate / ssl_certificate_key here
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size 10G;
client_body_timeout 300s;
location = /.well-known/carddav { return 301 /remote.php/dav; }
location = /.well-known/caldav { return 301 /remote.php/dav; }
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}Trên nginx 1.25 trở lên, hãy thêm http2 on;. Ubuntu 24.04 sử dụng bản build cũ hơn, nơi tham số tương đương là listen 443 ssl http2;. Chạy nginx -t để biết bản build của bạn hỗ trợ tham số nào.
client_max_body_size và các thiết lập long read timeout giúp ngăn chặn việc upload file lớn bị ngắt giữa chừng. proxy_request_buffering off giúp stream dữ liệu upload thay vì phải spool toàn bộ file vào disk của proxy trước.
Sử dụng nginx trực tiếp trên host là cách đơn giản nhất cho một ứng dụng duy nhất. Nếu Nextcloud dùng chung VPS với các container khác, chạy Traefik như một Docker Compose reverse proxy cho nhiều ứng dụng sẽ chuyển việc routing và cấp phát chứng chỉ vào các container labels; khi đó, các vấn đề về client_max_body_size và timeout sẽ xuất hiện dưới dạng middleware và transport settings.
trusted_proxies và overwriteprotocol
Đây là nơi hầu hết các instance Nextcloud tự host gặp lỗi, và các triệu chứng trông có vẻ không liên quan đến nguyên nhân.
X-Forwarded-Proto: https chỉ được áp dụng khi request đến từ một địa chỉ có trong danh sách trusted_proxies. Khi không được áp dụng, Nextcloud tin rằng request là HTTP thuần túy và trả về các URL http://; proxy sẽ redirect các URL đó sang HTTPS; trình duyệt thực hiện theo; Nextcloud lại tiếp tục trả về http://. Đó chính là vòng lặp redirect. OVERWRITEPROTOCOL: https sẽ cố định scheme bất kể điều gì.
Bẫy trong TRUSTED_PROXIES là địa chỉ mà Nextcloud nhìn thấy không phải là 127.0.0.1. nginx chạy trên host và kết nối tới một port đã được publish, nên container sẽ nhìn thấy Docker bridge gateway — một thứ nằm trong 172.x. Hãy tìm subnet thực tế:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'Điền CIDR đó (hoặc 172.16.0.0/12 bao phủ nó) vào TRUSTED_PROXIES. Nếu thiết lập quá rộng, bất kỳ client nào cũng có thể giả mạo X-Forwarded-For; nếu thiết lập sai, mọi lượt login sẽ hiển thị là đến từ địa chỉ gateway, cơ chế brute-force protection sẽ chặn toàn bộ instance của bạn, và phần admin overview sẽ báo lỗi "The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy."
OVERWRITECLIURL rất quan trọng đối với cron container, vì container này không có request đi vào để suy luận hostname. Nếu không có nó, các tác vụ chạy ngầm sẽ tạo ra các link dẫn đến localhost và các thông báo email sẽ gửi đi các URL không thể sử dụng được.
Background jobs: cron, không phải AJAX
Trình chạy job mặc định của Nextcloud là AJAX: các job được thực thi như một hệ quả khi có người dùng tải một trang web. Không có ai duyệt web vào lúc 04:00, nên việc xóa rác, dọn dẹp các version, tạo preview và thử lại các kết nối federated sẽ bị đình trệ. Triệu chứng đầu tiên là thư mục dữ liệu (data directory) sẽ tăng dung lượng liên tục. Dịch vụ cron ở trên chạy vòng lặp /cron.sh chính thức trên cùng các volume đó. Hãy cấu hình để Nextcloud chờ lệnh này:
docker compose exec -u www-data app php occ background:cronMọi lệnh occ đều có cấu trúc: docker compose exec -u www-data app php occ <command>. Bạn nên thiết lập alias cho nó.
Backup: ba thành phần, hoặc không có gì
Chỉ backup filesystem sẽ không thể khôi phục được một instance đang lỗi. Thư mục data chứa các byte dữ liệu; Postgres giữ file cache, shares, users và app state; config.php giữ database credentials, instance ID và password salt. Nếu khôi phục file mà không có database, Nextcloud sẽ không thấy dữ liệu. Nếu khôi phục database mà không có config.php, database sẽ không thể mở được. Nếu khôi phục một database cũ vào một data directory mới hơn, các share sẽ trỏ vào những file đã bị di chuyển.
Hãy backup cả ba thành phần từ một instance đã được quiesced (ngừng mọi hoạt động ghi):
#!/usr/bin/env bash
set -euo pipefail
cd /srv/nextcloud
DEST="/var/backups/nextcloud/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$DEST"
occ() { docker compose exec -T -u www-data app php occ "$@"; }
occ maintenance:mode --on
trap 'occ maintenance:mode --off' EXIT
docker compose exec -T db \
pg_dump -U nextcloud --clean --if-exists nextcloud | gzip > "$DEST/db.sql.gz"
docker compose exec -T app \
tar -C /var/www/html -cf - config custom_apps themes > "$DEST/app.tar"
rsync -a --delete /srv/nextcloud/data/ /var/backups/nextcloud/data/Maintenance mode giúp đảm bảo bản dump và bản copy file đồng nhất với nhau. Nếu bỏ qua bước này, bạn sẽ gặp tình trạng database tham chiếu đến một file mà rsync chưa kịp copy tới. Lưu ý rằng script này giữ các bản dump database có timestamp nhưng chỉ giữ một bản mirror duy nhất cho data directory — rsync --delete sẽ overwrite nó sau mỗi lần chạy — vì vậy chỉ có bản dump mới nhất mới khớp với bản copy file.
Sau đó, hãy chuyển dữ liệu ra khỏi máy. Một bản backup nằm cùng một VPS với dữ liệu gốc thì chỉ được coi là bản copy, không phải backup. Giải pháp thông thường là dùng restic với object storage hoặc một host thứ hai; cơ chế deduplication của nó xử lý data directory tốt hơn nhiều so với việc dùng tarball hàng đêm. Toàn bộ thiết lập, từ khởi tạo repository đến timer hàng đêm và quy trình diễn tập khôi phục, nằm trong off-box VPS backups with restic.
Khôi phục không đơn giản là làm ngược lại quy trình backup. Một stack mới khởi chạy sẽ chạy installer và tạo ra một config.php mới — bao gồm instance ID và password salt mới — việc import bản dump đè lên identity mới này sẽ làm hỏng các session và share tokens. Hãy khôi phục identity cũ trước, theo thứ tự sau:
docker compose up -d && docker compose stop app cron # create the volumes, then halt the app
sudo rsync -a --delete /var/backups/nextcloud/data/ /srv/nextcloud/data/
docker compose run --rm -T --entrypoint "" app \
tar -C /var/www/html -xf - < app.tar # the original config.php returns
gunzip -c db.sql.gz | docker compose exec -T db psql -U nextcloud -d nextcloud
docker compose start app cron
docker compose exec -T -u www-data app php occ maintenance:mode --off
docker compose exec -T -u www-data app php occ files:scan --allfiles:scan giúp đồng bộ file cache với những gì thực tế đang có trên disk. Hãy diễn tập việc này một lần trên một VPS dự phòng trước khi bạn thực sự cần đến nó.
Nâng cấp: thực hiện từng phiên bản major một
Nextcloud chỉ hỗ trợ nâng cấp duy nhất một phiên bản major tại một thời điểm. Việc nhảy vọt từ 29 lên 31 sẽ không diễn ra suôn sẻ — nó sẽ lỗi với Exception: Updates between multiple major versions and downgrades are unsupported. và khiến hệ thống bị kẹt ở maintenance mode.
Quy trình nâng cấp Docker là: thực hiện backup, sửa tag từ 31 thành 32 trong cả hai service app và cron, sau đó chạy docker compose pull && docker compose up -d, rồi đến docker compose logs -f app. Image entrypoint sẽ tự động kiểm tra code mới so với dữ liệu hiện có và tự chạy occ upgrade. Đừng ngắt quãng quá trình này. Khi log ngừng chạy, hãy chạy docker compose exec -u www-data app php occ status để kiểm tra versionstring và đảm bảo các apps đã được enable trở lại.
Hai quy tắc giúp bạn tránh lỗi: nâng cấp một phiên bản major, kiểm tra kỹ, sau đó mới nâng cấp phiên bản tiếp theo. Và đừng bao giờ sửa tag trên service app mà không sửa cron cho tương ứng — dùng hai phiên bản Nextcloud khác nhau trên cùng một database sẽ gây lỗi corruption dữ liệu.
Các lỗi bạn sẽ thực sự gặp phải
"Your data directory is readable by other users. Please change the permissions to 0770." Thư mục bind-mount đang có quyền read cho group hoặc world. sudo chmod 0770 /srv/nextcloud/data và sudo chown -R 33:33 /srv/nextcloud/data.
"Your data directory is invalid. Ensure there is a file called .ocdata in the root." Bind mount đang trỏ vào một nơi mà Nextcloud chưa từng khởi tạo — có thể do viết sai đường dẫn, hoặc một thư mục trống mới được thay thế vào instance đang chạy. Hãy kiểm tra xem host path có khớp với dòng volume hay không.
"Access through untrusted domain." Hostname trong request không nằm trong danh sách trusted_domains. NEXTCLOUD_TRUSTED_DOMAINS chỉ áp dụng khi cài đặt lần đầu; sau đó hãy thiết lập live: occ config:system:set trusted_domains 1 --value=cloud.example.com.
502 Bad Gateway, kèm theo connect() failed (111: Connection refused) while connecting to upstream trong /var/log/nginx/error.log. nginx không kết nối được tới 127.0.0.1:8080. Có thể container đang trong quá trình khởi tạo (kiểm tra docker compose logs app), đã bị exit (docker compose ps), hoặc dòng publish không khớp với port proxy_pass. Hãy xác nhận bằng ss -ltnp | grep 8080.
Lỗi redirect loop, hoặc cảnh báo "insecure" trong admin overview. Thiếu OVERWRITEPROTOCOL: https, hoặc TRUSTED_PROXIES không chứa subnet của Docker gateway. Xem phần proxy ở trên.
LockedException: "files/..." is locked. Nếu đã thiết lập REDIS_HOST, image sẽ cấu hình Redis làm locking backend và các lỗi stale locks sẽ rất hiếm. Nếu không có nó, các lock sẽ nằm trong bảng database oc_file_locks và một request bị ngắt giữa chừng khi đang write sẽ để lại các hàng dữ liệu thừa. Hãy xác nhận Redis thực sự đang được sử dụng — occ config:system:get memcache.locking phải trả về Redis class — trước khi bạn tự tay xóa các hàng lock.
"The PHP memory limit is below the recommended value of 512MB." Hãy tăng PHP_MEMORY_LIMIT và recreate lại container. Hãy lưu ý giá trị này sẽ ảnh hưởng thế nào đến mức trần (ceiling) tối đa của bạn.
Những gì sẽ bị lỗi khi mở rộng quy mô
Rào cản đầu tiên là thư mục dữ liệu vượt quá dung lượng volume. Việc mở rộng volume trên một VPS đòi hỏi phải resize và grow filesystem; việc này sẽ khó xử hơn nhiều nếu để đĩa đầy 100% — hãy thiết lập cảnh báo (alert) về dung lượng đĩa ngay bây giờ, đừng đợi đến lúc đó.
Rào cản thứ hai là oc_filecache. Việc liệt kê file và quét đồng bộ (sync scans) sẽ chậm dần khi số lượng dòng tăng lên. Cách khắc phục là xử lý ở tầng database: giữ Postgres trên storage tốc độ cao, cấp đủ shared memory cho nó, và dọn dẹp các dữ liệu rác hoặc các phiên bản cũ bằng các thiết lập retention thay vì để chúng tích tụ vô hạn.
Rào cản thứ ba là việc tạo preview tranh chấp tài nguyên với các tác vụ khác. Trên một máy chủ nhỏ, hãy giới hạn các preview providers và đừng bao giờ chạy occ preview:generate-all trong giờ làm việc.
Ngoài những vấn đề đó, câu trả lời thực tế là các dịch vụ bổ sung cần máy riêng. Collabora và full-text search là các service chạy ngầm riêng biệt với profile bộ nhớ riêng; việc đặt chúng trên cùng một máy đang chứa bản sao duy nhất của các file sẽ làm tăng failure domain mà không mang lại lợi ích gì. Hãy chuyển file storage sang storage tương thích S3 khi volume không còn phù hợp — và lưu ý rằng việc này làm cho backup khó hơn chứ không dễ hơn: database vẫn giữ metadata, và nó phải được dump đồng bộ với bucket.
Khi instance đã phục vụ người dùng thực tế, hãy đặt Uptime Kuma ở phía trước để bạn biết về tình trạng downtime trước khi các sync clients phát hiện ra. Một private cloud sẽ hoạt động tốt khi kết hợp với mail server riêng, và nếu bạn không muốn tự tay kết nối các service, hãy so sánh các nền tảng như Cloudron, CasaOS và Coolify để họ làm việc đó cho bạn.
FAQ
Tôi có thể chạy Nextcloud bằng SQLite thay vì Postgres không?
Bạn có thể, và official image sẽ cho phép điều đó, nhưng một desktop sync client gửi nhiều request song song sẽ gây lỗi SQLSTATE[HY000]: General error: 5 database is locked và HTTP 500. SQLite khóa toàn bộ database khi ghi, trong khi Nextcloud ghi dữ liệu liên tục — từ file locks, các hàng activity đến job state. Hãy bắt đầu với Postgres hoặc MariaDB; occ db:convert-type có tồn tại nhưng đó là một quá trình migration dữ liệu live rất dài và không thể làm từng phần.
Một VPS chạy Nextcloud thực sự cần bao nhiêu RAM?
Hãy tính toán dựa trên số lượng request đồng thời, không phải số lượng user. Mức resident memory tối đa sẽ xấp xỉ bằng số lượng request đồng thời nhân với PHP_MEMORY_LIMIT, cộng với Postgres shared buffers, một backend cho mỗi connection, và lượng RAM tăng đột biến khi generate preview. Một VPS 2 GB có thể chạy instance cho hộ gia đình nhỏ nếu bạn giới hạn preview và thêm swap; nếu thêm Collabora hoặc full-text search, bạn sẽ cần tính toán thêm cho một tập hợp các resident services khác.
Tại sao upload file lớn bị lỗi khi chạy sau nginx reverse proxy?
Thường do hai thiết lập trên proxy: client_max_body_size để mặc định 1 MB sẽ làm ngắt request, và các giá trị proxy_read_timeout / proxy_send_timeout ngắn sẽ làm ngắt các quá trình truyền tải lâu giữa chừng. Hãy đặt cả hai ở mức dư dả, chuyển proxy_request_buffering off sang chế độ stream thay vì spool, và tăng PHP_UPLOAD_LIMIT trên app container cho tương ứng.
Tại sao Nextcloud bị redirect vòng lặp hoặc cảnh báo về reverse proxy?
Container không nhìn thấy nginx tại 127.0.0.1 — nó nhìn thấy Docker bridge gateway tại 172.x. Khi địa chỉ đó không có trong TRUSTED_PROXIES, header X-Forwarded-Proto: https sẽ bị bỏ qua, Nextcloud sẽ xuất ra các URL http://, và proxy sẽ đẩy ngược chúng lại. Hãy đặt TRUSTED_PROXIES thành subnet bridge thực tế và pin OVERWRITEPROTOCOL: https.
Tôi có thể nâng cấp Nextcloud từ 29 thẳng lên 31 không?
Không. Nextcloud chỉ hỗ trợ nâng cấp từng phiên bản major một, và việc nhảy cóc sẽ dừng lại ở Updates between multiple major versions and downgrades are unsupported., khiến instance rơi vào maintenance mode. Hãy backup, nâng tag lên một phiên bản major trên cả hai service app và cron, thực hiện docker compose pull && docker compose up -d, kiểm tra bằng occ status, rồi lặp lại quy trình.