تشغيل Nextcloud على VPS عبر Docker مع TLS ونسخ احتياطية
ثبّت 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 وإنشاء تفريغ لقاعدة البيانات على خدمة SaaS يملكها طرف آخر.
تقدير الحجم: ما الذي يستهلك الذاكرة فعلياً
يهيمن على استهلاك Nextcloud للذاكرة ثلاثة أشياء، ولا يُعد أيٌّ منها «Nextcloud» بحد ذاته.
عمليات PHP. تخدم صورة -apache كل طلب متزامن من خلال عملية عاملة تحتوي على مفسّر PHP. قد تزداد ذاكرة كل عملية عاملة حتى PHP_MEMORY_LIMIT قبل أن ينهي PHP الطلب. تبلغ أسوأ حالة تقريبية للذاكرة المقيمة حاصل ضرب عدد الطلبات المتزامنة × حد الذاكرة، ويفتح عميل المزامنة المكتبي عدة اتصالات متوازية لكل مستخدم. يحدد التزامن السقف، وليس عدد المستخدمين.
قاعدة البيانات. ينشئ Postgres عملية خلفية لكل اتصال، ويحافظ على المخازن المؤقتة المشتركة في الذاكرة المقيمة. يتناسب حجم مجموعة العمل مع عدد الملفات، وليس مع عدد البايتات: يحتفظ oc_filecache بصف لكل ملف ولكل مستخدم. تكون قاعدة بيانات تحتوي على مئة ألف ملف صغير أكثر استهلاكاً للموارد من قاعدة بيانات تحتوي على مئة ملف كبير.
إنشاء المعاينات. يفك إنشاء صورة مصغرة الصورة المصدر إلى الذاكرة بدقتها الكاملة. وتستدعي معاينات الفيديو ffmpeg من خلال shell. يؤدي تشغيل 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. يكون swap بطيئاً، لكن إنهاء العملية بواسطة OOM أثناء الترقية أسوأ.
سبب تعطل 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:ثبّت الوسم الرئيسي، وتحقق من الوسم الحالي على 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 يعيد كتابة الإعداد. يشرح إصدار شهادات Let's Encrypt باستخدام certbot وnginx على Ubuntu 24.04 آلية تحدي HTTP-01، ومؤقت التجديد، وحالات الفشل بالتفصيل:
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 nginx يمرّر الرفع مباشرة بدلاً من تخزين الملف كاملاً مؤقتاً على قرص الـproxy أولاً.
يُعد nginx على المضيف أبسط حل يعمل مع تطبيق واحد. إذا كان Nextcloud سيشارك VPS مع حاويات أخرى، فإن تشغيل Traefik كـreverse proxy باستخدام Docker Compose لعدة تطبيقات ينقل التوجيه وإصدار الشهادات إلى labels الحاويات. وتظهر مخاوف client_max_body_size والمهلات نفسها هناك في صورة إعدادات middleware وtransport.
trusted_proxies و overwriteprotocol
هنا تحدث معظم مشكلات مثيلات Nextcloud المستضافة ذاتياً، وتبدو الأعراض غير مرتبطة بالسبب.
لا يُعتدّ بـ X-Forwarded-Proto: https إلا عندما يصل الطلب من عنوان مدرج في trusted_proxies. عندما لا يُعتدّ به، يعتقد Nextcloud أن الطلب يستخدم HTTP عاديًا، وينشئ عناوين URL وفق http://؛ ثم يعيد الـproxy توجيهها إلى HTTPS؛ ويتبع المتصفح إعادة التوجيه؛ ثم ينشئ Nextcloud http:// مرة أخرى. هذه هي حلقة إعادة التوجيه. يفرض OVERWRITEPROTOCOL: https المخطط بصرف النظر عن ذلك.
المشكلة في TRUSTED_PROXIES هي أن العنوان الذي يراه Nextcloud ليس 127.0.0.1. يعمل nginx على المضيف ويتصل بمنفذ منشور، لذلك ترى الحاوية بوابة Docker bridge، أي عنوانًا ضمن 172.x. اعثر على الشبكة الفرعية الفعلية:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'ضع CIDR هذا، أو 172.16.0.0/12 الذي يغطيه، في TRUSTED_PROXIES. إذا جعلته واسعًا أكثر من اللازم، يمكن لأي عميل انتحال X-Forwarded-For؛ وإذا أدخلته بشكل خاطئ، فسيبدو كل تسجيل دخول وكأنه قادم من عنوان البوابة، وستحظر حماية brute-force المثيل بأكمله دفعة واحدة، وسيعرض ملخص الإدارة الرسالة "إعداد رؤوس reverse proxy غير صحيح، أو أنك تصل إلى Nextcloud من proxy موثوق."
يهم OVERWRITECLIURL حاوية cron، إذ لا يصل إليها أي طلب وارد يمكنها من استنتاج اسم المضيف. من دونه، تنشئ المهام الخلفية روابط إلى localhost، وترسل إشعارات البريد الإلكتروني عناوين URL غير صالحة للاستخدام.
المهام في الخلفية: cron بدلاً من AJAX
مشغّل المهام الافتراضي في Nextcloud هو AJAX: تُنفَّذ المهام كنتيجة جانبية لتحميل شخص ما لصفحة. لا أحد يتصفح في الساعة 04:00، لذلك تتوقف آليات انتهاء صلاحية المهملات، وتنظيف الإصدارات، وإنشاء المعاينات، وإعادة المحاولات الاتحادية. وتكون أول علامة على ذلك أن دليل البيانات يستمر في النمو دون توقف. تشغّل خدمة cron أعلاه حلقة /cron.sh الرسمية على وحدات التخزين نفسها. أخبر Nextcloud بأن يتوقعها:
docker compose exec -u www-data app php occ background:cronيتبع كل أمر occ هذا الشكل: docker compose exec -u www-data app php occ <command>. من المفيد إنشاء اسم مستعار له.
النسخ الاحتياطية: ثلاثة عناصر أو لا شيء
تستعيد النسخة الاحتياطية التي تقتصر على نظام الملفات نسخةً معطّلة. يحتوي مجلد البيانات على وحدات البايت؛ ويحتفظ Postgres بذاكرة الملفات المؤقتة والمشاركات والمستخدمين وحالة التطبيق؛ بينما يحتوي config.php على بيانات اعتماد قاعدة البيانات ومعرّف المثيل وsalt كلمة المرور. إذا استعدت الملفات من دون قاعدة البيانات، فلن يتمكن Nextcloud من رؤيتها. وإذا استعدت قاعدة البيانات من دون config.php، فلن يتمكن من فتح قاعدة البيانات. وإذا استعدت قاعدة بيانات قديمة فوق مجلد بيانات أحدث، فستحصل على مشاركات تشير إلى ملفات نُقلت من أماكنها.
أنشئ نسخة احتياطية من العناصر الثلاثة كلها، بعد إيقاف التغييرات مؤقتاً على المثيل:
#!/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/يجعل وضع الصيانة تفريغ قاعدة البيانات ونسخ الملفات متوافقين. إذا تخطيته، فستلتقط في النهاية قاعدة بيانات تشير إلى ملف لم يكن rsync قد وصل إليه بعد. لاحظ أن البرنامج النصي يحتفظ بتفريغات مؤرخة لقاعدة البيانات، لكنه يحتفظ بنسخة mirror متجددة واحدة فقط من مجلد البيانات؛ إذ يستبدل rsync --delete هذه النسخة في كل تشغيل. لذلك لا يتوافق مع نسخة الملفات إلا أحدث تفريغ.
بعد ذلك، انقل النسخة خارج الخادم. فالنسخة الاحتياطية الموجودة على VPS نفسه الذي تحميه ليست نسخة احتياطية، بل نسخة عادية. يُعد restic إلى object storage أو إلى مضيف ثانٍ الحل المعتاد، كما أن إزالة التكرار فيه تتعامل مع مجلد البيانات بكفاءة أكبر بكثير من ملف tar يُنشأ كل ليلة. يشرح النسخ الاحتياطية لـVPS خارج الخادم باستخدام restic الإعداد الكامل، بدءاً من تهيئة المستودع ووصولاً إلى المؤقت الليلي واختبار الاستعادة.
لا تعني الاستعادة تنفيذ الخطوات العكسية ببساطة. يشغّل stack الذي بدأ حديثاً برنامج التثبيت، ويكتب config.php جديداً ومعرّف مثيل جديداً وsalt جديداً لكلمة المرور. ويؤدي استيراد التفريغ فوق هذه الهوية الجديدة إلى ترك جلسات ورموز مشاركة معطّلة. أعد الهوية القديمة أولاً، بالترتيب التالي:
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 --allيُجري files:scan تسوية لذاكرة الملفات المؤقتة وفق ما هو موجود فعلياً على القرص. تدرّب على ذلك مرة واحدة على VPS احتياطي قبل أن تحتاج إليه. يحكم الفصل نفسه بين وحدات البايت الموجودة على القرص والبيانات الوصفية في Postgres كل تطبيق آخر من هذا النوع. ولهذا السبب، فإن نسخة Immich الاحتياطية التي تلتقط المكتبة ولا تلتقط قاعدة البيانات تستعيد خطاً زمنياً فارغاً.
الترقية: إصدار رئيسي واحد في كل مرة
يدعم Nextcloud الترقية عبر إصدار رئيسي واحد فقط في كل مرة. الانتقال من 29 إلى 31 لا يفشل بطريقة آمنة، بل يفشل مع Exception: Updates between multiple major versions and downgrades are unsupported. ويتركك في وضع الصيانة.
تتم ترقية Docker كالتالي: أنشئ نسخة احتياطية، ثم عدّل الوسم من 31 إلى 32 في كل من الخدمتين app وcron، ثم نفّذ docker compose pull && docker compose up -d، وبعد ذلك docker compose logs -f app. تكتشف نقطة إدخال الصورة وجود تعليمات برمجية أحدث مقارنةً بالبيانات الحالية، وتنفّذ occ upgrade تلقائياً. لا تقاطع هذه العملية. عندما تتوقف السجلات عن تسجيل رسائل جديدة، نفّذ docker compose exec -u www-data app php occ status وتحقق من versionstring ومن عودة التطبيقات إلى حالة التمكين.
هناك قاعدتان توفران عليك المشكلات: ارفع إصداراً رئيسياً واحداً، ثم تحقّق منه قبل رفع الإصدار التالي. ولا تعدّل الوسم في خدمة app من دون تعديل cron ليطابقه؛ فاستخدام إصدارين مختلفين من Nextcloud مع قاعدة بيانات واحدة قد يؤدي إلى تلف البيانات.
الأخطاء التي ستراها فعلياً
"مجلد بياناتك قابل للقراءة من مستخدمين آخرين. غيّر الأذونات إلى 0770." يحتوي المجلد المرتبط بـbind mount على بتات قراءة للمجموعة أو لجميع المستخدمين. sudo chmod 0770 /srv/nextcloud/data وsudo chown -R 33:33 /srv/nextcloud/data.
"مجلد بياناتك غير صالح. تأكد من وجود ملف باسم .ocdata في الجذر." يشير bind mount إلى مكان لم يهيّئ فيه Nextcloud المجلد، أو يوجد خطأ مطبعي في المسار، أو استُبدل مجلد فارغ جديد بمجلد مثيل يعمل. تحقق من تطابق مسار المضيف مع سطر volume.
"الوصول عبر نطاق غير موثوق." اسم المضيف في الطلب غير موجود في 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، أو قد لا يتطابق سطر النشر مع منفذ proxy_pass. أكّد ذلك باستخدام ss -ltnp | grep 8080.
حلقة إعادة توجيه، أو تحذيرات "غير آمن" في نظرة المسؤول. الخاصية OVERWRITEPROTOCOL: https مفقودة، أو لا يحتوي TRUSTED_PROXIES على الشبكة الفرعية لبوابة Docker. راجع قسم الوكيل أعلاه.
LockedException: "files/..." is locked. عند ضبط REDIS_HOST، تهيّئ الصورة Redis ليكون backend لأقفال الملفات، وتصبح الأقفال القديمة نادرة. من دونه، تُخزَّن الأقفال في جدول قاعدة البيانات oc_file_locks، ويترك الطلب الذي يتوقف أثناء الكتابة صفوفاً متبقية. تأكد من استخدام Redis فعلياً؛ يجب أن يعرض occ config:system:get memcache.locking فئة Redis، قبل أن تبدأ بحذف صفوف الأقفال يدوياً.
"حد ذاكرة PHP أقل من القيمة الموصى بها البالغة 512MB." ارفع PHP_MEMORY_LIMIT وأعد إنشاء الحاوية. تذكّر تأثير ذلك في الحد الأقصى المحتمل للاستهلاك.
ما الذي يتعطل عند التوسع
العائق الأول هو أن دليل البيانات يتجاوز سعة وحدة التخزين. يؤدي توسيع وحدة التخزين على VPS إلى تكبير الحجم ثم توسيع نظام الملفات، ويكون ذلك أقل إيلاماً بكثير إذا جرى بشكل مجدول قبل امتلاء الوحدة بنسبة 100%. فعّل التنبيهات عند استخدام القرص الآن، لا لاحقاً.
العائق الثاني هو oc_filecache. تتباطأ قوائم الملفات وعمليات فحص المزامنة مع زيادة عدد الصفوف، والحل يتطلب العمل على قاعدة البيانات: أبقِ Postgres على وحدة تخزين سريعة، واسمح له باستخدام قدر كافٍ من الذاكرة المشتركة، ونظّف سلة المحذوفات والإصدارات باستخدام إعدادات الاحتفاظ بدلاً من تركها تتراكم إلى أجل غير مسمى.
العائق الثالث هو تنافس إنشاء المعاينات مع كل العمليات الأخرى. على جهاز صغير، احصر موفّري المعاينات، ولا تشغّل occ preview:generate-all أثناء ساعات العمل. إذا كانت معظم البيانات التي تخزنها تأتي من صور هاتف، فمن الأفضل تنفيذ إنشاء الصور المصغرة على خادم صور مخصص. يوضح مقارنة PhotoPrism وImmich من حيث RAM وتطبيقات الهاتف وأوامر النسخ الاحتياطي تكلفة كل منهما إلى جانب خادم Nextcloud.
بعد ذلك، تكون الإجابة الصريحة هي أن الخدمات الإضافية تحتاج إلى جهاز مستقل. يُعد Collabora والبحث في النص الكامل خدمتين مقيمتين منفصلتين، ولكل منهما متطلبات ذاكرة خاصة. ووضعهما على الجهاز الذي يحتفظ أيضاً بالنسخة الوحيدة من ملفاتك يوسّع نطاق العطل دون فائدة. إذا كان تحرير المستندات داخل المتصفح هو الإضافة التي تريدها، فإن الحد الأدنى من RAM وحدود الاتصالات لدى المورّد، والتي تحدد الفرق بين OnlyOffice وCollabora هي التي تحدد ما إذا كان VPS بسعة 2 إلى 4 GB يستطيع تشغيل أحدهما أصلاً. انقل تخزين الملفات إلى وحدة تخزين أساسية متوافقة مع S3 عندما تتوقف وحدة التخزين الحالية عن ملاءمة احتياجاتك، ولاحظ أن ذلك يجعل النسخ الاحتياطية أصعب، لا أسهل: تظل قاعدة البيانات تحتوي على البيانات الوصفية، ويجب تفريغها بالتزامن مع bucket.
بعد أن يبدأ instance في خدمة مستخدمين فعليين، ضع Uptime Kuma أمامه لكي تعرف بتوقف الخدمة قبل عملاء المزامنة. تتكامل السحابة الخاصة جيداً مع خادم البريد الخاص بك، وإذا كنت تفضّل عدم ربط الخدمات يدوياً، فقارن في Cloudron وCasaOS وCoolify بين المنصات التي تنفذ ذلك نيابة عنك. إذا كان محرك بحث مستضاف ذاتياً هو الإضافة التالية في قائمتك، فتوقع فئة مختلفة من المشكلات عن المذكورة أعلاه: تنتج أخطاء 429 في SearXNG إما عن محدِّد المعدل الخاص به أو عن حظر محركات البحث upstream لعنوان IP الخاص بـVPS، ولا يحدد أيّاً منهما إلا السجل.
FAQ
هل يمكنني تشغيل Nextcloud باستخدام SQLite بدلاً من Postgres؟
يمكنك ذلك، وستسمح لك الصورة الرسمية به، لكن عميل مزامنة واحداً على سطح المكتب يرسل طلبات متوازية سيصطدم بـSQLSTATE[HY000]: General error: 5 database is locked وأخطاء HTTP 500. يفرض SQLite قفلاً للكتابة على قاعدة البيانات بأكملها، بينما يكتب Nextcloud باستمرار في أقفال الملفات وصفوف النشاط وحالة المهام. ابدأ باستخدام Postgres أو MariaDB؛ يوجد occ db:convert-type، لكنه ترحيل طويل وغير قابل للتجزئة للبيانات الحية.
ما مقدار RAM الذي يحتاجه Nextcloud VPS فعلياً؟
حدّد الموارد وفق التزامن، لا وفق عدد المستخدمين. تبلغ الذاكرة المقيمة في أسوأ الحالات تقريباً عدد الطلبات المتزامنة مضروباً في PHP_MEMORY_LIMIT، إضافةً إلى المخازن المؤقتة المشتركة في Postgres وعملية خلفية واحدة لكل اتصال، إضافةً إلى الارتفاع الذي قد تسببه عملية إنشاء المعاينات. يمكن لخادم بسعة 2 GB تشغيل مثيل صغير للاستخدام المنزلي إذا حدّدت المعاينات وأضفت swap؛ لكن إضافة Collabora أو البحث في النص الكامل تعني أنك تحتاج إلى تقدير موارد مجموعة ثانية من الخدمات المقيمة.
لماذا تفشل عمليات الرفع الكبيرة خلف reverse proxy يعمل بواسطة nginx؟
يفسّر إعدادان في الـproxy المشكلة عادةً: يترك client_max_body_size القيمة الافتراضية البالغة 1 MB، ما يؤدي إلى اقتطاع الطلب، بينما تؤدي قيم proxy_read_timeout / proxy_send_timeout القصيرة إلى إنهاء عمليات النقل الطويلة في منتصفها. اضبط القيمتين على حدود كبيرة، واضبط proxy_request_buffering off على البث بدلاً من التخزين المؤقت، وارفع PHP_UPLOAD_LIMIT في حاوية التطبيق لتطابق ذلك.
لماذا يعيد Nextcloud التوجيه في حلقة أو يحذّر من reverse proxy؟
لا يرى التطبيق داخل الحاوية nginx على 127.0.0.1، بل يرى بوابة Docker bridge في مكان ما ضمن 172.x. عندما يكون هذا العنوان مفقوداً من TRUSTED_PROXIES، يتم تجاهل الرأس X-Forwarded-Proto: https، ويصدر Nextcloud عناوين http://، ثم يعيد الـproxy توجيهها إليه. اضبط TRUSTED_PROXIES على الشبكة الفرعية الفعلية لـbridge وثبّت 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، وبعد ذلك كرر العملية.