كيفية تثبيت Nextcloud على VPS باستخدام Docker
تعلم كيفية تشغيل Nextcloud على خادم VPS باستخدام Docker Compose مع Postgres وRedis. يوفر هذا الدليل خطوات إعداد TLS وتأمين النسخ الاحتياطية لضمان استعادة بياناتك بشكل كامل.
ما الذي تبنيه فعلياً
يرشدك هذا الدليل إلى تشغيل Nextcloud على خادم VPS باستخدام Docker Compose، مع وضع طبقة TLS من Let's Encrypt أمامها، وإعداد نسخة احتياطية قابلة للاستعادة فعلياً. يتكون الإعداد من أربع حاويات ووكيل (proxy): صورة nextcloud الرسمية التي تستمع على واجهة loopback، وقاعدة بيانات Postgres التي تحفظ كل بيانات الملفات الوصفية، وRedis لإدارة أقفال الملفات، ونسخة ثانية من صورة Nextcloud تعمل فقط لتنفيذ حلقة cron، بالإضافة إلى nginx على المضيف الذي ينهي اتصال TLS أمام كل هذه المكونات. يستغرق التثبيت نفسه عشرين دقيقة، وهو ليس الجزء الأهم. هناك قراران تتخذهما في الساعة الأولى يحددان ما إذا كانت ملفاتك ستظل موجودة بعد عام: استخدام قاعدة بيانات حقيقية بدلاً من SQLite، وإعداد نسخة احتياطية تلتقط دليل البيانات وقاعدة البيانات وconfig.php كمجموعة متسقة واحدة.
يفترض هذا الدليل استخدام Ubuntu 24.04 LTS أو Debian 13، مع تثبيت Docker Engine وإضافة Compose v2 من مستودع Docker الرسمي، ووجود سجل DNS من نوع A (بالإضافة إلى AAAA إذا كنت تستخدم IPv6) يشير بالفعل إلى cloud.example.com الخاص بخادم الـVPS. يتطلب كل هذا خادماً تتحكم فيه بالكامل، إذ لا توجد طريقة لإجراء إنهاء TLS وتفريغ قاعدة البيانات (dump) على خدمة SaaS تابعة لطرف آخر.
تحديد الحجم: ما الذي يستهلك الذاكرة فعلياً
يهيمن على استهلاك الذاكرة في Nextcloud ثلاثة عوامل، ولا يُعد أي منها "Nextcloud" بحد ذاته.
عمال PHP (PHP workers). تخدم صورة -apache كل طلب متزامن من خلال عملية عاملة (worker process) تحتوي على مفسر PHP. قد ينمو كل عامل ليصل إلى PHP_MEMORY_LIMIT قبل أن ينهي PHP الطلب. في أسوأ الحالات، تكون الذاكرة المقيمة (resident memory) المطلوبة هي تقريباً عدد الطلبات المتزامنة × حد الذاكرة، علماً بأن عميل المزامنة المكتبي يفتح عدة اتصالات متوازية لكل مستخدم. التزامن، وليس عدد المستخدمين، هو ما يحدد السقف الأعلى.
قاعدة البيانات. يقوم Postgres بإنشاء عملية خلفية (fork) لكل اتصال ويحتفظ بالمخازن المؤقتة المشتركة في الذاكرة. يتناسب حجم مجموعة العمل (working set) مع عدد الملفات، وليس عدد البايتات: يحتوي oc_filecache على صف واحد لكل ملف لكل مستخدم. مئة ألف ملف صغير تشكل عبئاً على قاعدة البيانات أكبر من مئة ملف كبير.
توليد المعاينات (Preview generation). عند توليد صورة مصغرة، يتم فك ترميز الصورة المصدر في الذاكرة بكامل دقتها. تستدعي معاينات الفيديو أداة ffmpeg. يؤدي تشغيل occ preview:generate-all إلى تكرار هذا الارتفاع في استهلاك الذاكرة بشكل متتالٍ، وهو السبب الأكثر شيوعاً لدفع خادم VPS صغير إلى الوقوع تحت رحمة OOM killer.
يُعد Redis غير مكلف نسبياً من حيث الموارد. أي إضافات تقوم بتثبيتها لاحقاً، مثل Collabora أو البحث النصي الكامل أو ماسح الفيروسات، هي خدمات منفصلة ومقيمة في الذاكرة ولها بصمتها الخاصة، لذا يجب إدراجها في خطة تحديد الحجم قبل تفعيلها.
إذا كنت تعاني من محدودية في ذاكرة الوصول العشوائي (RAM)، فاستخدم هذه الأدوات للتحكم: قلل PHP_MEMORY_LIMIT، وحدد سقفاً لـ preview_max_x / preview_max_y / preview_max_filesize_image، وقلص enabledPreviewProviders لتقتصر على التنسيقات التي تتصفحها فعلياً، واضبط trashbin_retention_obligation و versions_retention_obligation حتى لا ينمو دليل البيانات بصمت ليصل إلى عدة أضعاف حجم ملفاتك. أضف ملف تبديل (swap file). التبديل بطيء، لكن إنهاء العملية بواسطة OOM killer في منتصف عملية الترقية أسوأ بكثير.
لماذا تتعطل قاعدة بيانات SQLite
يأتي Nextcloud مع دعم لـ SQLite، وستستخدمه الصورة الرسمية بسعادة. لا تفعل ذلك. تقوم SQLite بتسلسل عمليات الكتابة باستخدام قفل على مستوى قاعدة البيانات بالكامل: كاتب واحد في كل مرة، للملف بأكمله. يكتب Nextcloud باستمرار، مثل أقفال الملفات، وسجلات النشاط، ومدخلات التخزين المؤقت، وحالة المهام، كما يرسل عميل سطح المكتب عند مزامنة شجرة ملفات العديد من الطلبات المتوازية. في ظل هذا النمط، ستحصل على SQLSTATE[HY000]: General error: 5 database is locked وأخطاء HTTP 500، ويظهر الفشل تماماً عندما تبدأ النسخة في أن تكون مفيدة.
التحويل لاحقاً ممكن باستخدام occ db:convert-type، لكنها عملية ترحيل طويلة وشاملة (إما النجاح أو الفشل) على مجموعة بيانات حية. ابدأ باستخدام Postgres أو MariaDB.
ملف Compose
ضع هذا في /srv/nextcloud/compose.yaml، مع وضع الأسرار في ملف .env مجاور بصلاحيات 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:ثبّت الإصدار الرئيسي (major tag) وتحقق من الإصدار الحالي على Docker Hub قبل نسخ 31 حرفياً. سيؤدي استخدام latest إلى نقلك عبر حدود إصدار رئيسي في أي docker compose pull مستقبلي، وNextcloud لا يدعم ذلك.
دليل البيانات هو bind mount وليس named volume، وهذا مقصود: المسار الذي يمكنك توجيه أداة النسخ الاحتياطي إليه مباشرة أكثر قيمة من الترتيب. أنشئه باستخدام معرف المستخدم (UID) الخاص بـ www-data في الصورة وبالصلاحيات التي يتطلبها Nextcloud:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataلاحظ نشر المنفذ: 127.0.0.1:8080:80. ينشر Docker المنافذ عن طريق كتابة قواعد DNAT التي يتم تقييمها قبل أن ترى سلسلة INPUT في ufw الحزمة، لذا فإن استخدام 8080:80 مجرداً يضع Nextcloud غير مشفر على الإنترنت العام بغض النظر عما يقوله ufw. الربط بـ loopback يبقيه بعيداً عن الواجهة العامة. عندها، لا يحتاج جدار الحماية إلا للسماح للـ proxy، وإذا كنت تفضل عدم ترك SSH مفتوحاً أمام الإنترنت بأكمله، فإن الوصول إلى الـ VPS عبر شبكة WireGuard VPN ذاتية الاستضافة يتيح لك إسقاط المنفذ 22 من القواعد العامة تماماً:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableشغّل الخدمة باستخدام docker compose up -d، ثم راقب docker compose logs -f app. الإقلاع الأول ينسخ شجرة التطبيق بالكامل إلى الـ volume ويشغل المثبّت؛ لا يستجيب الحاوية لأي شيء حتى ينتهي ذلك.
بروتوكول TLS والـ Reverse Proxy
ثبّت nginx وcertbot من مستودعات التوزيعة، وأنشئ كتلة خادم (server block) بسيطة على المنفذ 80 مع ضبط server_name بشكل صحيح، ثم اترك certbot يعيد كتابتها. آليات تحدي HTTP-01، ومؤقت التجديد، وأنماط الفشل مشروحة بالكامل في إصدار شهادات Let's Encrypt باستخدام certbot وnginx على Ubuntu 24.04:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comيضيف certbot أسطر ssl_certificate وإعادة التوجيه من :80 إلى :443، كما يثبّت مؤقتاً في systemd لتجديد الشهادة التي تبلغ مدتها 90 يوماً. تأكد من وجوده باستخدام systemctl list-timers | grep certbot، فمؤقت التجديد الذي لم يتم تفعيله يمثل قنبلة موقوتة مدتها 90 يوماً.
كتلة الـ proxy نفسها:
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 بإصدار أقدم يكون المكافئ فيه هو listen 443 ssl http2;. سيخبرك nginx -t أي الخيارين يقبله إصدارك.
إعدادات client_max_body_size ومهلات القراءة الطويلة هي ما يمنع انقطاع عمليات الرفع الكبيرة في منتصفها. يقوم proxy_request_buffering off ببث ملفات الرفع مباشرة بدلاً من تخزين الملف بالكامل على قرص الـ proxy أولاً.
يُعد nginx على المضيف أبسط حل يعمل لتطبيق واحد. إذا كان Nextcloud سيشارك الـ VPS مع حاويات أخرى، فإن تشغيل Traefik كـ Reverse Proxy عبر Docker Compose لتطبيقات متعددة ينقل التوجيه وإصدار الشهادات إلى تسميات الحاويات (container labels)، وتظهر نفس مخاوف client_max_body_size والمهلات هناك كإعدادات للـ middleware والـ transport.
trusted_proxies و overwriteprotocol
هنا يقع معظم مستخدمي Nextcloud ذاتي الاستضافة في الخطأ، وتظهر أعراض لا تبدو مرتبطة بالسبب الحقيقي.
لا يتم اعتماد X-Forwarded-Proto: https إلا عندما يصل الطلب من عنوان مدرج في trusted_proxies. عندما لا يتم اعتماده، يعتقد Nextcloud أن الطلب هو HTTP عادي ويصدر روابط http://؛ يقوم الـproxy بإعادة توجيهها إلى HTTPS؛ يتبع المتصفح الرابط؛ ثم يصدر Nextcloud روابط http:// مرة أخرى. هذا هو سبب حلقة إعادة التوجيه. بينما يثبّت OVERWRITEPROTOCOL: https البروتوكول بغض النظر عن أي شيء.
الفخ في TRUSTED_PROXIES هو أن العنوان الذي يراه Nextcloud ليس 127.0.0.1. يعمل nginx على المضيف ويتصل بمنفذ منشور، لذا يرى الحاوية بوابة جسر Docker، وهي عنوان ضمن 172.x. اعثر على الشبكة الفرعية الحقيقية:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'ضع هذا الـCIDR (أو النطاق الذي يغطيه 172.16.0.0/12) في TRUSTED_PROXIES. إذا ضبطته بنطاق واسع جداً، فقد يتمكن أي عميل من انتحال X-Forwarded-For؛ وإذا ضبطته بشكل خاطئ، فسيظهر كل تسجيل دخول وكأنه قادم من عنوان البوابة، وستقوم حماية القوة الغاشمة بحظر مثيلك بالكامل دفعة واحدة، وستظهر في لوحة تحكم المسؤول رسالة: "إعداد ترويسة الـreverse proxy غير صحيح، أو أنك تصل إلى Nextcloud من خلال proxy غير موثوق."
يعد OVERWRITECLIURL مهماً لحاوية cron، التي لا تتلقى طلبات واردة لاستنتاج اسم المضيف منها. بدون هذا الإعداد، تولد المهام الخلفية روابط إلى localhost، وترسل إشعارات البريد الإلكتروني روابط غير قابلة للاستخدام.
مهام الخلفية: استخدام cron بدلاً من AJAX
المشغّل الافتراضي للمهام في Nextcloud هو AJAX: حيث يتم تنفيذ المهام كأثر جانبي عند تحميل أحد المستخدمين لصفحة ما. بما أن أحداً لا يتصفح الموقع في الساعة 04:00، فإن عمليات حذف المهملات، وتنظيف النسخ، وإنشاء المعاينات، وإعادة محاولة الاتصالات الموحدة تتوقف، وتظهر أولى أعراض ذلك في نمو حجم مجلد البيانات بشكل مستمر. تقوم خدمة cron المذكورة أعلاه بتشغيل حلقة /cron.sh الرسمية مقابل نفس وحدات التخزين (volumes). أخبر Nextcloud بأن يتوقع ذلك:
docker compose exec -u www-data app php occ background:cronيتبع كل أمر occ هذا النمط: docker compose exec -u www-data app php occ <command>. من المفيد إنشاء اسم مستعار (alias) له.
Backups: three things, or none
A filesystem-only backup restores to a broken instance. The data directory holds the bytes; Postgres holds the file cache, shares, users, and app state; config.php holds the database credentials, the instance ID and the password salt. Restore the files without the database and Nextcloud cannot see them. Restore the database without config.php and it cannot open the database. Restore an old database against a newer data directory and you get shares pointing at files that moved.
Back up all three, from a quiesced instance:
#!/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 is what makes the dump and the file copy agree with each other. Skip it and you will eventually capture a database that references a file the rsync had not reached yet. Note that the script keeps timestamped database dumps but only one rolling mirror of the data directory, rsync --delete overwrites it each run, so only the newest dump pairs with the file copy.
Then get it off the box. A backup that lives on the same VPS as the thing it backs up is a copy, not a backup. restic against object storage or a second host is the usual answer, and its deduplication handles the data directory far better than a nightly tarball. The full setup, from repository init to the nightly timer and the restore drill, is in off-box VPS backups with restic.
Restore is not simply the reverse. A freshly-started stack runs the installer and writes a brand-new config.php, a new instance ID and password salt, and importing the dump on top of that new identity leaves broken sessions and share tokens. Put the old identity back first, in this order:
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 reconciles the file cache with what is actually on disk. Rehearse this once, on a spare VPS, before you need it. The same split between bytes on disk and metadata in Postgres governs every other app of this shape, which is why an Immich backup that captures the library but not the database restores to an empty timeline.
الترقيات: إصدار رئيسي واحد في كل مرة
يدعم Nextcloud الترقية بمقدار إصدار رئيسي واحد فقط في كل مرة. القفز من الإصدار 29 إلى 31 لا يفشل بشكل آمن، بل يؤدي إلى الخطأ Exception: Updates between multiple major versions and downgrades are unsupported. ويتركك في وضع الصيانة (maintenance mode).
تتم ترقية Docker كالتالي: خذ نسخة احتياطية، عدّل الوسم (tag) من 31 إلى 32 في كل من الخدمتين app وcron، ثم نفّذ docker compose pull && docker compose up -d، وبعدها docker compose logs -f app. تكتشف نقطة دخول الصورة (image entrypoint) وجود كود أحدث مقارنة بالبيانات الموجودة وتنفذ occ upgrade تلقائياً. لا تقاطع هذه العملية. عندما تتوقف السجلات عن التحديث، نفّذ docker compose exec -u www-data app php occ status وتحقق من versionstring ومن أن التطبيقات قد عادت للعمل وهي مفعّلة.
هناك قاعدتان تحميانك: ارفع إصداراً رئيسياً واحداً، تحقق من سلامة النظام، ثم ارفع الإصدار التالي. ولا تقم أبداً بتعديل الوسم في الخدمة app دون تعديل cron ليطابقه؛ فتشغيل إصدارين مختلفين من Nextcloud على قاعدة بيانات واحدة هو مسار مؤكد لتلف البيانات.
الأخطاء التي ستواجهها فعلياً
"Your data directory is readable by other users. Please change the permissions to 0770." (دليل بياناتك قابل للقراءة من قبل مستخدمين آخرين. يرجى تغيير الصلاحيات إلى 0770). يحتوي الدليل المربوط (bind-mounted) على صلاحيات قراءة للمجموعة أو للعامة. راجع 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." (دليل بياناتك غير صالح. تأكد من وجود ملف باسم .ocdata في الجذر). يشير الربط إلى مسار لم يقم Nextcloud بتهيئته، أو هناك خطأ مطبعي في المسار، أو تم استبدال الدليل بآخر فارغ أثناء عمل المثيل. تأكد من تطابق مسار المضيف مع سطر الـ volume.
"Access through untrusted domain." (الوصول عبر نطاق غير موثوق). اسم المضيف في الطلب غير موجود في trusted_domains. لا ينطبق NEXTCLOUD_TRUSTED_DOMAINS إلا عند التثبيت الأول؛ بعد ذلك قم بضبطه مباشرة عبر: occ config:system:set trusted_domains 1 --value=cloud.example.com.
502 Bad Gateway، مع وجود connect() failed (111: Connection refused) while connecting to upstream في /var/log/nginx/error.log. لم يتمكن nginx من الوصول إلى أي شيء على 127.0.0.1:8080. إما أن الحاوية لا تزال قيد التهيئة (تحقق من docker compose logs app)، أو أنها توقفت (docker compose ps)، أو أن سطر النشر (publish) لا يطابق المنفذ proxy_pass. تأكد من ذلك باستخدام ss -ltnp | grep 8080.
حلقة إعادة توجيه (redirect loop)، أو تحذيرات "غير آمن" (insecure) في لوحة تحكم المسؤول. المكون OVERWRITEPROTOCOL: https مفقود، أو أن TRUSTED_PROXIES لا يحتوي على الشبكة الفرعية لبوابة Docker. راجع قسم الـ proxy أعلاه.
LockedException: "files/..." is locked. عند ضبط REDIS_HOST، تقوم الصورة بتهيئة Redis كخلفية للقفل (locking backend) وتصبح الأقفال العالقة نادرة. بدون ذلك، تبقى الأقفال في جدول قاعدة البيانات oc_file_locks، ويؤدي إنهاء الطلب أثناء الكتابة إلى بقاء صفوف معلقة. تأكد من أن Redis قيد الاستخدام فعلياً، يجب أن يعيد occ config:system:get memcache.locking فئة Redis، قبل أن تقوم بمسح صفوف القفل يدوياً.
"The PHP memory limit is below the recommended value of 512MB." (حد ذاكرة PHP أقل من القيمة الموصى بها وهي 512MB). ارفع قيمة PHP_MEMORY_LIMIT وأعد إنشاء الحاوية. تذكر تأثير ذلك على الحد الأقصى لاستهلاك الذاكرة في أسوأ الحالات.
ما الذي يتعطل عند التوسع
العقبة الأولى هي تجاوز حجم دليل البيانات لسعة وحدة التخزين. زيادة حجم وحدة التخزين على خادم VPS تتطلب تغيير الحجم ثم توسيع نظام الملفات، وهي عملية أقل إيلاماً بكثير عند جدولتها بدلاً من القيام بها عند امتلاء القرص بنسبة 100%. فعّل التنبيهات على استخدام القرص الآن، وليس لاحقاً.
العقبة الثانية هي oc_filecache. تتباطأ عمليات سرد الملفات ومسح المزامنة مع زيادة عدد الصفوف، والحل يكمن في صيانة قاعدة البيانات: احتفظ بـ Postgres على وحدة تخزين سريعة، واسمح لها باستخدام ذاكرة مشتركة كافية، وقم بتنظيف الملفات المهملة والإصدارات القديمة باستخدام إعدادات الاستبقاء بدلاً من تركها تتراكم إلى الأبد.
العقبة الثالثة هي تنافس عملية إنشاء المعاينات مع كل شيء آخر. على خادم صغير، اجعل مزودات المعاينة محدودة ولا تشغّل occ preview:generate-all أبداً خلال ساعات العمل. إذا كان معظم ما تخزنه هو صور كاميرا الهاتف، فإن معالجة الصور المصغرة يجب أن تتم على خادم مخصص للصور بدلاً من ذلك، ويغطي مقارنة بين PhotoPrism و Immich من حيث استهلاك الذاكرة وتطبيقات الهاتف وأوامر النسخ الاحتياطي تكلفة كل منهما مقارنة بخادم Nextcloud.
بعد ذلك، الإجابة الصريحة هي أن الإضافات تتطلب خادماً خاصاً بها. Collabora والبحث في النصوص الكاملة هي خدمات مقيمة منفصلة ذات متطلبات ذاكرة خاصة بها، ووضعها على نفس الخادم الذي يحوي نسختك الوحيدة من الملفات يزيد من نطاق الفشل دون أي فائدة. إذا كان تحرير المستندات داخل المتصفح هو الإضافة التي تريدها، فإن الحد الأدنى لذاكرة الوصول العشوائي وحدود الاتصال التي تميز OnlyOffice عن Collabora يحدد أياً منهما يمكن لخادم VPS بذاكرة 2 إلى 4 جيجابايت تحمله. انقل تخزين الملفات إلى وحدة تخزين متوافقة مع S3 عندما لا تعود وحدة التخزين المحلية مناسبة، ولاحظ أن هذا يجعل النسخ الاحتياطي أصعب، وليس أسهل: لا تزال قاعدة البيانات تحتفظ بالبيانات الوصفية، ويجب تفريغها بالتزامن مع محتويات الحاوية (bucket).
بمجرد أن يبدأ المثيل في خدمة مستخدمين فعليين، ضع Uptime Kuma أمامه لتصلك تنبيهات التوقف قبل أن تلاحظها تطبيقات المزامنة. تتوافق السحابة الخاصة بشكل جيد مع خادم البريد الخاص بك، وإذا كنت تفضل عدم ربط الخدمات يدوياً، فإن Cloudron و CasaOS و Coolify تقارن المنصات التي تقوم بذلك نيابة عنك. إذا كان محرك بحث ذاتي الاستضافة هو التالي في قائمتك، فتوقع نوعاً مختلفاً من المشاكل عن تلك المذكورة أعلاه: تأتي أخطاء 429 في SearXNG إما من محدد معدل الطلبات الخاص به أو من حظر محركات البحث الأولية لعنوان IP الخاص بخادمك، والسجلات هي الوحيدة التي ستخبرك بالسبب.
FAQ
هل يمكنني تشغيل Nextcloud باستخدام SQLite بدلاً من Postgres؟
يمكنك ذلك، وتسمح لك الصورة الرسمية بذلك، لكن عميل المزامنة المكتبي الواحد الذي يرسل طلبات متوازية سيؤدي إلى SQLSTATE[HY000]: General error: 5 database is locked وظهور أخطاء HTTP 500. تستخدم SQLite قفل كتابة على مستوى قاعدة البيانات بالكامل، بينما يقوم Nextcloud بالكتابة باستمرار، سواء في أقفال الملفات، أو سجلات النشاط، أو حالة المهام. ابدأ باستخدام Postgres أو MariaDB؛ حيث يوجد occ db:convert-type، لكنه يتطلب عملية ترحيل شاملة ومطولة للبيانات الحية.
ما مقدار ذاكرة الوصول العشوائي (RAM) التي يحتاجها خادم VPS لتشغيل Nextcloud فعلياً؟
حدد الحجم بناءً على التزامن، وليس عدد المستخدمين. الذاكرة المقيمة في أسوأ الحالات تساوي تقريباً عدد الطلبات المتزامنة مضروباً في PHP_MEMORY_LIMIT، بالإضافة إلى المخازن المؤقتة المشتركة لـ Postgres وخلفية واحدة لكل اتصال، مضافاً إليها أي ارتفاع مفاجئ في استهلاك الذاكرة أثناء توليد المعاينات. يمكن لخادم بسعة 2 GB تشغيل مثيل صغير لمنزل إذا قمت بتقييد المعاينات وإضافة مساحة تبديل (swap)؛ أما إذا أضفت Collabora أو البحث بالنص الكامل، فستحتاج إلى تخصيص موارد إضافية لمجموعة ثانية من الخدمات المقيمة.
لماذا تفشل عمليات الرفع الكبيرة خلف Nginx reverse proxy؟
عادة ما يرجع السبب إلى إعدادين في الـ proxy: ترك client_max_body_size على القيمة الافتراضية 1 MB يؤدي إلى قطع الطلب، كما أن قيم proxy_read_timeout / proxy_send_timeout القصيرة تنهي عمليات النقل الطويلة في منتصف الطريق. اضبط كلاً منهما بسخاء، واضبط proxy_request_buffering off على البث (stream) بدلاً من التخزين المؤقت (spool)، وارفع قيمة PHP_UPLOAD_LIMIT في حاوية التطبيق لتتطابق معها.
لماذا يعيد Nextcloud التوجيه في حلقة مفرغة أو يحذر بشأن الـ reverse proxy؟
لا ترى الحاوية الـ nginx عند 127.0.0.1، بل ترى بوابة جسر Docker، الموجودة في مكان ما ضمن 172.x. عندما يكون هذا العنوان مفقوداً من TRUSTED_PROXIES، يتم تجاهل ترويسة X-Forwarded-Proto: https، ويصدر Nextcloud روابط http://، فيقوم الـ proxy بإعادة توجيهها مرة أخرى. اضبط TRUSTED_PROXIES على شبكة الجسر الفرعية الحقيقية وثبّت OVERWRITEPROTOCOL: https.
هل يمكنني ترقية Nextcloud مباشرة من الإصدار 29 إلى 31؟
لا. يدعم Nextcloud إصداراً رئيسياً واحداً فقط في كل عملية ترقية، وتتوقف الترقية عند تخطي الإصدارات مع ظهور Updates between multiple major versions and downgrades are unsupported.، مما يترك المثيل في وضع الصيانة. قم بأخذ نسخة احتياطية، وارفع رقم الإصدار بمقدار درجة واحدة في كل من خدمتي app وcron، ثم نفذ docker compose pull && docker compose up -d، وتحقق من النتيجة باستخدام occ status، ثم كرر العملية.