لنفرض أن ملفات فريقك اليوم موجودة على Dropbox أو OneDrive، فسوف تجد أن الأمر يعمل بشكل جيد في البداية، فكل شخص يثبت التطبيق على جهازه وتتزامن الملفات Sync بين الأجهزة دون أن يفكر أحد في السيرفر Server الذي يحملها، ولكن مع الوقت يكبر حجم الملفات ويزيد عدد المستخدمين فترتفع الفاتورة مع كل حساب جديد، وتكتشف أن المزود هو الذي يحدد المساحة والأسعار ومدة الاحتفاظ بالإصدارات القديمة، وأن ملفات فريقك موجودة على سيرفرات لا تعرف أين هي، وقد تفرض عليك الأنظمة أو العقود في مؤسستك أن تبقى هذه البيانات داخلها.
والحل الأول الذي يخطر على البال هو أن تضع مجلداً مشتركاً Shared Folder على سيرفر في الشبكة يصل إليه الجميع عبر SMB أو FTP، وهذا الحل يعمل داخل المكتب فقط، فلا توجد مزامنة حقيقية بين الأجهزة عندما يعمل أحدهم من البيت، ولا يوجد سجل إصدارات Version History تعود إليه إذا عدل أحدهم ملفاً بالخطأ، ولا توجد روابط مشاركة Share Links ترسلها لشخص من خارج الفريق، ولذلك فالحل الأنسب هو أن تشغل سيرفر مزامنة خاصاً بك يعطي فريقك تجربة قريبة من Dropbox، والملفات فيه على سيرفرك أنت، وأشهر خيارين لذلك هما Nextcloud وSeafile.
وقد يتساءل البعض: لماذا Seafile وليس Nextcloud وهو الأشهر بينهما؟ والإجابة أن Nextcloud منصة متكاملة فيها التقويم والبريد والتطبيقات المكتبية وعشرات الإضافات Plugins، وهذا مفيد إذا كنت تحتاج إلى كل ذلك، وأما إذا كانت حاجتك الأساسية هي مزامنة الملفات ومشاركتها فإن Seafile يركز على هذه المهمة وحدها، ولذلك فهو أخف على السيرفر وأسرع مع آلاف الملفات ومع الملفات الكبيرة، والسبب أنه يخزن الملفات أجزاء Blocks بطريقة تشبه Git، فلا يرفع عند كل تعديل إلا الأجزاء التي تغيرت.
ويرتب Seafile الملفات في مكتبات Libraries، ولكل مكتبة سجل إصدارات وسلة محذوفات Trash وصلاحيات مشاركة Permissions خاصة بها، وتستطيع أيضاً أن تشفر المكتبة Encryption من جهة الجهاز Client-Side Encryption فلا يقرأ محتواها حتى مدير السيرفر، كما يشرح توثيق ميزات الأمان. وله عميل مزامنة Sync Client لأنظمة Windows وmacOS وLinux، وتطبيقات للهواتف، ودعم لبروتوكول WebDAV.
لكن تذكر: Seafile لا يحفظ الملفات على القرص بشكلها العادي، وإنما يحفظها أجزاء داخلية، وبالتالي لا تستطيع أن تفتح مجلد البيانات Data Directory وتتصفح الملفات منه مباشرة، فالوصول إليها يكون دائماً عبر Seafile نفسه أو عبر WebDAV، وهذا يغير طريقة تفكيرك في النسخ الاحتياطي كما سيأتي.
وسوف نناقش في هذا المقال ما يلي:
- تثبيت Seafile 13 بالملفات الرسمية
.envوseafile-server.yml، مع MariaDB وRedis وSeaDoc، وشرح ما في كل ملف. - الإعداد الأول: حساب المدير، والمكتبات، والمشاركة، والمستخدمين، والبريد، وعميل المزامنة، وWebDAV.
- إصدار شهادة TLS بـ Caddy المرفق مع Seafile، أو تشغيله خلف Reverse Proxy يعمل لديك مسبقاً.
- النسخ الاحتياطي والاستعادة على سيرفر جديد بالترتيب الصحيح، ثم التحديث وأشهر المشكلات وحلولها.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر Linux بمعالجين CPU وذاكرة RAM بحجم 4 GB لفريق صغير، و2 GB تكفي للتجربة، ومساحة قرص Disk تتسع لملفاتك مع هامش للإصدارات القديمة وسلة المحذوفات، والسبب أن Seafile يحتفظ بالأجزاء القديمة حتى تنتهي مدة الاحتفاظ بها.
- Docker Engine مع ملحق Docker Compose، وإذا لم يكونا مثبتين فاتبع دليل تثبيت Docker على Ubuntu.
- نطاق فرعي Subdomain مثل
seafile.example.comعليه سجل A يشير إلى عنوان السيرفر (203.0.113.10). - المنفذان Ports رقم 80 و443 مفتوحان، سواءً استخدمت Caddy المرفق مع Seafile لإصدار الشهادة Certificate، أو Reverse Proxy يعمل لديك أصلاً.
- سيرفر بريد SMTP لرسائل إعادة تعيين كلمة المرور Password Reset والإشعارات Notifications، وهو اختياري ولكننا ننصح به.
مم يتكون النظام؟
تغيرت طريقة التثبيت الرسمية منذ الإصدار 12، فلم يعد هناك ملف docker-compose.yml واحد، وإنما ملف .env فيه كل الإعدادات، وعدة ملفات YAML تختار منها ما تحتاجه عبر المتغير COMPOSE_FILE. وفي الإصدار 13 صار Seafile يقرأ معظم إعداداته من متغيرات البيئة Environment Variables بدلاً من ملفات الإعداد Configuration Files، وصار Redis هو ذاكرة التخزين المؤقت Cache الافتراضية بدلاً من Memcached، كما تذكر ملاحظات الترقية إلى 13.0 Upgrade Notes. والجدول التالي يبين الملفات التي سوف نستخدمها:
| الملف | الخدمات | الدور |
|---|---|---|
seafile-server.yml | seafile وdb وredis | السيرفر نفسه (Seahub وسيرفر الملفات)، وقاعدة البيانات Database من نوع MariaDB، وRedis للتخزين المؤقت |
caddy.yml | caddy | Reverse Proxy يقرأ إعداداته من labels الـ Containers، ويصدر شهادة Let's Encrypt تلقائياً |
seadoc.yml | seadoc | محرر المستندات التعاوني Collaborative Editor المسمى SeaDoc (اختياري) |
notification-server.yml | notification-server | إشعارات فورية لعملاء المزامنة بدلاً من الاستعلام الدوري Polling (اختياري) |
تثبيت Seafile خطوة بخطوة Installation
مجلد التثبيت وتنزيل الملفات الرسمية
سوف نضع ملفات Compose في /opt/seafile، والبيانات في /opt/seafile-data و/opt/seafile-mysql، وهذه هي المسارات الافتراضية في دليل التثبيت الرسمي، والسبب أننا نريد أن تطابق أوامرك ما تقرؤه في التوثيق عندما تحتاج إليه لاحقاً:
sudo mkdir -p /opt/seafile
cd /opt/seafileبعد ذلك نقوم بتنزيل الملفات الرسمية للإصدار 13.0 من موقع Seafile:
sudo curl -fLO https://manual.seafile.com/13.0/repo/docker/ce/seafile-server.yml
sudo curl -fLO https://manual.seafile.com/13.0/repo/docker/caddy.yml
sudo curl -fLO https://manual.seafile.com/13.0/repo/docker/seadoc.yml
sudo curl -fL -o .env https://manual.seafile.com/13.0/repo/docker/ce/envلاحظ أن هذه الملفات تستخدم وسوماً Tags متحركة مثل 13.0-latest، أو redis دون رقم إصدار، وهذا يعني أن أي docker compose pull قد يأتيك بإصدار جديد لم تقرأ ملاحظاته، ولذلك سوف نثبت كل Docker Image على إصدار محدد من داخل .env، فلا يتغير شيء إلا عندما تقرر أنت التحديث Upgrade.
توليد كلمات المرور والمفاتيح Secrets
تحتاج إلى أربع قيم عشوائية: كلمة مرور مستخدم قاعدة البيانات، وكلمة مرور المستخدم root في قاعدة البيانات، وكلمة مرور Redis، ومفتاح JWT الذي تتبادل به الخدمات الرموز Tokens فيما بينها، والأمر التالي يولدها كلها:
for n in DB_PASSWORD DB_ROOT_PASSWORD REDIS_PASSWORD JWT_PRIVATE_KEY; do echo "$n=$(openssl rand -hex 32)"; doneاحتفظ بالمخرج مؤقتاً، فسوف تنسخه في الخطوة التالية.
ملف .env وشرح ما فيه
افتح الملف .env وعدل القيم التالية فقط، واترك بقية الملف كما هو:
sudo nano /opt/seafile/.envCOMPOSE_FILE='seafile-server.yml,caddy.yml,seadoc.yml'
COMPOSE_PATH_SEPARATOR=','
## Docker Images بإصدارات مثبتة
SEAFILE_IMAGE=seafileltd/seafile-mc:13.0.28
SEAFILE_DB_IMAGE=mariadb:10.11.19
SEAFILE_REDIS_IMAGE=redis:8.10.2-alpine
SEAFILE_CADDY_IMAGE=lucaslorentz/caddy-docker-proxy:2.12.1-alpine
SEADOC_IMAGE=seafileltd/sdoc-server:2.0.9
NOTIFICATION_SERVER_IMAGE=seafileltd/notification-server:13.0.21
## مسارات التخزين
BASIC_STORAGE_PATH=/opt
SEAFILE_VOLUME=$BASIC_STORAGE_PATH/seafile-data
SEAFILE_MYSQL_VOLUME=$BASIC_STORAGE_PATH/seafile-mysql/db
SEAFILE_CADDY_VOLUME=$BASIC_STORAGE_PATH/seafile-caddy
SEADOC_VOLUME=$BASIC_STORAGE_PATH/seadoc-data
## عنوان الخدمة
SEAFILE_SERVER_HOSTNAME=seafile.example.com
SEAFILE_SERVER_PROTOCOL=https
TIME_ZONE=Etc/UTC
JWT_PRIVATE_KEY=ضع_قيمة_JWT_PRIVATE_KEY_المولدة
## قاعدة البيانات
SEAFILE_MYSQL_DB_HOST=db
SEAFILE_MYSQL_DB_USER=seafile
SEAFILE_MYSQL_DB_PASSWORD=ضع_قيمة_DB_PASSWORD_المولدة
SEAFILE_MYSQL_DB_CCNET_DB_NAME=ccnet_db
SEAFILE_MYSQL_DB_SEAFILE_DB_NAME=seafile_db
SEAFILE_MYSQL_DB_SEAHUB_DB_NAME=seahub_db
## التخزين المؤقت
CACHE_PROVIDER=redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=ضع_قيمة_REDIS_PASSWORD_المولدة
## قيم التشغيل الأول فقط
INIT_SEAFILE_MYSQL_ROOT_PASSWORD=ضع_قيمة_DB_ROOT_PASSWORD_المولدة
[email protected]
INIT_SEAFILE_ADMIN_PASSWORD=كلمة_مرور_مؤقتة_قوية
## الإضافات
ENABLE_SEADOC=true
ENABLE_NOTIFICATION_SERVER=false
NOTIFICATION_SERVER_URL=في الإعداد أعلاه لاحظ التالي:
SEAFILE_SERVER_HOSTNAMEيقبل اسم نطاق Domain أو عنوان IP فقط، دون رقم منفذ ودونhttps://، وفي التهيئة الأولى Initialization يرفض الـ Container قيمة مثلlocalhostأوlocalhost:8080.- المتغيرات التي تبدأ بـ
INIT_يقرؤها الـ Container في التشغيل الأول فقط لينشئ قواعد البيانات وحساب المدير Admin Account، وبالتالي فإن تغييرها بعد ذلك ليس له أي أثر، فإذا أردت تغيير كلمة مرور المدير فغيرها من الواجهة. - لا تقم بتغيير
SEAFILE_MYSQL_DB_PASSWORDوJWT_PRIVATE_KEYبعد التشغيل الأول، إلا إذا غيرتهما أيضاً في قاعدة البيانات وفي بقية الخدمات، والسبب أن MariaDB وSeaDoc يحتفظان بالقيمة القديمة. - إذا لم تكن تحتاج إلى SeaDoc فاحذف
seadoc.ymlمنCOMPOSE_FILE، واجعلENABLE_SEADOC=false.
وهذا الملف يحمل كل كلمات المرور، ولذلك نجعله مقروءاً للمالك فقط:
sudo chmod 600 /opt/seafile/.envماذا يوجد داخل ملفات Compose؟
لن تحتاج إلى تعديل ملفات YAML، فكل القيم تأتي من .env، ولكن من المفيد أن تعرف ما فيها حتى تفهم ما يحدث عندما تظهر مشكلة. وهذه الأجزاء الأساسية من seafile-server.yml في الإصدار 13.0، بعد اختصار المتغيرات المتشابهة:
services:
db:
image: ${SEAFILE_DB_IMAGE:-mariadb:10.11}
container_name: seafile-mysql
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
- MYSQL_LOG_CONSOLE=true
- MARIADB_AUTO_UPGRADE=1
volumes:
- "${SEAFILE_MYSQL_VOLUME:-/opt/seafile-mysql/db}:/var/lib/mysql"
networks:
- seafile-net
healthcheck:
test: ["CMD", "/usr/local/bin/healthcheck.sh", "--connect", "--mariadbupgrade", "--innodb_initialized"]
interval: 20s
start_period: 30s
timeout: 5s
retries: 10
redis:
image: ${SEAFILE_REDIS_IMAGE:-redis}
container_name: seafile-redis
restart: unless-stopped
command:
- /bin/sh
- -c
- exec redis-server --requirepass "$$REDIS_PASSWORD" --save "" --appendonly no
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
networks:
- seafile-net
seafile:
image: ${SEAFILE_IMAGE:-seafileltd/seafile-mc:13.0-latest}
container_name: seafile
restart: unless-stopped
volumes:
- ${SEAFILE_VOLUME:-/opt/seafile-data}:/shared
environment:
- SEAFILE_MYSQL_DB_HOST=${SEAFILE_MYSQL_DB_HOST:-db}
- SEAFILE_MYSQL_DB_PASSWORD=${SEAFILE_MYSQL_DB_PASSWORD:?Variable is not set or empty}
- INIT_SEAFILE_MYSQL_ROOT_PASSWORD=${INIT_SEAFILE_MYSQL_ROOT_PASSWORD:-}
- INIT_SEAFILE_ADMIN_EMAIL=${INIT_SEAFILE_ADMIN_EMAIL:[email protected]}
- INIT_SEAFILE_ADMIN_PASSWORD=${INIT_SEAFILE_ADMIN_PASSWORD:-asecret}
- SEAFILE_SERVER_HOSTNAME=${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
- SEAFILE_SERVER_PROTOCOL=${SEAFILE_SERVER_PROTOCOL:-http}
- JWT_PRIVATE_KEY=${JWT_PRIVATE_KEY:?Variable is not set or empty}
- ENABLE_SEADOC=${ENABLE_SEADOC:-true}
- SEADOC_SERVER_URL=${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}/sdoc-server
- CACHE_PROVIDER=${CACHE_PROVIDER:-redis}
- REDIS_HOST=${REDIS_HOST:-redis}
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
# ... بقية متغيرات قاعدة البيانات والإضافات
labels:
caddy: ${SEAFILE_SERVER_PROTOCOL:-http}://${SEAFILE_SERVER_HOSTNAME:?Variable is not set or empty}
caddy.reverse_proxy: "{{upstreams 80}}"
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- seafile-net
networks:
seafile-net:
name: seafile-netفي الإعداد أعلاه لاحظ التالي:
- الخدمة
seafileلا تبدأ إلا بعد أن تصبح MariaDB سليمةservice_healthy، والسبب أن التهيئة الأولى تنشئ قواعد البيانات الثلاث وتفشل إذا لم تجد MariaDB جاهزة. - Redis يعمل بكلمة مرور ودون حفظ على القرص (
--save "")، لأنه هنا ذاكرة مؤقتة فقط، وفقدان محتواه عند إعادة التشغيل لا يضر. - labels الخاصة بـ
caddyهي التي يقرؤها Caddy ليعرف النطاق ويوجه الطلبات إلى المنفذ 80 داخل الـ Container.
أما الملف caddy.yml فيشغل caddy-docker-proxy على المنفذين 80 و443، وهو يقرأ labels الـ Containers عبر Docker socket ويبني إعداداته منها تلقائياً، فإذا كانت قيمة SEAFILE_SERVER_PROTOCOL هي https فإنه يصدر شهادة Let's Encrypt للنطاق ويجددها Renewal بنفسه:
services:
caddy:
image: ${SEAFILE_CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.12-alpine}
restart: unless-stopped
container_name: seafile-caddy
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=seafile-net
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${SEAFILE_CADDY_VOLUME:-/opt/seafile-caddy}:/data/caddy
networks:
- seafile-net
healthcheck:
test: ["CMD-SHELL", "curl --fail http://localhost:2019/metrics || exit 1"]
start_period: 20s
interval: 20s
timeout: 5s
retries: 3
networks:
seafile-net:
name: seafile-netوالملف seadoc.yml يضيف خدمة SeaDoc، مع labels توجه إليها المسارين /sdoc-server/ و/socket.io/ عبر Caddy نفسه.
تشغيل الخدمات
الآن سوف نقوم بسحب الـ Images وتشغيل الخدمات:
cd /opt/seafile
sudo docker compose pull
sudo docker compose up -dينتظر الـ Container seafile حتى تصبح MariaDB سليمة، ثم ينشئ في التشغيل الأول قواعد البيانات الثلاث وحساب المدير، وتستطيع متابعة ذلك في السجل Log حتى تظهر الرسالة Seahub is started ثم Done.:
sudo docker logs -f seafileوبعد ذلك تأكد أن كل الخدمات تعمل:
sudo docker compose psالإعداد الأول بعد التثبيت
الدخول وتغيير كلمة المرور
افتح https://seafile.example.com، وادخل بالبريد وكلمة المرور اللذين وضعتهما في INIT_SEAFILE_ADMIN_EMAIL وINIT_SEAFILE_ADMIN_PASSWORD، ثم قم بتغيير كلمة المرور فوراً من صورة الحساب Avatar ثم Settings ثم Password، وبعد ذلك احذف القيمة المؤقتة من .env فلم تعد لها حاجة.

تنظيم الملفات في مكتبات
بعد الدخول سوف تظهر صفحة Files بثلاثة أقسام: مكتباتك، والمكتبات التي شاركها معك الآخرون، والمكتبات المشاركة مع الجميع، ولكل مستخدم مكتبة شخصية ينشئها Seafile تلقائياً باسم My Library.

والمكتبة هي الوحدة التي تتم عليها المزامنة والمشاركة والتشفير، ولذلك خطط لها بحسب طريقة عمل فريقك، فمكتبة لكل قسم أو مشروع أفضل من مكتبة واحدة ضخمة، والسبب أن المستخدم يختار المكتبات التي يزامنها على جهازه، وأن الصلاحيات تعطى على مستوى المكتبة أو المجلد. ولإنشاء مكتبة اضغط + ثم New Library:

وداخل المكتبة ترفع الملفات Upload بالسحب والإفلات، وتنشئ المجلدات، وتعاين ملفات Markdown والنصوص والصور وPDF مباشرة من المتصفح. ومن القائمة الجانبية تفتح History لتستعيد Restore أي نسخة سابقة من المكتبة، وTrash للملفات المحذوفة، وSettings لتحدد مدة الاحتفاظ بالإصدارات القديمة.

مشاركة الملفات داخل الفريق وخارجه
حدد ملفاً أو مجلداً ثم اضغط Share، ومن النافذة تستطيع أن تنشئ رابط مشاركة عاماً Share Link بكلمة مرور ومدة صلاحية Expiration، يسمح بالمعاينة فقط أو بالمعاينة والتنزيل، أو رابطاً داخلياً Internal Link لا يفتحه إلا من لديه صلاحية على المكتبة. وللمجلدات أيضاً رابط رفع Upload Link يرفع منه شخص من خارج النظام ملفات إليك دون أن يحتاج إلى حساب.

أما المشاركة داخل الفريق فتتم من قائمة المكتبة نفسها، حيث تشاركها مع مستخدم أو مع مجموعة Group، بصلاحية القراءة فقط أو القراءة والكتابة، وفي الفرق التي يتغير أعضاؤها باستمرار فإن المجموعات هي الطريقة العملية لإدارة الصلاحيات، والسبب أنك تضيف الموظف الجديد إلى المجموعة مرة واحدة بدلاً من أن تشارك معه كل مكتبة على حدة.
لوحة إدارة النظام Admin Panel
تفتح لوحة الإدارة من صورة الحساب ثم System Admin، وصفحة Info فيها تعرض الإصدار، وعدد المكتبات والملفات، والمساحة المستخدمة، وعدد الأجهزة المتصلة:

ومن Users ← Add User تنشئ حسابات الفريق، ومن صفحة كل مستخدم تحدد حصته من المساحة Quota، أو تعطيه صلاحية المدير:


ومن Settings في لوحة الإدارة تقوم بضبط اسم الموقع وشعاره، وتفعيل التسجيل الذاتي Self-Registration أو إيقافه، وتحديد قواعد كلمات المرور. وإذا كان لديك نظام دخول موحد SSO مثل Authentik فاربط Seafile به عبر OAuth من ملف seahub_settings.py، فيدخل الموظف بحسابه المعتاد، ويغلق حسابه في مكان واحد عندما يترك العمل.
إعداد البريد
يرسل Seafile رسائل إعادة تعيين كلمة المرور وإشعارات المشاركة، وبدون بريد لن يستطيع المستخدم أن يستعيد كلمة مروره بنفسه، ولذلك أضف إعدادات SMTP في آخر الملف /opt/seafile-data/seafile/conf/seahub_settings.py:
sudo nano /opt/seafile-data/seafile/conf/seahub_settings.pyEMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.example.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'SMTP_PASSWORD'
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USERثم أعد تشغيل الخدمة حتى تقرأ الإعدادات الجديدة:
cd /opt/seafile
sudo docker compose restart seafileوإذا كنت تدير بريدك بنفسك فراجع دليل mailcow لتنشئ صندوق بريد مخصصاً للإرسال.
تثبيت عميل المزامنة على الأجهزة والهواتف
في Clients بالقائمة الجانبية سوف تجد روابط عميل Seafile لسطح المكتب Desktop وتطبيقات iOS وAndroid، وهي أيضاً في صفحة التنزيل الرسمية. وعندما تضيف الحساب في العميل اكتب عنوان السيرفر كاملاً https://seafile.example.com، ثم البريد وكلمة المرور، واختر المكتبات التي تريد مزامنتها. وإذا كنت تريد أن تظهر الملفات على شكل قرص شبكي Network Drive دون أن تنزلها كلها على الجهاز، فاستخدم تطبيق SeaDrive لنظامي Windows وmacOS، وهو مناسب للأجهزة ذات المساحة الصغيرة.
تفعيل WebDAV
تحتاج إلى WebDAV للتطبيقات التي لا تدعم عميل Seafile، مثل بعض تطبيقات الهاتف أو برامج النسخ الاحتياطي Backup. وفي النشر Deployment عبر Docker يكون المسار /seafdav جاهزاً داخل الـ Container، ولكن الخدمة نفسها معطلة افتراضياً في الملف seafdav.conf، ولذلك يكفي أن تقوم بتفعيلها ثم تعيد التشغيل:
sudo sed -i 's/^enabled = false/enabled = true/' /opt/seafile-data/seafile/conf/seafdav.conf
cd /opt/seafile
sudo docker compose restart seafileبعد ذلك اتصل من أي عميل WebDAV بالعنوان https://seafile.example.com/seafdav/ ببريدك وكلمة مرورك، وللتحقق من الطرفية Terminal نفذ الأمر التالي:
curl -s -u [email protected] -X PROPFIND -H "Depth: 1" https://seafile.example.com/seafdav/ -o /dev/null -w '%{http_code}\n'والمخرج سوف يكون 207، وهذا يعني أن الخدمة تعمل، وسوف تظهر المكتبات في عميل WebDAV على شكل مجلدات. ولاحظ أن Seafile 13 لا يقبل في WebDAV تسجيل الدخول بحساب LDAP لأسباب أمنية، كما تذكر ملاحظات الترقية، فإذا كان فريقك يدخل عبر LDAP فسوف يحتاج كل مستخدم إلى إنشاء رمز WebDAV خاص به من صفحة حسابه.
ربط النطاق وإصدار شهادة TLS
ترك Caddy المرفق يصدر الشهادة بنفسه
إذا كان السيرفر مخصصاً لـ Seafile فإن الإعداد الذي كتبناه في .env (SEAFILE_SERVER_PROTOCOL=https مع caddy.yml) يكفي، حيث يستمع Caddy على المنفذين 80 و443، ويصدر شهادة Let's Encrypt للنطاق seafile.example.com عند أول طلب، ثم يجددها تلقائياً، وكل ما عليك هو أن تتأكد قبل التشغيل أن السجل A يشير إلى السيرفر، والسبب أن Let's Encrypt يتحقق من ملكيتك للنطاق عبر HTTP (HTTP Challenge) على المنفذ 80. وإذا لم تصدر الشهادة فراجع سجل Caddy:
sudo docker logs --tail=50 seafile-caddyإذا كان لديك Reverse Proxy يعمل مسبقاً
إذا كان المنفذان 80 و443 مشغولين بـ Reverse Proxy لديك مثل Nginx Proxy Manager، فلا تقم بتشغيل Caddy بجانبه، والسبب أن الاثنين سوف يتنافسان على المنفذين نفسيهما ولن يبدأ أحدهما، وبدلاً من ذلك اجعل NPM يصل إلى الـ Containers عبر الشبكة seafile-net، كما يشرح التوثيق الخاص بأنواع Reverse Proxy الأخرى. ابدأ بحذف caddy.yml من COMPOSE_FILE في .env، وأبق البروتوكول https لأنه العنوان الذي يراه المستخدمون في المتصفح:
COMPOSE_FILE='seafile-server.yml,seadoc.yml'
SEAFILE_SERVER_PROTOCOL=httpsثم أوقف Caddy وأعد إنشاء بقية الـ Containers:
cd /opt/seafile
sudo docker compose up -d --remove-orphansبعد ذلك اربط NPM بالشبكة من ملف Compose الخاص به:
services:
app:
networks:
- default
- seafile-net
networks:
seafile-net:
external: trueوالآن أنشئ في NPM مضيفاً من نوع Proxy Host للنطاق seafile.example.com يوجه إلى http://seafile:80، وفعل Websockets Support وForce SSL، واطلب شهادة Let's Encrypt، ثم أضف في تبويب Advanced توجيه Routing المسارات الخاصة بـ SeaDoc وحد حجم الرفع Upload Size Limit:
client_max_body_size 0;
location /sdoc-server/ {
proxy_pass http://seadoc:80/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /socket.io {
proxy_pass http://seadoc:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}في الإعداد أعلاه لاحظ أن التوجيه Directive client_max_body_size 0 يلغي حد حجم الطلب في Nginx، وبدونه يفشل رفع الملفات الكبيرة من المتصفح بالخطأ 413، وأن المسار /socket.io يحتاج إلى ترقية الاتصال إلى WebSocket، ولذلك فيه السطران Upgrade وConnection.
كيف تتأكد أن كل شيء يعمل؟
- الشهادة صالحة، فالأمر
curl -sI https://seafile.example.com/accounts/login/يعيد الرمز200دون أي خطأ في الشهادة. - ارفع ملفاً كبيراً بحجم مئات الميغابايتات من المتصفح، ثم زامن مكتبة من عميل سطح المكتب، وعدل ملفاً فيها، وتأكد أن التعديل يظهر في الويب وفي History.
- أنشئ رابط مشاركة وافتحه من نافذة تصفح خاصة Private Window، حتى ترى ما يراه شخص من خارج الفريق.
واجهة API تعيد رقم الإصدار:
curl -s https://seafile.example.com/api2/server-info/والمخرج المتوقع يتضمن "version": "13.0.28".
كل الـ Containers تعمل، وseafile وseafile-mysql بحالة healthy:
cd /opt/seafile
sudo docker compose psالنسخ الاحتياطي والاستعادة
قد يبدو من الوهلة الأولى أن عميل المزامنة نفسه نسخة احتياطية، فالملفات موجودة على السيرفر وعلى أجهزة الفريق، ولكن في الواقع فهو غير ذلك، فالمزامنة تنقل الحذف والتعديل الخاطئ والملف المشفر من برنامج فدية Ransomware إلى كل الأجهزة كما تنقل التعديل الصحيح، ولذلك تحتاج إلى نسخة احتياطية مستقلة عن Seafile نفسه.
وفي Seafile جزءان يجب أن تنسخهما معاً: الأول هو قواعد البيانات الثلاث، أي ccnet_db للمستخدمين والمجموعات، وseafile_db للمكتبات، وseahub_db للواجهة والروابط، والثاني هو مجلد البيانات /opt/seafile-data وفيه أجزاء الملفات والإعدادات.
والترتيب هنا مهم، حيث يوصي التوثيق بأن تنسخ قاعدة البيانات أولاً ثم مجلد البيانات، والسبب أن كل سجل في قاعدة البيانات سوف يجد الأجزاء التي يشير إليها في مجلد البيانات، وأما الأجزاء الجديدة التي يكتبها Seafile أثناء النسخ فلا تضر، ولو عكست الترتيب فقد تحصل على قاعدة بيانات تشير إلى أجزاء غير موجودة في النسخة فتتلف المكتبات عند الاستعادة. والأوامر التالية تنسخ القواعد الثلاث:
sudo mkdir -p /opt/backup/seafile
cd /opt/backup/seafile
for db in ccnet_db seafile_db seahub_db; do
sudo docker exec seafile-mysql sh -c "mariadb-dump -uroot -p\"\$MYSQL_ROOT_PASSWORD\" --opt --single-transaction $db" | sudo tee "$db-$(date +%F).sql" >/dev/null
doneثم انسخ مجلد البيانات نسخاً تزايدياً Incremental Backup، ومعه ملفات Compose و.env:
sudo rsync -a --delete /opt/seafile-data/ /opt/backup/seafile/seafile-data/
sudo cp /opt/seafile/.env /opt/seafile/*.yml /opt/backup/seafile/ضع أوامر نسخ قواعد البيانات في سكربت Script تشغله المهام المجدولة Cron Jobs يومياً، وانقل /opt/backup/seafile إلى تخزين خارج السيرفر Offsite Storage، والسبب أن نسخة على السيرفر نفسه تضيع معه إذا تعطل القرص أو اخترق السيرفر، وأدوات مثل restic تناسب هذه المهمة لأنها لا تنقل إلا الأجزاء التي تغيرت.
الاستعادة على سيرفر جديد تتم بالترتيب التالي: ضع ملفات Compose و.env في /opt/seafile، والبيانات في /opt/seafile-data، ثم شغل قاعدة البيانات وحدها وانتظر حتى تصبح سليمة، واستورد Import القواعد الثلاث، ثم أنشئ المستخدم seafile بكلمة المرور الموجودة في .env، والسبب أن ملفات النسخ تحمل الجداول فقط ولا تحمل مستخدمي MariaDB، فإذا تجاوزت هذه الخطوة فسوف يبدأ Seafile ولكن كل طلب إليه يفشل بخطأ داخلي، وبعد ذلك شغل كل الخدمات:
cd /opt/seafile
sudo docker compose up -d --wait db
for db in ccnet_db seafile_db seahub_db; do
sudo docker exec seafile-mysql sh -c "mariadb -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -e 'CREATE DATABASE IF NOT EXISTS $db CHARACTER SET utf8mb4'"
sudo docker exec -i seafile-mysql sh -c "mariadb -uroot -p\"\$MYSQL_ROOT_PASSWORD\" $db" < /opt/backup/seafile/$db-2026-09-26.sql
done
DB_PASS=$(sudo grep '^SEAFILE_MYSQL_DB_PASSWORD=' .env | cut -d= -f2-)
sudo docker exec seafile-mysql sh -c "mariadb -uroot -p\"\$MYSQL_ROOT_PASSWORD\" -e \"CREATE USER IF NOT EXISTS 'seafile'@'%' IDENTIFIED BY '$DB_PASS'; GRANT ALL PRIVILEGES ON ccnet_db.* TO 'seafile'@'%'; GRANT ALL PRIVILEGES ON seafile_db.* TO 'seafile'@'%'; GRANT ALL PRIVILEGES ON seahub_db.* TO 'seafile'@'%';\""
sudo docker compose up -dضع مكان التاريخ اسم ملفات النسخة التي تستعيدها، وبعد الاستعادة شغل فحص السلامة Integrity Check لتتأكد أن المكتبات متسقة، لأن قاعدة البيانات والملفات نسخت في وقتين مختلفين:
sudo docker exec seafile /opt/seafile/seafile-server-latest/seaf-fsck.shsudo docker exec seafile /opt/seafile/seafile-server-latest/seaf-gc.sh، وأضف الخيار --dry-run لترى ما سوف يحذفه دون أن يحذف شيئاً.التحديث إلى إصدار أحدث Upgrade
التحديث داخل السلسلة نفسها بسيط، مثل الانتقال من 13.0.28 إلى إصدار أحدث من 13.0، فتأخذ نسخة احتياطية، وتغير الوسم في .env، وتسحب الـ Image الجديدة، وتعيد التشغيل، وعند الإقلاع يشغل الـ Container سكربتات ترقية قاعدة البيانات تلقائياً:
cd /opt/seafile
sudo sed -i 's|^SEAFILE_IMAGE=.*|SEAFILE_IMAGE=seafileltd/seafile-mc:13.0.30|' .env
sudo docker compose pull
sudo docker compose up -d
sudo docker logs -f seafileضع مكان 13.0.30 الإصدار المستقر Stable الذي تريده من صفحة الوسوم على Docker Hub، ولا تستخدم الوسوم المنتهية بـ -testing لأنها إصدارات تجريبية لم تعتمد بعد، وهذا ينطبق اليوم على وسوم 14.0 أيضاً. وحدث sdoc-server بالطريقة نفسها بحسب جدول التوافق Compatibility في ملاحظات الإصدار.
أما الانتقال بين الإصدارات الرئيسية Major Versions، من 12.0 إلى 13.0 أو لاحقاً إلى 14.0، فيحتاج إلى خطوات إضافية تشرحها صفحة الترقية الرسمية لكل إصدار، ففي الانتقال إلى 13.0 مثلاً تنزل ملفات YAML الجديدة، وتضيف إلى .env متغيرات قاعدة البيانات والتخزين المؤقت (CACHE_PROVIDER مع Redis أو Memcached) وJWT_PRIVATE_KEY، ثم تحذف الأقسام المكررة من ملفات الإعداد القديمة مثل [database] و[memcached] من seafile.conf وDATABASES وCACHES من seahub_settings.py، والسبب أن الإعداد صار يأتي من متغيرات البيئة.
لكن تذكر: لا تتخط أي إصدار رئيسي، وجرب الترقية على نسخة من البيانات قبل أن تطبقها على بيئة الإنتاج Production، لأن الترقية تغير جداول قاعدة البيانات ولا رجوع عنها إلا من النسخة الاحتياطية.
مشكلات شائعة وحلولها
الـ Container يتوقف بالخطأ is not a valid ip or domain
والسبب أن قيمة SEAFILE_SERVER_HOSTNAME فيها رقم منفذ، أو http://، أو اسم دون نقطة مثل localhost، والحل أن تصححها إلى اسم نطاق كامل FQDN. وإذا كانت هذه أول محاولة تشغيل ولم تكتمل التهيئة، فاحذف مجلدي البيانات /opt/seafile-data و/opt/seafile-mysql ثم شغل من جديد، ولا تقم بذلك أبداً على سيرفر فيه بيانات حقيقية.
خطأ CSRF أو روابط تنزيل خاطئة
يظهر هذا الخطأ عندما يختلف العنوان الذي يفتحه المستخدم عن SEAFILE_SERVER_PROTOCOL وSEAFILE_SERVER_HOSTNAME، مثلاً يفتح المستخدم الموقع عبر HTTPS بينما البروتوكول في .env هو http، والحل أن تجعل القيمتين مطابقتين للعنوان العام تماماً، ثم تنفذ docker compose up -d.
رفع الملفات الكبيرة يفشل
الخطأ 413 Request Entity Too Large يأتي من الـ Reverse Proxy، وحله أن تضيف client_max_body_size 0; في إعداد Nginx أو NPM. وإذا انقطع الرفع بعد دقيقة تقريباً فهناك مهلة Timeout قصيرة في الـ Reverse Proxy أو في جدار حماية Firewall مثل Cloudflare، والحل أن ترفع مهلة القراءة، أو أن تستخدم عميل المزامنة للملفات الضخمة لأنه يرفعها أجزاء.
SeaDoc لا يفتح المستندات
تحقق أن ENABLE_SEADOC=true، وأن المسارين /sdoc-server/ و/socket.io يصلان إلى الـ Container seadoc، فمع Caddy يحدث هذا تلقائياً، ومع أي Reverse Proxy آخر تقوم بإعداده يدوياً. وتحقق أيضاً أن قيمة JWT_PRIVATE_KEY واحدة في الخدمتين، ولقراءة سجل الخدمة نفذ sudo docker logs --tail=50 seadoc.
Seafile لا يتصل بقاعدة البيانات بعد تغيير كلمة المرور
تحفظ MariaDB كلمة مرور المستخدم seafile منذ التهيئة الأولى، فإذا غيرت SEAFILE_MYSQL_DB_PASSWORD في .env فيجب أن تغيرها في قاعدة البيانات أيضاً بالأمر ALTER USER 'seafile'@'%' IDENTIFIED BY '…'; من داخل الـ Container seafile-mysql.
المساحة لا تنخفض بعد حذف الملفات
وهذا أمر متوقع، فالأجزاء المحذوفة تبقى حتى يعمل جامع المهملات seaf-gc.sh، والإصدارات القديمة تبقى بحسب مدة الاحتفاظ المحددة في إعدادات كل مكتبة، ولذلك قلل المدة في المكتبات التي تتغير ملفاتها كثيراً، وشغل جامع المهملات دورياً.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- المجلد المشترك على الشبكة لا يعطيك مزامنة ولا سجل إصدارات، وSeafile يعطي فريقك تجربة قريبة من Dropbox والملفات على سيرفرك، وهو أخف من Nextcloud إذا كانت حاجتك هي الملفات فقط.
- ثبت كل Docker Image على إصدار محدد في
.env، واجعلSEAFILE_SERVER_HOSTNAMEوSEAFILE_SERVER_PROTOCOLمطابقين للعنوان العام تماماً، ولا تغيرJWT_PRIVATE_KEYوكلمة مرور قاعدة البيانات بعد التشغيل الأول. - استخدم Caddy المرفق إذا كان السيرفر لـ Seafile وحده، وإذا كان لديك Reverse Proxy فاحذف
caddy.ymlووجه المسارات الخاصة بـ SeaDoc يدوياً. - كلمة مرور المكتبة المشفرة لا يمكن استرجاعها، فاحفظها في مدير كلمات المرور.
- المزامنة ليست نسخة احتياطية: انسخ قواعد البيانات أولاً ثم مجلد البيانات، وانقل النسخة خارج السيرفر، وعند الاستعادة أنشئ المستخدم
seafileفي MariaDB ثم شغلseaf-fsck.sh.
سجل التحديثات
- سبتمبر 2026: كتابة الدليل واختباره على Seafile 13.0.28.
- أكتوبر 2026: مراجعة الدليل وإعادة اختباره على Seafile 13.0.28، وإضافة خطوة إنشاء المستخدم
seafileوانتظار MariaDB إلى الاستعادة على سيرفر جديد، وملاحظة تسجيل الدخول بحساب LDAP في WebDAV، وتفاصيل الترقية من 12.0 إلى 13.0.