الخطوة 03 · النشر
حاويتان ووكيل واحد. ثم أغلق الباب.
عملية النشر المرجعية أدناه هي Umami، لأنها الأداة التي ينبغي لأغلب القراء تشغيلها، ولأن الشكل العام قابل للتعميم: حاوية تطبيق، وحاوية قاعدة بيانات يمكنها الوصول إليها ولا يستطيع أي طرف آخر ذلك، ووكيل عكسي يحمل الشهادة. تختلف Plausible وMatomo في عدد الحاويات وأسماء المتغيرات، لا في البنية — فخذ ملفات Compose الرسمية الخاصة بهما وطبّق القواعد الثلاث نفسها.
القواعد الثلاث، مرتّبة بحسب حجم الكلفة إن أُهملت. ثبّت كل صورة على وسم دقيق، لا على وسم متغيّر أبدًا: فحزمة تحليلات تسحب بصمت إصدارًا رئيسيًا جديدًا خلال إعادة تشغيل لا علاقة لها بالأمر هي ترحيل مخطط لم تجدوله. ولّد سرّ التطبيق من مصدر عشوائي حقيقي واحتفظ به — فهو يشفّر مواد الجلسة، وتغييره لاحقًا يُخرج الجميع من جلساتهم في أفضل الأحوال. لا تنشر أي منفذ لقاعدة البيانات: فالحاويتان تتشاركان شبكة واحدة، وهذا كل ما تحتاجه من ضبط الوصول.
mkdir -p /srv/analytics && cd /srv/analytics
openssl rand -base64 32 > .app_secret # keep this file; back it up with the database
openssl rand -base64 24 > .db_password
chmod 600 .app_secret .db_password
ملف Compose. خدمتان، وشبكة خاصة واحدة، ووحدة تخزين واحدة مُسمّاة لقاعدة البيانات، وليس أي منفذ منشور — فالوكيل هو الشيء الوحيد الذي يتحدث إلى العالم الخارجي:
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-v2.x.y # an exact tag, never :latest
environment:
DATABASE_URL: postgresql://umami:CHANGE_ME@db:5432/umami
APP_SECRET: CHANGE_ME # the openssl output above
depends_on: [db]
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: CHANGE_ME
volumes:
- umami-db:/var/lib/postgresql/data
restart: unless-stopped
volumes:
umami-db:
Caddy هو أقصر طريق إلى إعداد TLS صحيح هنا: سطران من الإعداد، وشهادة يتم الحصول عليها وتجديدها دون مهمة cron، وإعدادات افتراضية حديثة لا تحتاج إلى البحث عنها. إذا كنت تشغّل nginx على الخادم بالفعل، فابقَ عليه — فالمطلوب هو وكيل أمامي، لا هذا الوكيل بعينه. وفي كل الحالات، يجب ألا يكون تطبيق التحليلات هو ما يستمع على المنفذ 443 مباشرة أبدًا.
# Caddyfile — Caddy runs as a third service in the same Compose project, so
# "umami" resolves on the internal network. It is the only service that
# publishes ports (80 and 443).
stats.example.com {
encode zstd gzip
reverse_proxy umami:3000
}
شغّل الحزمة، ثم نفّذ الأمر الوحيد الحساس للوقت فعليًا. شغّل docker compose up -d، وانتظر انتهاء عمليات الترحيل، وافتح لوحة التحكم. تأتي كل واحدة من هذه الأدوات مزوَّدة إما بحساب مدير افتراضي موثَّق أو بشاشة تسجيل أول مفتوحة، وقد أصبح اسم المضيف معلومة عامة في اللحظة التي صدرت فيها الشهادة، لأن سجلات شفافية الشهادات عامة ويجري جرفها باستمرار. غيّر كلمة المرور الافتراضية وأغلق التسجيل في غضون دقائق من أول تحميل ناجح، لا في اليوم التالي.
docker compose up -d
docker compose logs -f umami # wait for the schema migration to finish
docker compose ps # both services healthy, no published ports listed
ss -tlnp | grep -E ':(5432|3306)' # must print nothing at all
الدقائق الخمس التي تحدد من يملك النسخة
تُشحَن Umami بحساب مدير موثَّق تكون كلمة مروره نفسها في كل تثبيت على وجه الأرض. ويصبح أول زائر لـPlausible هو المالك ما لم يُعطَّل التسجيل في بيئة التشغيل. وتُرشد Matomo أول زائر خلال مُثبِّت يُنشئ المستخدم الخارق. وفي الحالات الثلاث، الفترة الزمنية بين "وجود الشهادة" و"تسجيلك للدخول" هي فترة يمكن لشخص آخر أن يسجّل الدخول فيها بدلًا منك — وهو لا يحتاج إلى تخمين اسم المضيف، لأنه منشور له بالفعل. سجّل الدخول أولًا، وغيّر بيانات الاعتماد، ثم اضبط مفتاح التسجيل على الإغلاق وأعد تحميل الصفحة للتأكد من أن الإعداد ثبت.