VPS-এ Nextcloud সেটআপ করার নিয়ম
Docker Compose, Postgres এবং Redis ব্যবহার করে VPS-এ Nextcloud চালানোর সম্পূর্ণ নির্দেশিকা। এতে TLS এবং ডেটা ব্যাকআপ রাখার সঠিক পদ্ধতি দেওয়া হয়েছে।
আপনি আসলে কী তৈরি করছেন
এই নির্দেশিকাটি Docker Compose ব্যবহার করে একটি VPS-এ Nextcloud চালাবে, এর সামনে Let's Encrypt TLS সেটআপ করবে এবং একটি কার্যকর ব্যাকআপ সিস্টেম তৈরি করবে। এখানে চারটি container এবং একটি proxy ব্যবহার করা হবে: loopback-এ শুনছে এমন অফিসিয়াল nextcloud image, ফাইল মেটাডেটা সংরক্ষণের জন্য Postgres, ফাইল lock সংরক্ষণের জন্য Redis, শুধুমাত্র cron loop চালানোর জন্য Nextcloud image-এর একটি দ্বিতীয় কপি, এবং হোস্টের nginx যা সবকিছুর সামনে TLS terminate করবে। ইনস্টলেশন সম্পন্ন করতে ২০ মিনিট সময় লাগে, তবে এটি সবচেয়ে গুরুত্বপূর্ণ অংশ নয়। প্রথম এক ঘণ্টার মধ্যে নেওয়া দুটি সিদ্ধান্ত নির্ধারণ করবে এক বছর পর আপনার ফাইলগুলো থাকবে কি না: SQLite-এর পরিবর্তে একটি প্রকৃত database ব্যবহার করা, এবং data directory, database এবং config.php-কে একটি সুসংগত সেট হিসেবে ব্যাকআপ নেওয়া।
এর জন্য Ubuntu 24.04 LTS বা Debian 13, Docker-এর নিজস্ব repository থেকে ইনস্টল করা Docker Engine (Compose v2 plugin সহ), এবং একটি DNS A record (IPv6 থাকলে AAAA সহ) যা ইতিমধ্যে VPS-কে cloud.example.com হিসেবে নির্দেশ করছে প্রয়োজন। এই সবকিছুর জন্য আপনার নিয়ন্ত্রণে থাকা একটি সার্ভার প্রয়োজন — অন্য কোনো SaaS প্ল্যাটফর্মে TLS termination এবং database dump করার কোনো উপায় নেই।
Sizing: প্রকৃতপক্ষে যা মেমরি খরচ করে
Nextcloud-এর মেমরি ব্যবহারের প্রধানত তিনটি কারণ রয়েছে, এবং এর মধ্যে কোনোটিই সরাসরি "Nextcloud" নয়।
PHP workers. -apache ইমেজটি প্রতিটি সমসাময়িক (concurrent) রিকোয়েস্ট একটি worker process-এর মাধ্যমে সার্ভ করে, যেখানে একটি PHP interpreter থাকে। PHP রিকোয়েস্টটি বন্ধ করার আগে প্রতিটি worker PHP_MEMORY_LIMIT পর্যন্ত মেমরি নিতে পারে। আপনার সর্বোচ্চ resident memory হলো মোটামুটি concurrent requests × the memory limit, এবং একটি desktop sync client প্রতিটি ইউজারের জন্য বেশ কিছু parallel connection ওপেন করে। ইউজার সংখ্যা নয়, বরং concurrency মেমরির সীমা নির্ধারণ করে।
The database. Postgres প্রতিটি connection-এর জন্য একটি backend fork করে এবং shared buffers গুলো resident হিসেবে রাখে। এর working set ফাইলের সংখ্যার ওপর নির্ভর করে, বাইটের ওপর নয়: oc_filecache প্রতিটি ইউজারের প্রতিটি ফাইলের জন্য একটি করে row রাখে। এক লক্ষ ছোট ফাইল রাখা একশটি বড় ফাইলের চেয়ে ডাটাবেসকে বেশি ভারাক্রান্ত করে।
Preview generation. একটি thumbnail তৈরি করার সময় সোর্স ইমেজটিকে তার full resolution-এ মেমরিতে decode করা হয়। Video preview-এর জন্য ffmpeg ব্যবহার করা হয়। occ preview:generate-all চালালে এই মেমরি স্পাইক বারবার এবং পরপর ঘটে, যা একটি ছোট VPS-কে OOM killer-এর কবলে ফেলে দেওয়ার সবচেয়ে সাধারণ কারণ।
Redis তুলনামূলকভাবে কম মেমরি খরচ করে। পরবর্তীতে আপনি যা কিছু যুক্ত করবেন — যেমন Collabora, full-text search, বা একটি antivirus scanner — সেগুলো আলাদা resident service হিসেবে কাজ করে এবং সেগুলোর নিজস্ব মেমরি footprint আছে। এগুলো চালু করার আগেই আপনার sizing plan-এ অন্তর্ভুক্ত করা উচিত।
যদি আপনার RAM কম থাকে, তবে এই পদক্ষেপগুলো নিন: PHP_MEMORY_LIMIT কমিয়ে দিন, preview_max_x / preview_max_y / preview_max_filesize_image এর সীমা নির্ধারণ করুন, enabledPreviewProviders শুধুমাত্র প্রয়োজনীয় ফরম্যাটের জন্য সীমিত করুন, এবং trashbin_retention_obligation ও versions_retention_obligation এমনভাবে সেট করুন যাতে data directory ফাইল সাইজের তুলনায় অনেক বেশি বড় না হয়ে যায়। একটি swap file যোগ করুন। Swap ধীরগতির, কিন্তু আপগ্রেড চলাকালীন OOM kill হওয়া আরও ভয়াবহ।
কেন SQLite কাজ করে না
Nextcloud-এ SQLite সাপোর্ট থাকে এবং অফিসিয়াল ইমেজটি এটি ব্যবহার করতে পারে। তবে তা করবেন না। SQLite পুরো ডাটাবেস জুড়ে একটি লক ব্যবহার করে রাইট অপারেশন সম্পন্ন করে: পুরো ফাইলের জন্য একবারে মাত্র একজন রাইটার কাজ করতে পারেন। Nextcloud প্রতিনিয়ত রাইট অপারেশন চালায় — যেমন file locks, activity rows, cache entries এবং job state। এছাড়া একটি ডেস্কটপ ক্লায়েন্ট যখন কোনো ডিরেক্টরি ট্রি সিঙ্ক করে, তখন অনেকগুলো প্যারালাল রিকোয়েস্ট তৈরি হয়। এই ধরনের পরিস্থিতিতে আপনি SQLSTATE[HY000]: General error: 5 database is locked এবং HTTP 500 এরর পাবেন। যখন আপনার ইন্সট্যান্সটি ব্যবহার উপযোগী হতে শুরু করে, ঠিক তখনই এই সমস্যাটি দেখা দেয়।
পরবর্তীতে occ db:convert-type ব্যবহার করে কনভার্ট করা সম্ভব, কিন্তু লাইভ ডাটাবেসের ক্ষেত্রে এটি একটি দীর্ঘ এবং জটিল মাইগ্রেশন প্রক্রিয়া। শুরু থেকেই Postgres বা MariaDB ব্যবহার করুন।
The Compose file
এটি /srv/nextcloud/compose.yaml-এ রাখুন, এবং mode 600-এ একটি sibling .env ফাইলে secrets গুলো রাখুন।
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:31 সরাসরি কপি করার আগে major tag ফিক্স করে নিন এবং Docker Hub-এ বর্তমান tag টি যাচাই করে নিন। ভবিষ্যতে কোনো docker compose pull-এ latest আপনাকে একটি major boundary অতিক্রম করতে বাধ্য করতে পারে, যা Nextcloud সমর্থন করে না।
Data directory টি ইচ্ছাকৃতভাবে একটি bind mount হিসেবে রাখা হয়েছে, named volume হিসেবে নয়: সরাসরি backup tool দিয়ে পয়েন্ট করা যায় এমন একটি path গুছিয়ে রাখার চেয়ে বেশি মূল্যবান। এটি image-এর www-data UID এবং Nextcloud-এর প্রয়োজনীয় permissions দিয়ে তৈরি করুন:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataPort publish-এর দিকে লক্ষ্য করুন: 127.0.0.1:8080:80। Docker মূলত DNAT rules লিখে port publish করে, যা ufw-এর INPUT chain packet দেখার আগেই কার্যকর হয় — তাই একটি সাধারণ 8080:80 ব্যবহার করলে ufw যা-ই বলুক না কেন, Nextcloud পাবলিক ইন্টারনেটে unencrypted অবস্থায় চলে আসবে। Loopback-এ bind করে রাখলে এটি পাবলিক interface থেকে দূরে থাকে। এরপর firewall-কে শুধুমাত্র proxy-কে allow করলেই চলে — এবং আপনি যদি SSH পুরো ইন্টারনেটের জন্য খোলা রাখতে না চান, তবে self-hosted WireGuard VPN ব্যবহার করে VPS-এ প্রবেশ করা আপনাকে পাবলিক rules থেকে port 22 সম্পূর্ণভাবে বাদ দিতে সাহায্য করবে:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enabledocker compose up -d দিয়ে এটি চালু করুন, তারপর docker compose logs -f app পর্যবেক্ষণ করুন। প্রথম boot-এ পুরো application tree ভলিউমে কপি হয় এবং installer চলে; সেই প্রক্রিয়া শেষ না হওয়া পর্যন্ত container কোনো রেসপন্স দেবে না।
TLS এবং reverse proxy
distro থেকে nginx এবং certbot install করুন। সঠিক server_name সহ একটি সাধারণ port-80 server block তৈরি করুন, তারপর certbot দিয়ে সেটি rewrite করতে দিন। HTTP-01 challenge-এর কার্যপদ্ধতি, renewal timer এবং failure modes সম্পর্কে বিস্তারিত জানতে issuing Let's Encrypt certificates with certbot and nginx on Ubuntu 24.04 দেখুন:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comCertbot ssl_certificate লাইন এবং :80 → :443 redirect যোগ করে। এটি একটি systemd timer install করে যা 90-day certificate renew করে। systemctl list-timers | grep certbot দিয়ে এটি নিশ্চিত করুন — যদি renewal timer enable করা না থাকে, তবে 90-day certificateটি মেয়াদ শেষ হওয়ার ঝুঁকি তৈরি করে।
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;
}
}nginx 1.25 বা তার পরবর্তী ভার্সনের জন্য http2 on; যোগ করুন। Ubuntu 24.04-এ একটি পুরনো build থাকে যেখানে এর সমতুল্য হলো listen 443 ssl http2;। আপনার build কোনটি গ্রহণ করবে তা nginx -t দিয়ে জানবেন।
client_max_body_size এবং দীর্ঘ read timeouts বড় ফাইল upload মাঝপথে বন্ধ হওয়া রোধ করে। proxy_request_buffering off পুরো ফাইলটি প্রথমে proxy-র disk-এ spool করার পরিবর্তে সরাসরি stream করে।
একটি single app-এর জন্য host-এ nginx ব্যবহার করা সবচেয়ে সহজ পদ্ধতি। যদি Nextcloud অন্য container-এর সাথে VPS শেয়ার করে, তবে running Traefik as a Docker Compose reverse proxy for multiple apps ব্যবহার করুন। এটি routing এবং certificate issuance-কে container labels-এ নিয়ে যায়। সেখানেও client_max_body_size এবং timeout সংক্রান্ত বিষয়গুলো middleware এবং transport settings হিসেবে প্রয়োজন হয়।
trusted_proxies এবং overwriteprotocol
বেশিরভাগ self-hosted Nextcloud ইনস্টলেশনে এখানেই ভুলটি ঘটে, এবং এর লক্ষণগুলো মূল কারণের সাথে সম্পর্কহীন মনে হতে পারে।
X-Forwarded-Proto: https শুধুমাত্র তখনই কার্যকর হয় যখন রিকোয়েস্টটি trusted_proxies-এ তালিকাভুক্ত কোনো অ্যাড্রেস থেকে আসে। যখন এটি কার্যকর হয় না, Nextcloud মনে করে রিকোয়েস্টটি plain HTTP এবং এটি http:// URL প্রদান করে; প্রক্সি সেগুলোকে HTTPS-এ রিডাইরেক্ট করে; ব্রাউজার তা অনুসরণ করে; এবং Nextcloud পুনরায় http:// প্রদান করে। এটিই হলো redirect loop। OVERWRITEPROTOCOL: https যেকোনো ক্ষেত্রে scheme নির্দিষ্ট করে দেয়।
TRUSTED_PROXIES-এর সমস্যা হলো Nextcloud যে অ্যাড্রেসটি দেখে তা 127.0.0.1 নয়। nginx হোস্টের ওপর চলে এবং একটি published port-এর সাথে কানেক্ট করে, তাই কন্টেইনারটি Docker bridge gateway দেখতে পায় — যা 172.x-এর অন্তর্ভুক্ত। সঠিক subnet খুঁজে বের করুন:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'সেই CIDR (অথবা এর অন্তর্ভুক্ত 172.16.0.0/12) TRUSTED_PROXIES-এ লিখুন। এটি খুব বেশি বিস্তৃত (wide) সেট করলে যেকোনো ক্লায়েন্ট X-Forwarded-For স্পুফ করতে পারে; ভুলভাবে সেট করলে প্রতিটি লগইন গেটওয়ে অ্যাড্রেস থেকে আসছে বলে মনে হবে, ফলে brute-force protection আপনার পুরো ইনস্ট্যান্সটিকে একসাথে ব্লক করে দেবে, এবং admin overview-তে "The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy." দেখাবে।
cron কন্টেইনারের জন্য OVERWRITECLIURL গুরুত্বপূর্ণ, কারণ এর কাছে hostname অনুমিত করার মতো কোনো ইনকামিং রিকোয়েস্ট থাকে না। এটি ছাড়া, background jobs গুলো localhost-এর লিঙ্ক তৈরি করে এবং ইমেল নোটিফিকেশনগুলো অব্যবহারযোগ্য URL পাঠায়।
Background jobs: cron, AJAX নয়
Nextcloud-এর ডিফল্ট job runner হলো AJAX: কেউ কোনো page load করলে কাজগুলো সম্পন্ন হয়। রাত 04:00 মিনিটে কেউ ব্রাউজ করে না, তাই trash expiry, versions cleanup, previews এবং federated retries আটকে যায়। এর প্রথম লক্ষণ হলো data directory ক্রমাগত বড় হতে থাকে। উপরের cron service একই volumes-এর বিপরীতে অফিসিয়াল /cron.sh loop চালায়। Nextcloud-কে এটি ব্যবহারের জন্য নির্দেশ দিন:
docker compose exec -u www-data app php occ background:cronপ্রতিটি occ command এই ফরম্যাট অনুসরণ করে: docker compose exec -u www-data app php occ <command>। এটি alias হিসেবে সেট করে রাখা সুবিধাজনক।
Backups: তিনটি বিষয়, অথবা কিছুই নয়
শুধুমাত্র filesystem backup করলে একটি ক্ষতিগ্রস্ত instance পুনরুদ্ধার করা সম্ভব নয়। data directory-তে ডেটা থাকে; Postgres ফাইল cache, shares, users এবং app state সংরক্ষণ করে; config.php ডেটাবেস credentials, instance ID এবং password salt সংরক্ষণ করে। ডেটাবেস ছাড়া ফাইলগুলো restore করলে Nextcloud সেগুলো খুঁজে পাবে না। config.php ছাড়া ডেটাবেস restore করলে এটি ডেটাবেসটি খুলতে পারবে না। নতুন data directory-তে পুরনো ডেটাবেস restore করলে এমন সব share পাওয়া যাবে যা এমন ফাইল নির্দেশ করে যা স্থানান্তরিত হয়েছে।
একটি quiesced instance থেকে এই তিনটি বিষয়ই backup করুন:
#!/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 নিশ্চিত করে যে dump এবং file copy একে অপরের সাথে সামঞ্জস্যপূর্ণ। এটি বাদ দিলে আপনি এমন একটি ডেটাবেস পাবেন যা এমন একটি ফাইলকে নির্দেশ করছে যা rsync তখনও কপি করতে পারেনি। মনে রাখবেন, এই script ডেটাবেস dump গুলো timestamp সহ সংরক্ষণ করে কিন্তু data directory-র জন্য মাত্র একটি rolling mirror রাখে — rsync --delete প্রতিটি run-এ এটি overwrite করে — তাই শুধুমাত্র নতুনতম dump-টি file copy-র সাথে সামঞ্জস্যপূর্ণ হবে।
এরপর ব্যাকআপটি সার্ভার থেকে সরিয়ে ফেলুন। যে VPS-এ মূল সিস্টেমটি আছে সেখানেই ব্যাকআপ রাখা মানে সেটি কেবল একটি copy, backup নয়। object storage অথবা দ্বিতীয় কোনো host-এ restic ব্যবহার করা হলো সাধারণ সমাধান, এবং এর deduplication পদ্ধতি nightly tarball-এর চেয়ে data directory-র ক্ষেত্রে অনেক ভালো কাজ করে। repository init থেকে শুরু করে nightly timer এবং restore drill পর্যন্ত সম্পূর্ণ setup সম্পর্কে off-box VPS backups with restic দেখুন।
Restore করা মানে কেবল উল্টো প্রক্রিয়া অনুসরণ করা নয়। একটি নতুনভাবে শুরু করা stack installer চালায় এবং একটি সম্পূর্ণ নতুন config.php — একটি নতুন instance ID এবং password salt — তৈরি করে। সেই নতুন identity-র ওপর dump ইমপোর্ট করলে session এবং share token নষ্ট হয়ে যায়। প্রথমে পুরনো identity ফিরিয়ে আনুন, এই ক্রমে:
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 ফাইল cache এবং ডিস্কে থাকা প্রকৃত ফাইলের মধ্যে সামঞ্জস্য বজায় রাখে। প্রয়োজন হওয়ার আগেই একটি spare VPS-এ এটি একবার অনুশীলন করে নিন।
Upgrades: একবারে একটি major version
Nextcloud একবারে শুধুমাত্র একটি major version upgrade সমর্থন করে। 29 থেকে সরাসরি 31-এ আপডেট করলে তা সফলভাবে সম্পন্ন হয় না — এটি Exception: Updates between multiple major versions and downgrades are unsupported. এর মাধ্যমে ব্যর্থ হয় এবং আপনাকে maintenance mode-এ ফেলে রাখে।
Docker upgrade করার নিয়ম হলো: একটি backup নিন, app এবং cron উভয় service-এ tag পরিবর্তন করে 31 থেকে 32 করুন, তারপর docker compose pull && docker compose up -d করুন, এবং তারপর docker compose logs -f app করুন। image entrypoint বিদ্যমান data-এর বিপরীতে নতুন code শনাক্ত করে এবং নিজে থেকেই occ upgrade রান করে। এটি মাঝপথে থামাবেন না। যখন logs আসা বন্ধ হয়ে যাবে, তখন docker compose exec -u www-data app php occ status রান করুন এবং versionstring এবং apps গুলো পুনরায় enabled হয়েছে কিনা তা পরীক্ষা করুন।
আপনার কাজের সুবিধার্থে দুটি নিয়ম: প্রথমে একটি major version আপডেট করুন, সেটি যাচাই করুন, তারপর পরবর্তীটি আপডেট করুন। এবং cron পরিবর্তন না করে কখনোই app service-এর tag পরিবর্তন করবেন না — একটি database-এর বিপরীতে দুটি ভিন্ন Nextcloud version ব্যবহার করা ডেটা corruption করার কারণ হতে পারে।
আপনি আসলে যে error গুলো দেখতে পাবেন
"Your data directory is readable by other users. Please change the permissions to 0770." bind-mounted directory-টিতে group বা world read bits আছে। sudo chmod 0770 /srv/nextcloud/data এবং 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 এমন কোনো জায়গায় পয়েন্ট করছে যা Nextcloud কখনো initialize করেনি — পাথে typo আছে, অথবা একটি সচল instance-এর নিচে একটি নতুন খালি directory পরিবর্তন করা হয়েছে। নিশ্চিত করুন যে host path এবং volume line মিলে যাচ্ছে।
"Access through untrusted domain." রিকোয়েস্টের hostname trusted_domains-এ নেই। NEXTCLOUD_TRUSTED_DOMAINS শুধুমাত্র প্রথম install করার সময় প্রযোজ্য; পরবর্তীতে এটি live সেট করুন: occ config:system:set trusted_domains 1 --value=cloud.example.com।
502 Bad Gateway, যেখানে /var/log/nginx/error.log-এ connect() failed (111: Connection refused) while connecting to upstream আছে। nginx, 127.0.0.1:8080-এ কোনো রেসপন্স পায়নি। হয় container টি এখনও initialising অবস্থায় আছে (docker compose logs app চেক করুন), অথবা এটি exit করেছে (docker compose ps), অথবা publish line এবং proxy_pass port মিলে যাচ্ছে না। ss -ltnp | grep 8080 দিয়ে নিশ্চিত করুন।
A redirect loop, অথবা admin overview-এ "insecure" warning। OVERWRITEPROTOCOL: https নেই, অথবা TRUSTED_PROXIES-এ Docker gateway subnet নেই। উপরের proxy section দেখুন।
LockedException: "files/..." is locked। REDIS_HOST সেট করা থাকলে, image টি Redis-কে locking backend হিসেবে কনফিগার করে এবং stale locks খুব কম দেখা যায়। এটি ছাড়া, locks গুলো oc_file_locks ডাটাবেস টেবিলে থাকে এবং রাইট করার মাঝখানে কোনো রিকোয়েস্ট বন্ধ হয়ে গেলে rows থেকে যায়। ম্যানুয়ালি lock rows ডিলিট করার আগে নিশ্চিত করুন যে Redis আসলে ব্যবহৃত হচ্ছে — occ config:system:get memcache.locking দিলে Redis class রিটার্ন করা উচিত।
"The PHP memory limit is below the recommended value of 512MB." PHP_MEMORY_LIMIT বৃদ্ধি করুন এবং container টি পুনরায় তৈরি করুন। মনে রাখবেন এটি আপনার worst-case ceiling-এর ওপর কী প্রভাব ফেলে।
স্কেল করার সময় যা সমস্যা তৈরি করে
প্রথম বাধা হলো ডেটা ডিরেক্টরি যখন ভলিউমের চেয়ে বড় হয়ে যায়। VPS-এ ভলিউম বাড়ানো মানে হলো resize এবং filesystem grow করা; ডিস্ক ১০০% পূর্ণ হওয়ার পর এটি করা অনেক বেশি কঠিন। তাই ডিস্ক ব্যবহারের ওপর এখনই alert সেট করুন, পরে নয়।
দ্বিতীয় বাধা হলো oc_filecache। রো (row) সংখ্যা বাড়লে ফাইল লিস্ট করা এবং sync scan ধীর হয়ে যায়। এর সমাধান হলো ডেটাবেস নিয়ে কাজ করা: Postgres-কে দ্রুত স্টোরেজে রাখুন, একে পর্যাপ্ত shared memory ব্যবহার করতে দিন, এবং অপ্রয়োজনীয় ডেটা ও ভার্সনগুলো জমা হতে না দিয়ে retention settings ব্যবহার করে prune করুন।
তৃতীয় বাধা হলো preview generation যা অন্যান্য কাজের সাথে প্রতিযোগিতা করে। ছোট সার্ভারের ক্ষেত্রে, preview provider সীমিত রাখুন এবং কাজের সময়ের মধ্যে কখনো occ preview:generate-all চালাবেন না।
এর বাইরে আসল কথা হলো, অতিরিক্ত ফিচারগুলোর জন্য আলাদা মেশিন প্রয়োজন। Collabora এবং full-text search হলো আলাদা resident services যেগুলোর নিজস্ব memory profile আছে। আপনার ফাইলের একমাত্র কপি যে সার্ভারে আছে, সেখানেই এগুলো রাখা মানে কোনো লাভ ছাড়াই failure domain বাড়িয়ে দেওয়া। যখন ভলিউম আর উপযুক্ত থাকে না, তখন ফাইল স্টোরেজ S3-compatible primary storage-এ সরিয়ে নিন — মনে রাখবেন, এটি ব্যাকআপ করা কঠিন করে তোলে, সহজ নয়: ডেটাবেস এখনও metadata ধারণ করে এবং bucket-এর সাথে সামঞ্জস্য রেখে এটিকে dump করতে হয়।
যখন instance-টি প্রকৃত ব্যবহারকারীদের সার্ভিস দিতে শুরু করবে, তখন এর সামনে Uptime Kuma ব্যবহার করুন যাতে sync client-এর আগে আপনি ডাউনটাইম সম্পর্কে জানতে পারেন। একটি প্রাইভেট ক্লাউড আপনার নিজস্ব mail server-এর সাথে ভালো কাজ করে। আর আপনি যদি সার্ভিসগুলো ম্যানুয়ালি কানেক্ট করতে না চান, তবে Cloudron, CasaOS and Coolify প্ল্যাটফর্মগুলো তুলনা করে দেখতে পারেন যা এই কাজটি আপনার হয়ে করে দেয়।
FAQ
আমি কি Postgres এর পরিবর্তে SQLite ব্যবহার করে Nextcloud চালাতে পারি?
আপনি পারবেন এবং অফিসিয়াল ইমেজটি সেটি করার অনুমতি দেবে, কিন্তু একটি সিঙ্গেল ডেস্কটপ sync client যদি প্যারালাল রিকোয়েস্ট পাঠায়, তবে সেটি SQLSTATE[HY000]: General error: 5 database is locked এবং HTTP 500 এর সম্মুখীন হবে। SQLite পুরো ডাটাবেস জুড়ে একটি write lock নিয়ে নেয়, আর Nextcloud প্রতিনিয়ত রাইট অপারেশন চালায় — যেমন file locks, activity rows, এবং job state। Postgres বা MariaDB দিয়ে শুরু করা ভালো; occ db:convert-type বিদ্যমান আছে কিন্তু লাইভ ডাটা মাইগ্রেট করা একটি দীর্ঘ এবং জটিল প্রক্রিয়া।
Nextcloud VPS এর জন্য আসলে কতটুকু RAM প্রয়োজন?
এটি ইউজার সংখ্যার ওপর নয়, বরং concurrency বা সমসাময়িক রিকোয়েস্টের ওপর নির্ভর করে। সবচেয়ে খারাপ পরিস্থিতিতে প্রয়োজনীয় resident memory হলো সমসাময়িক রিকোয়েস্টের সংখ্যা গুণিতক PHP_MEMORY_LIMIT, সাথে Postgres shared buffers এবং প্রতিটি কানেকশনের জন্য একটি করে backend, এবং preview generation এর কারণে সৃষ্ট স্পাইক। আপনি যদি preview লিমিট করেন এবং swap যোগ করেন, তবে একটি 2 GB বক্স দিয়ে ছোট একটি পরিবারের জন্য instance চালানো সম্ভব; তবে Collabora বা full-text search যোগ করলে আপনাকে আরও অতিরিক্ত resident services এর জন্য জায়গা রাখতে হবে।
nginx reverse proxy এর পেছনে বড় ফাইল আপলোড কেন ব্যর্থ হয়?
সাধারণত প্রক্সি-র দুটি সেটিংস এর কারণ হিসেবে কাজ করে: client_max_body_size যদি ডিফল্ট 1 MB এ থাকে তবে রিকোয়েস্টটি কেটে যাবে, এবং ছোট proxy_read_timeout / proxy_send_timeout ভ্যালু দীর্ঘ ট্রান্সফার মাঝপথে থামিয়ে দেয়। উভয়টি পর্যাপ্ত পরিমাণে সেট করুন, proxy_request_buffering off কে spool এর পরিবর্তে stream হিসেবে সেট করুন, এবং অ্যাপ কন্টেইনারে PHP_UPLOAD_LIMIT এর মান বাড়িয়ে নিন।
Nextcloud কেন redirect loop তৈরি করে বা reverse proxy সম্পর্কে সতর্কবার্তা দেয়?
কন্টেইনারটি 127.0.0.1 এ nginx কে দেখতে পায় না — এটি Docker bridge gateway কে দেখে, যা 172.x এর আশেপাশে থাকে। যখন TRUSTED_PROXIES থেকে সেই অ্যাড্রেসটি বাদ পড়ে যায়, তখন X-Forwarded-Proto: https হেডারটি উপেক্ষা করা হয়, Nextcloud http:// URL জেনারেট করে এবং প্রক্সি সেগুলো পুনরায় ফেরত পাঠায়। TRUSTED_PROXIES কে আসল bridge subnet এ সেট করুন এবং OVERWRITEPROTOCOL: https ফিক্সড করুন।
আমি কি Nextcloud সরাসরি 29 থেকে 31 ভার্সনে আপগ্রেড করতে পারি?
না। Nextcloud প্রতিটি আপগ্রেডে মাত্র একটি মেজর ভার্সন সাপোর্ট করে। ভার্সন স্কিপ করলে তা Updates between multiple major versions and downgrades are unsupported. এ এসে থেমে যাবে এবং instance টি maintenance mode এ চলে যাবে। ব্যাকআপ নিন, app এবং cron উভয় সার্ভিসের ট্যাগ এক ধাপ করে বাড়ান, docker compose pull && docker compose up -d করুন, occ status দিয়ে যাচাই করুন, এবং তারপর পুনরায় প্রক্রিয়াটি অনুসরণ করুন।