لنفرض أن مطوراً في فريقك أمضى يوماً كاملاً حتى عرف لماذا يفشل النشر Deployment على سيرفر الإنتاج، ثم كتب الحل في رسالة على المحادثات أو في ملف على جهازه، فسوف تجد بعد ستة أشهر أن المشكلة نفسها عادت، وأن من يواجهها اليوم لا يعرف أين كتب الحل، أو أن صاحبه غادر الشركة وأخذ هذه المعرفة معه. والحل الأول الذي يخطر على البال هو مجلد مشترك فيه ملفات Word أو Markdown، وهذا الحل يعمل في الأسبوع الأول، ولكنه يفشل بسرعة لأن البحث Search فيه ضعيف، ولا يعرف أحد أي نسخة من الملف هي الأحدث، ولا يستطيع شخصان تعديل الملف نفسه في الوقت نفسه. والحل الثاني هو الويكي المدمج في مستودع الكود على Gitea أو GitHub، وهو مناسب لتوثيق الكود، ولكنه غير مناسب لفريق الدعم أو الموارد البشرية الذين لا يستخدمون Git أصلاً.
لذلك فالحل الأنسب هو ويكي داخلي Wiki يجمع إجراءات النشر وقرارات التصميم وخطوات استقبال الموظف الجديد Onboarding وحلول المشكلات التي تتكرر كل شهر في مكان واحد يبحث فيه الجميع. ومن الخيارات المعروفة التي تثبتها على سيرفرك BookStack وWiki.js، وهما مفتوحا المصدر Open Source، وOutline الذي يتناوله هذا الدليل، حيث تكتب فيه بمحرر Editor سريع يدعم Markdown، ويعدل عدة أشخاص المستند نفسه في اللحظة نفسها Real-time Collaboration، وتنتظم المستندات في مجموعات Collections لكل منها صلاحياتها Permissions، وفيه بحث فوري وقوالب Templates وتعليقات Comments، وتستطيع مشاركة مستند واحد عبر رابط، وله واجهة API كاملة.
ولاحظ أن Outline ليس مفتوح المصدر بالمعنى الدقيق، فالكود متاح على GitHub ولكنه منشور برخصة Business Source License 1.1 واختصاراً BSL، وهذه الرخصة تسمح لك بتثبيته واستخدامه داخل مؤسستك لموظفيك والمتعاقدين معك، ولكنها تمنع أن تقدمه خدمة مستندات تجارية Document Service لجهات أخرى تنشئ فيه فرقها ومستنداتها، وكل إصدار يتحول إلى رخصة Apache 2.0 بعد تاريخ تحدده الرخصة نفسها، وهو للإصدار 1.10.1 يوم 9 سبتمبر 2030. فإذا كان الويكي لفريقك فلا توجد مشكلة، وإذا كنت تريد تقديمه لعملائك فاقرأ الرخصة أولاً.
وقد يتساءل البعض: لماذا يأتي هذا الدليل بعد authentik، ولماذا لا أنشئ حسابات بكلمات مرور داخل Outline نفسه؟ والإجابة أن Outline لا يملك نظام كلمات مرور Passwords خاصاً به، حيث يدخل المستخدم عبر مزود هوية Identity Provider من نوع OIDC أو Google أو Microsoft أو Slack، أو عبر رابط يصل إلى بريده Magic Link إذا كان حسابه موجوداً مسبقاً، لذلك سوف نستخدم authentik الذي ثبتناه في دليل تثبيت authentik مزوداً للهوية، وأما إذا احتاج فريقك إلى ويكي بكلمات مرور محلية دون مزود هوية فإن BookStack أو Wiki.js أنسب له.
وسوف نناقش في هذا المقال ما يلي:
- إعداد التطبيق والـ Provider في authentik، ولماذا يحتاج Outline إلى ربط خاص للبريد يرسل
email_verified. - تثبيت Outline باستخدام Docker Compose مع PostgreSQL وRedis، وشرح الأسطر المهمة في الملف.
- ربط النطاق مع TLS وWebSocket، ثم الدخول الأول، وأول مجموعة ومستند، وإعدادات المدير.
- تخزين المرفقات على قرص السيرفر أو على خدمة متوافقة مع S3.
- النسخ الاحتياطي والاستعادة، والتحديث إلى إصدار أحدث، وأشهر المشكلات وحلولها.
ما تحتاجه قبل أن تبدأ Requirements
- سيرفر Linux بمعالجين 2 vCPU وذاكرة RAM بحجم 2 GB على الأقل، والسبب أن Outline نفسه يحتاج إلى 512 MB كحد أدنى وينصح توثيقه بـ 1 GB أو أكثر بحسب عدد المستخدمين، ثم يأخذ PostgreSQL وRedis نصيبهما من الذاكرة أيضاً. ويتطلب Outline قاعدة PostgreSQL من الإصدار 14 فأحدث وRedis من الإصدار 4 فأحدث، ونستخدم في هذا الدليل PostgreSQL 17 وRedis 8.
- Docker Engine مع Compose v2، وإذا لم يكن مثبتاً فاتبع دليل تثبيت Docker أولاً.
- نطاق فرعي Subdomain مثل
wiki.example.comيشير إلى السيرفر، وReverse Proxy يصدر شهادة TLS Certificate ويدعم WebSocket مثل Nginx Proxy Manager، والسبب أن التحرير الجماعي كله يمر عبر WebSocket. - سيرفر authentik على
https://auth.example.com، ويجب أن يصل إليه الـ Container الخاص بـ Outline، والسبب أن Outline يطلب التوكن Token من authentik مباشرة من السيرفر وليس عبر متصفح المستخدم. - حساب SMTP لإرسال الإشعارات Notifications والدعوات ورسائل الدخول بالبريد، وهو اختياري ولكننا ننصح به، والسبب أن الدخول بالبريد وإشعارات التعديلات لا تعمل بدونه.
نبدأ من authentik
سوف نبدأ بـ authentik، والسبب أن Outline يحتاج إلى معرف العميل Client ID والسر Client Secret قبل أن يعمل، وهما لا يظهران إلا بعد إنشاء الـ Provider.
لماذا يحتاج البريد إلى ربط خاص فيه email_verified؟
يرسل authentik مع نطاق Scope البريد email قيمة email_verified، ومنذ الإصدار 2025.10 صارت هذه القيمة في الربط الافتراضي false، والسبب أن authentik لا يملك مصدراً واحداً يعرف منه هل تحقق المستخدم من بريده أم لا. والمشكلة أن Outline يرفض الدخول ببريد غير مؤكد في حالتين: إذا كان لهذا البريد حساب موجود مسبقاً في Outline، مثل زميل دعوته بالبريد، أو إذا حددت نطاقات مسموحة Allowed Domains في الإعدادات كما سوف نفعل لاحقاً، وعندها يعرض رسالة تقول إن البريد لم يتم التحقق منه. لذلك أنشئ ربطاً جديداً للنطاق Scope Mapping من Customization ← Property Mappings ← Create ← Scope Mapping:
- Name:
OAuth Mapping: OpenID email with email_verified - Scope name:
email - Expression:
return {
"email": request.user.email,
"email_verified": True,
}وبهذا الإعداد تثق بالبريد المسجل في authentik كما هو، وهذا مناسب إذا كان المديرون Admins وحدهم ينشئون الحسابات، أو كانت الحسابات تأتي من Google Workspace. أما إذا كان التسجيل الذاتي Self-registration مفتوحاً في authentik فلا تقم بإرسال True ثابتة، والسبب أن Outline يربط البريد المؤكد بالحساب الموجود الذي يحمل البريد نفسه، فيستطيع من يسجل ببريد زميلك أن يدخل إلى حساب زميلك في الويكي، والحل أن ترسل قيمة تحفظها بعد التحقق الفعلي من البريد كما يشرح توثيق authentik.
إنشاء التطبيق Application والـ Provider
من Applications ← New Application أدخل الاسم Outline والـ slug outline، ثم اختر OAuth2/OpenID Provider واضبطه كما يلي:
- Authorization Flow:
default-provider-authorization-implicit-consent. - Client Type: Confidential. احفظ Client ID والسر.
- Grant Types: أبق Authorization Code وRefresh token مفعلين.
- Redirect URIs:
StrictوAuthorizationوالعنوانhttps://wiki.example.com/auth/oidc.callback. - Signing Key:
authentik Self-signed Certificate.
واخترنا المطابقة Strict لأن authentik يقبل عندها عنوان العودة الذي يطابق المسجل حرفياً فقط، فلا يستطيع أحد أن يوجه رمز الدخول إلى عنوان آخر يملكه، والمسار /auth/oidc.callback ثابت في Outline، ويبنيه من قيمة URL التي سوف نضعها في ملف Compose.

ثم في Advanced protocol settings:
- Subject Mode: Based on the User's username.
- Selected Scopes:
openidوprofileوالـ mapping الذي أنشأته للبريد، واحذف الـ mapping الافتراضيauthentik default OAuth Mapping: OpenID 'email'، والسبب أن الاثنين يرسلان النطاقemailنفسه فيتعارضان.

وإذا أردت أن يقتصر الويكي على موظفين محددين، فاربط بالتطبيق مجموعة Group مثل employees من تبويب Policy / Group / User Bindings، وبالتالي يرفض authentik دخول من ليس فيها قبل أن يصل إلى Outline أصلاً.
تثبيت Outline خطوة بخطوة
المجلد وملف .env والأسرار Secrets
سوف نضع كل ما يخص Outline في مجلد واحد، فيسهل نسخه احتياطياً ونقله إلى سيرفر آخر:
sudo mkdir -p /opt/outline
cd /opt/outlineثم ننشئ ملف .env بالأسرار، ونضع فيه Client ID والسر اللذين حفظتهما من authentik:
cat > .env <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
SECRET_KEY=$(openssl rand -hex 32)
UTILS_SECRET=$(openssl rand -hex 32)
OIDC_CLIENT_ID=الصق-معرف-العميل
OIDC_CLIENT_SECRET=الصق-السر
SMTP_PASSWORD=change-me
EOF
chmod 600 .envيستخدم Outline المفتاح SECRET_KEY لتشفير Encryption بيانات حساسة داخل قاعدة البيانات Database، ويطلبه بصيغة hex بطول 32 بايت، ولهذا نولده بالأمر openssl rand -hex 32. ولا تقم بتغييره بعد التشغيل، والسبب أنك إذا غيرته أو فقدته فلن يستطيع Outline قراءة تلك البيانات مرة أخرى، لذلك احفظه مع النسخة الاحتياطية Backup. أما UTILS_SECRET فهو مفتاح ثان يطلبه Outline، وتكفيه أي قيمة عشوائية طويلة.
ملف docker-compose.yml
وملف Compose كما يلي، وفيه ثلاث خدمات هي Outline وPostgreSQL وRedis:
services:
outline:
image: outlinewiki/outline:1.10.1
restart: unless-stopped
environment:
NODE_ENV: production
URL: https://wiki.example.com
PORT: "3000"
SECRET_KEY: ${SECRET_KEY:?}
UTILS_SECRET: ${UTILS_SECRET:?}
DEFAULT_LANGUAGE: en_US
# قاعدة البيانات وRedis على شبكة Compose الداخلية
DATABASE_URL: postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline
PGSSLMODE: disable
REDIS_URL: redis://redis:6379
# الملفات المرفقة على القرص
FILE_STORAGE: local
FILE_STORAGE_LOCAL_ROOT_DIR: /var/lib/outline/data
FILE_STORAGE_UPLOAD_MAX_SIZE: "262144000"
# TLS ينتهي عند الوكيل العكسي
FORCE_HTTPS: "false"
# تسجيل الدخول عبر authentik
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
OIDC_AUTH_URI: https://auth.example.com/application/o/authorize/
OIDC_TOKEN_URI: https://auth.example.com/application/o/token/
OIDC_USERINFO_URI: https://auth.example.com/application/o/userinfo/
OIDC_LOGOUT_URI: https://auth.example.com/application/o/outline/end-session/
OIDC_USERNAME_CLAIM: preferred_username
OIDC_DISPLAY_NAME: authentik
OIDC_SCOPES: openid profile email
# البريد
SMTP_HOST: smtp.example.com
SMTP_PORT: "587"
SMTP_USERNAME: [email protected]
SMTP_PASSWORD: ${SMTP_PASSWORD}
SMTP_FROM_EMAIL: [email protected]
SMTP_SECURE: "false"
ENABLE_UPDATES: "false"
ports:
- "127.0.0.1:3000:3000"
volumes:
- data:/var/lib/outline/data
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- default
- proxy
postgres:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_USER: outline
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: outline
volumes:
- db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U outline -d outline"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:8.8.3-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 10
volumes:
data:
db:
redis:
networks:
proxy:
external: trueفي الإعداد أعلاه لاحظ التالي:
- ربطنا المنفذ Port رقم 3000 بالعنوان
127.0.0.1، والسبب أن Docker يتجاوز جدار الحماية Firewall عند نشر المنافذ، فلا يصل إلى Outline من الخارج إلا الـ Reverse Proxy الذي ينضم معه إلى الشبكة المشتركةproxy. - Redis ما زال إلزامياً في Outline، حيث يشترطه التوثيق ويستخدمه للطوابير Queues والتخزين المؤقت Cache، ولا تشبه الحالة هنا authentik الذي تخلى عن Redis، لذلك لا تحذف خدمة redis من الملف.
FORCE_HTTPS: "false"لأن TLS ينتهي عند الـ Reverse Proxy، والقيمة الافتراضيةtrueتجعل Outline يحول الطلبات إلى https بنفسه، وملف الإعدادات النموذجي يسمح بتعطيلها عندما تكون متأكداً أن TLS ينتهي قبله.- كتبنا عناوين OIDC الأربعة يدوياً كما في توثيق authentik، ويدعم Outline أيضاً المتغير
OIDC_ISSUER_URLليكتشفها وحده من/.well-known/openid-configurationكما يشرح توثيق OIDC في Outline، ولكن العناوين الصريحة أوضح عند تتبع الأخطاء. OIDC_LOGOUT_URIهو العنوان الذي يحول إليه Outline المستخدم عند تسجيل الخروج فتنتهي جلسته في authentik أيضاً، وفيه slug التطبيقoutline، ويطلب توثيق Outline أن تضبطه أو تضبطOIDC_DISABLE_REDIRECT، والسبب أن المستخدم بدونه يضغط زر الخروج فيجد نفسه داخل Outline مرة أخرى لأن جلسته في authentik ما زالت قائمة.SMTP_SECURE: "false"مع المنفذ 587 يعني STARTTLS، أي أن الاتصال يبدأ عادياً ثم يرقيه Outline إلى TLS، ومع المنفذ 465 اجعل القيمة"true"، ولاحظ أن القيمة الافتراضية في بيئة الإنتاجtrue، فإذا تركتها مع المنفذ 587 فسوف يفشل الاتصال.ENABLE_UPDATES: "false"يمنع Outline من إرسال إحصاءات مجهولة الهوية إلى المطورين ليتحقق من وجود إصدار جديد، فإذا أردت أن ترى حالة التحديث في الإعدادات فاتركهtrue.- لا يوجد فحص صحة Health Check لخدمة outline في الملف، والسبب أن الـ Image الرسمية فيها فحص مدمج على المسار
/_healthكل دقيقة، فلا تضف فحصاً آخر.
التشغيل ومتابعة السجلات Logs
الآن سوف نقوم بإنشاء شبكة proxy مرة واحدة إن لم تكن موجودة من تثبيت الـ Reverse Proxy، ثم نشغل الخدمات ونتابع سجل Outline:
docker network create proxy
docker compose up -d
docker compose logs -f outlineوفي التشغيل الأول ينفذ Outline ترحيلات قاعدة البيانات Migrations وحده، فترى في السجل السطر Running migrations… ثم OIDC plugin registered، وهذا يعني أن متغيرات OIDC قرئت كاملة، فإذا لم يظهر هذا السطر فلن ترى زر authentik في صفحة الدخول. وفي الإصدارات القديمة كانت الترحيلات تحتاج إلى أمر منفصل هو yarn db:migrate، ولم يعد ذلك لازماً لأن الترحيلات تعمل تلقائياً عند بدء الـ Container. وللتحقق نفذ:
curl -s http://127.0.0.1:3000/_healthوالمخرج سوف يكون OK، وبعد دقيقة تقريباً تظهر خدمة outline في docker compose ps بحالة healthy.
ربط النطاق Domain وشهادة TLS
في Nginx Proxy Manager أنشئ مضيفاً Proxy Host للنطاق wiki.example.com يوجه إلى الـ Container المسمى outline على المنفذ 3000، وفعل Websockets Support، والسبب أن التحرير الجماعي لا يعمل بدونه، واختر شهادة Let's Encrypt مع Force SSL، ثم أضف في الإعداد المتقدم السطر التالي حتى يقبل الـ Reverse Proxy مرفقات بالحجم الذي حددناه في FILE_STORAGE_UPLOAD_MAX_SIZE:
client_max_body_size 250m;وإذا كنت تستخدم Caddy فهذا كل ما تحتاجه، لأنه يمرر WebSocket تلقائياً:
wiki.example.com {
reverse_proxy outline-outline-1:3000
}ويجب أن تطابق قيمة URL في ملف Compose العنوان العام حرفياً، والسبب أن Outline يبني منها عنوان العودة callback الذي يرسله إلى authentik، فإذا اختلف حرف واحد رفض authentik الطلب.
الدخول الأول
افتح https://wiki.example.com/، ولن ترى نموذج تسجيل Sign-up Form، وإنما زر «Continue with authentik» الذي يأخذ اسمه من OIDC_DISPLAY_NAME:

وعند الضغط عليه ينقلك إلى authentik مع عبارة «Log in to continue to Outline»، فأدخل كلمة المرور واجتز المصادقة الثنائية 2FA كالمعتاد:

وأول من يدخل ينشئ مساحة العمل Workspace ويصبح مديرها Admin، ويجد فيها مجموعة Welcome بمستندات تعريفية، لذلك احرص على أن تكون أنت أول من يدخل بعد التشغيل مباشرة، ولا تقم بنشر الرابط للفريق قبل ذلك.

أول مجموعة وأول مستند
أنشئ من New collection مجموعة لكل فريق أو مجال، مثل Engineering، وحدد من يقرؤها ومن يعدلها، ثم اضغط New doc واكتب كما تكتب في Markdown، أي ## للعناوين Headings و1. للقوائم Lists، وتستطيع سحب الصور إلى المحرر مباشرة، حيث يحفظ Outline المرفقات في الـ Volume data تحت /var/lib/outline/data/uploads/:

إعدادات المدير الأساسية
افتح Settings من صورة حسابك، وأول ما سوف تعدله الأقسام التالية:
- Authentication: يظهر authentik بحالة «Connected». أضف نطاق مؤسستك
example.comفي Allowed domains، والسبب أن Outline عندها لا ينشئ حساباً لبريد من خارج هذا النطاق حتى لو سمح به authentik، وتستطيع أيضاً تعطيل الدخول بالبريد إذا أردت أن يمر الجميع عبر authentik وحده. - Security: اختر الصلاحية الافتراضية للأعضاء الجدد Editor أو Viewer، وقرر هل تسمح بالمشاركة العامة Public Sharing للمستندات، وغالب الظن أنك لا تريد أن يشارك أحد إجراءات الإنتاج برابط عام.
- Users وGroups: امنح دور Admin لمن تريد، وأنشئ مجموعات مستخدمين وامنحها صلاحيات على المجموعات Collections.

تخزين المرفقات على S3 (اختياري)
التخزين المحلي Local Storage يكفي لسيرفر واحد، وأما إذا أردت حفظ المرفقات Attachments في خدمة متوافقة مع S3 مثل AWS S3 أو Cloudflare R2 أو سيرفر MinIO أو Garage لديك، فاستبدل قسم الملفات في ملف Compose بما يلي:
FILE_STORAGE: s3
AWS_ACCESS_KEY_ID: ${S3_ACCESS_KEY}
AWS_SECRET_ACCESS_KEY: ${S3_SECRET_KEY}
AWS_REGION: us-east-1
AWS_S3_UPLOAD_BUCKET_URL: https://s3.example.com
AWS_S3_UPLOAD_BUCKET_NAME: outline
AWS_S3_FORCE_PATH_STYLE: "true"
AWS_S3_ACL: private
# لـ R2 وبعض المزودين الذين لا يدعمون presigned POST
# AWS_S3_UPLOAD_METHOD: putوهنا يرفع المتصفح الملفات إلى الـ bucket مباشرة بروابط موقعة Presigned URLs ولا تمر عبر Outline، لذلك يجب أن يصل متصفح المستخدم إلى عنوان S3، وأن يسمح إعداد CORS على الـ bucket بالطلبين PUT وPOST من https://wiki.example.com. واجعل صلاحية مفتاح الوصول Access Key مقصورة على هذا الـ bucket، والسبب أن المفتاح محفوظ في ملف على السيرفر، فإذا تسرب فلا يصل صاحبه إلى غير مرفقات الويكي، والتفاصيل في توثيق Outline.
كيف تتأكد أن كل شيء يعمل؟
- الأمر
docker compose psيعرض الـ Containers الثلاثة بحالةhealthy، والأمرcurl -s https://wiki.example.com/_healthيعيدOK. - الدخول عبر authentik يعمل من نافذة خاصة Private Window، ويطلب المصادقة الثنائية إذا كانت مفروضة.
- افتح المستند نفسه في متصفحين واكتب في أحدهما، فإذا ظهر ما تكتبه فوراً في الآخر فاتصال WebSocket سليم.
- ارفع صورة في مستند ثم حدث الصفحة، ويجب أن تبقى الصورة ظاهرة.
- عند إضافة عضو جديد يرسل Outline إلى بريده رسالة «Welcome to Outline»، ولتجربة الرسائل قبل ربط خدمة بريد حقيقية وجه SMTP إلى Mailpit، وهو سيرفر SMTP تجريبي يلتقط الرسائل ويعرضها في واجهة ويب دون أن يرسلها.
النسخ الاحتياطي Backup والاستعادة Restore
تحتاج إلى نسخ ثلاثة أشياء: الأول قاعدة PostgreSQL، وفيها المستندات وسجل تعديلاتها Revision History والمستخدمون والصلاحيات، والثاني الـ Volume data وفيه المرفقات، أو الـ bucket إن كنت تستخدم S3، والثالث ملف .env بما فيه SECRET_KEY. ولا حاجة إلى نسخ Redis، والسبب أنه للطوابير والتخزين المؤقت فقط، ويعيد Outline بناء ما يحتاجه فيه.
cd /opt/outline
mkdir -p backups
docker compose exec -T postgres pg_dump -U outline -d outline -Fc > backups/outline-db-$(date +%F).dump
docker run --rm -v outline_data:/data:ro -v "$PWD/backups:/backup" alpine:3 \
tar czf /backup/outline-data-$(date +%F).tar.gz -C /data .
cp .env backups/outline-env-$(date +%F)ولاحظ أن اسم الـ Volume هنا outline_data، والسبب أن Compose يضيف اسم المجلد outline قبل اسم الـ Volume، فإذا وضعت الملفات في مجلد آخر فتأكد من الاسم بالأمر docker volume ls. واحفظ .env في مكان آمن ومنفصل لأن فيه الأسرار، وتستطيع أيضاً تصدير مساحة العمل كلها من Settings ← Export بصيغة HTML أو Markdown أو JSON، وهي نسخة إضافية مقروءة تفتحها دون Outline، وتنفعك إذا احتجت إلى إجراء من الويكي في يوم يكون فيه الويكي نفسه متوقفاً.
أما الاستعادة على سيرفر جديد فتحتاج إلى الإصدار نفسه من Outline وملف .env نفسه، ثم تشغل قاعدة البيانات وRedis وحدهما وتستعيد القاعدة من التفريغ Dump بالأمر pg_restore قبل تشغيل Outline:
cd /opt/outline
docker compose up -d postgres redis
docker compose exec -T postgres pg_restore -U outline -d outline --clean --if-exists --no-owner < backups/outline-db-2026-09-27.dump
docker run --rm -v outline_data:/data -v "$PWD/backups:/backup" alpine:3 \
sh -c 'tar xzf /backup/outline-data-2026-09-27.tar.gz -C /data && chown -R 1001:1001 /data'
docker compose up -d outlineوفي الأوامر أعلاه لاحظ أن chown يعيد ملكية المرفقات إلى المستخدم nodejs الذي يعمل به Outline داخل الـ Container ورقمه 1001، والسبب أن الأمر tar يعمل بالمستخدم root فتصبح الملفات المستعادة ملكاً له ويفشل رفع الصور بعدها. وإذا أردت أن تتأكد من الرقم فنفذ docker compose exec outline id، فإذا كان مختلفاً فاستخدمه في chown. وتذكر أن النسخة التي لم تجرب استعادتها لا يعتمد عليها، لذلك جرب الاستعادة على سيرفر تجريبي Staging مرة كل بضعة أشهر.
التحديث Upgrade إلى إصدار أحدث
- اقرأ ملاحظات الإصدار على GitHub، وابحث خصوصاً عن أي تغيير في متغيرات البيئة Environment Variables أو في أدنى إصدار يتطلبه من PostgreSQL.
- خذ نسخة احتياطية من القاعدة والمرفقات.
غير الوسم Tag في docker-compose.yml، مثلاً إلى outlinewiki/outline:1.10.2، ثم نفذ:
docker compose pull outline
docker compose up -d outline
docker compose logs -f outlineوتعمل الترحيلات تلقائياً عند بدء التشغيل، ولكن بعد أن يرحل الإصدار الأحدث القاعدة لا تقم بالعودة إلى إصدار أقدم، والسبب أن الترحيلات قد لا تكون قابلة للعكس، فلا رجوع عنها إلا من النسخة الاحتياطية. ويظهر الإصدار الحالي وحالته «Up to date» أسفل قائمة الإعدادات، إلا إذا عطلت ENABLE_UPDATES. أما PostgreSQL فلا تقم بترقيته إلى إصدار رئيسي جديد بتغيير الوسم وحده، حتى لو رأيت أن ملف Compose في توثيق Outline صار يستخدم postgres:18، والسبب أن ملفات البيانات لا تقرأ بين الإصدارات الرئيسية، فحدثه بين الإصدارات الرئيسية عبر pg_dump ثم الاستعادة في Container بالإصدار الجديد، كما في دليل Mattermost.
وقد تبدو متابعة التحديثات أمراً ثانوياً في أداة داخلية لا يستخدمها إلا الفريق، ولكن الويكي يجمع في مكان واحد إجراءات الإنتاج وعناوين السيرفرات وأحياناً بعض الأسرار، وبالتالي فهو هدف مغر لأي مخترق يصل إليه:
مشكلات شائعة وحلولها Troubleshooting
رسالة Authentication failed – we were unable to sign you in
افتح سجل Outline وسجل authentik في اللحظة نفسها، ففي سجل authentik تعني «Invalid grant_type» أن Authorization Code غير مفعل في الـ Provider، وتعني «Redirect URI Error» أن قيمة URL في Outline لا تطابق العنوان المسجل. وأما في سجل Outline فتعني رسالة البريد غير المؤكد أن الـ mapping الخاص بـ email_verified غير مختار، أو أن الـ mapping الافتراضي ما زال مختاراً معه.
خطأ في الحصول على التوكن Token بعد العودة من authentik
السبب أن الـ Container الخاص بـ Outline لا يصل إلى OIDC_TOKEN_URI، واختبر ذلك بالأمر docker compose exec outline wget -qO- https://auth.example.com/-/health/live/، وإذا كان النطاق داخلياً فقط فأضف extra_hosts إلى خدمة outline حتى يعرف الـ Container عنوانه.
الصفحة تعيد التحويل إلى https بلا نهاية، أو لا تحفظ ملفات تعريف الارتباط Cookies
إذا كان الـ Reverse Proxy ينهي TLS فاجعل FORCE_HTTPS: "false"، وتأكد أنه يمرر X-Forwarded-Proto: https، وأما في بيئة اختبار عبر HTTP فتأكد أن URL يبدأ بـ http://.
المستند لا يحفظ، أو تظهر رسالة «Trying to reconnect»
السبب أن اتصال WebSocket لا يمر عبر الـ Reverse Proxy، والحل أن تفعل Websockets Support في الـ Proxy Host.
فشل رفع الصور
مع التخزين المحلي يكون السبب واحداً من اثنين: إما صلاحيات المجلد، فأعد تنفيذ chown على الـ Volume كما في قسم الاستعادة، وإما حد client_max_body_size في الـ Reverse Proxy. وأما مع S3 فالسبب إعداد CORS على الـ bucket، أو أن المتصفح لا يصل إلى عنوان AWS_S3_UPLOAD_BUCKET_URL.
لا يوجد مدير بعد الدخول الأول
المدير هو صاحب الحساب الأول الذي أنشأ مساحة العمل، فإذا دخل شخص آخر قبلك فاطلب منه أن يمنحك دور المدير من Settings ← Users، وأما على تثبيت جديد لا محتوى فيه فالأسهل أن تحذف Volume القاعدة وتبدأ من جديد.
الخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- المعرفة التي تبقى في المحادثات والملفات المتفرقة تضيع مع أول موظف يغادر، والويكي الداخلي مثل Outline يجمعها في مكان واحد يبحث فيه الجميع ويعدلون فيه معاً.
- Outline منشور برخصة BSL 1.1، وهي تسمح بتشغيله لفريقك ولكنها تمنع تقديمه خدمة مستندات تجارية لجهات أخرى.
- لا يملك Outline كلمات مرور خاصة به، لذلك يحتاج إلى مزود هوية مثل authentik، مع ربط للبريد يرسل
email_verified: trueوعنوان عودة بمطابقة Strict. - Redis ما زال إلزامياً، واربط المنفذ بالعنوان
127.0.0.1، وفعل WebSocket في الـ Reverse Proxy، واجعلURLيطابق العنوان العام حرفياً. - انسخ قاعدة البيانات والمرفقات وملف
.envمعSECRET_KEY، وخذ نسخة قبل كل تحديث لأن الترحيلات لا رجوع عنها إلا من النسخة الاحتياطية.
سجل التحديثات (Changelog)
- سبتمبر 2026: كتابة الدليل واختباره على Outline 1.10.1.
- أكتوبر 2026: مراجعة الدليل على Outline 1.10.1، وهو آخر إصدار حتى الآن: صححنا وصف الرخصة (BSL 1.1 وليست مفتوحة المصدر)، ووضحنا متى يرفض Outline البريد غير المؤكد، وأضفنا أدنى إصدار من PostgreSQL وRedis والحد الأدنى للذاكرة بحسب التوثيق، وشرح
OIDC_LOGOUT_URIوOIDC_ISSUER_URL، وصيغة HTML في التصدير.