Relayium

شغّل Relayium كخدمة استقبال دائمة التشغيل

آخر تحديث: 2026-08-06

يتعامل relayium serve --once مع عملية نقل واردة واحدة ثم يخرج — وهذا مناسب لعملية سحب لمرة واحدة. لكن إذا أردت أن تكون آلة ما نقطة إنزال دائمة — خادم منزلي تصل إليه النسخ الاحتياطية ليلًا، أو آلة بناء يدفع إليها CI منتجاتها، أو NAS يستطيع هاتفك إرسال الصور إليه في أي وقت — فأنت تريد أن يظل serve قيد التشغيل طوال الوقت، لا أن يُشغَّل يدويًا لكل عملية نقل.

يغطّي هذا الدليل بدء مُستمِع طويل التشغيل، والموافقة على من يُسمَح له بالدفع إليه، والتفويض المسبق للنظراء في الحالات التي لا يكون فيها أحد أمام الطرفية، وتشغيله تحت systemd، والسماح لمُرسِل يستخدم sync --delete بأن يعكس عمليات الحذف.

قبل أن تبدأ

كل ما يلي هو relayium CLI، فثبّته أولًا إن لم تكن قد فعلت. على macOS وLinux، يُسقط أمر واحد ملفًا ثنائيًا مُسبق البناء في PATH الخاص بك:

curl -fsSL https://relayium.com/install.sh | sh

ابدأ المُستمِع

ما تحتاجه قبل الخطوة 1

  • الـ CLI على الجهازين معًا. يطبع relayium version سطر إصدار على كلٍّ منهما، وإذا ردّت الصدفة بـ command not found فهو غير مثبَّت هناك بعد.
  • دليل للملفات الواردة على هذا الجهاز، ومساحة قرص تكفي لما سيصل إليه.
  • عنوان يستطيع المرسِل الوصول إليه، ومنفذ وارد مفتوح. وما لم تمرّر ‎--port‎ فإن serve يُنصِت على 9031.
  • إن كان هذا الجهاز سيعمل بلا طرفية — وهذا هو مغزى تحويله إلى خدمة — فستحتاج بصمة المرسِل مسبقًا. لها قسم كامل أدناه، وهي أكثر الأسباب شيوعًا لرفض المستقبِل الدائم كلَّ شيء.

يستمع serve إلى عمليات الدفع بأسلوب daemon direct (relayium://host:port) عبر اتصال TLS 1.3 مثبَّت ويكتب ما يستقبله في مجلد. لا حاجة إلى مشاركة أي شيء مسبقًا لبدئه — لا بصمات لنسخها، ولا خادم للتسجيل فيه:

relayium serve --dir ~/inbox
relayium serve --dir /srv/drop --port 9040   # منفذ غير افتراضي
relayium serve --dir ~/inbox --allow-delete  # السماح لمُرسِل يستخدم sync --delete بعكس عمليات الحذف
  1. اختر مكان وصول الملفات وشغّل المُنصِت. لا شيء يحتاج إلى مشاركة مسبقة حتى هذه النقطة.

    relayium serve --dir ~/inbox
  2. من الجهاز المرسِل، ادفع ملفًا إلى هذا المضيف عبر عنوان ‎relayium://‎ الخاص به.

    relayium push ./report.pdf relayium://drop.example.com:9031
  3. عد إلى المستقبِل وأجب عن طلب الموافقة. الإجابة y تكتب البصمة في authorized_fingerprints، فلا يُسأل عن الدفعات التالية من الجهاز نفسه مطلقًا.

  4. تأكّد أن الملف وصل فعلًا إلى ‎--dir‎ وليس إلى الدليل الذي شغّلت منه serve.

    ls -l ~/inbox

كيف يبدو مُنصِت يعمل بشكل صحيح

يعلن serve منذ البداية أنه بلا أقران مُصرَّح لهم، ثم يسأل عند أول دفعة من جهاز جديد ويصمت في كل ما بعدها. ينتهي المرسِل بالرمز 0 ويكون الملف داخل ‎--dir‎.

$ relayium serve --dir ~/inbox
no authorized peers yet — you'll be asked to approve each new peer on its first push.
Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

وافق على من يُسمَح له بالدفع

في أول مرة يدفع فيها نظير جديد، يعرض لك serve — إن كان يعمل في طرفية — من أين أتت الدفعة وبصمتها ويطلب منك الموافقة عليها، بالطريقة نفسها التي يسأل بها SSH عن مضيف مجهول عند أول اتصال:

Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

فوّض النظراء مسبقًا للإعدادات غير التفاعلية

حين لا يملك serve طرفيةً يطالب عليها — خدمة systemd، أو عملية في الخلفية، أو أنبوب — فإنه لا يستطيع السؤال، ولذلك يرفض أي بصمة لا يعرفها مسبقًا. بدلًا من ذلك، فوّض النظراء مسبقًا. على الآلة التي ستدفع، شغّل relayium id لطباعة بصمتها؛ وعلى المُستقبِل، أضِفها قبل وصول أول دفعة:

# على الآلة التي ستدفع: اطبع بصمتها
relayium id

# على هذا المُستقبِل الدائم التشغيل: فوّضها مسبقًا
relayium authorize 74318e3b...
  1. على الجهاز الذي سيدفع، اطبع بصمته. إنها 64 حرفًا ست عشريًا وتُعرِّف الجهاز نفسه لا عنوانه.

    relayium id
  2. صرّح له على هذا المستقبِل — بالـ ‎--config-dir‎ نفسه الذي ستعمل به الخدمة. فالتصريح بمستخدم آخر، أو بالمسار الافتراضي بينما تستعمل الوحدة مسارًا غيره، يكتب البصمة في ملف لا تقرؤه الخدمة أبدًا.

    relayium authorize 74318e3b… --config-dir /etc/relayium

شغّله تحت systemd

للحصول على خدمة تصمد أمام عمليات إعادة التشغيل والأعطال، سلّم serve إلى systemd. وجّه --config-dir إلى مسار ثابت حتى تبقى هوية المضيف وقائمة نظرائه المفوَّضين في مكانها عبر عمليات إعادة التشغيل:

# /etc/systemd/system/relayium-serve.service
[Unit]
Description=Relayium always-on receiver
After=network-online.target

[Service]
ExecStart=/usr/local/bin/relayium serve --dir /srv/drop --port 9031 --config-dir /etc/relayium --allow-delete
Restart=always
User=relayium

[Install]
WantedBy=multi-user.target
  1. صرّح لكل قرين يُفترض أن يستطيع الدفع، قبل وجود الخدمة أصلًا. فهي لا تستطيع السؤال، وكل ما ليس موثوقًا سلفًا مرفوض.

  2. اكتب ملف الوحدة أعلاه في ‎/etc/systemd/system/relayium-serve.service‎، بحيث يشير ‎--config-dir‎ إلى المسار الثابت نفسه الذي صرّحت تحته.

  3. أعد تحميل systemd وشغّل الخدمة، مع تفعيلها لتعود بعد إعادة التشغيل.

    sudo systemctl daemon-reload
    sudo systemctl enable --now relayium-serve
  4. تأكّد أنها تعمل وأن التحذير الذي يرفض كل شيء غائب عن السجل. والثاني وحده هو الخاص بهذا الإعداد.

    systemctl is-active relayium-serve
    journalctl -u relayium-serve -n 20 --no-pager

كيف تبدو خدمة تعمل بشكل صحيح

يجيب is-active بـ active، ولا يظهر تحذير الإقلاع عن غياب الأقران المُصرَّح لهم. وذلك التحذير هو السطر الوحيد الذي يخبرك، قبل أن يشتكي أي مرسِل، أن هذه الخدمة سترفض كل دفعة.

$ systemctl is-active relayium-serve
active
$ journalctl -u relayium-serve -n 20 --no-pager | grep -c 'all pushes will be rejected'
0

شغّله عند الإقلاع على macOS (launchd)

لا يملك macOS نظام systemd — فمدير خدماته هو launchd. لإبقاء serve قيد التشغيل على جهاز Mac (مثلًا Mac mini مُبقى مشغّلًا كنقطة إنزال)، ثبّته كـ LaunchDaemon حتى يبدأ عند الإقلاع، قبل أن يسجّل أحد الدخول. اضبط UserName حتى يعمل باسمك لا باسم root، وامنح --dir و--config-dir مسارات مطلقة حتى تبقى ملفات هويته وثقته في ~/.config/relayium الخاص بك:

<!-- /Library/LaunchDaemons/com.relayium.serve.plist  (replace YOU with your macOS username) -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>              <string>com.relayium.serve</string>
  <key>UserName</key>           <string>YOU</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/bin/relayium</string>
    <string>serve</string>
    <string>--dir</string>         <string>/Users/YOU/inbox</string>
    <string>--port</string>        <string>9031</string>
    <string>--config-dir</string>  <string>/Users/YOU/.config/relayium</string>
    <string>--allow-delete</string>
  </array>
  <key>RunAtLoad</key>   <true/>
  <key>KeepAlive</key>   <true/>
  <key>StandardOutPath</key>    <string>/Users/YOU/relayium-serve.log</string>
  <key>StandardErrorPath</key>  <string>/Users/YOU/relayium-serve.log</string>
</dict>
</plist>
# 1) authorize each pusher first — launchd gives serve no terminal to prompt on:
relayium authorize <fingerprint>     # get the fingerprint from the pusher's  relayium id

# 2) save the plist above to that path, then load it (root-owned, starts at boot):
sudo chown root:wheel /Library/LaunchDaemons/com.relayium.serve.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.relayium.serve.plist

# check it's running / follow logs / stop it:
sudo launchctl print system/com.relayium.serve | grep state
tail -f ~/relayium-serve.log
sudo launchctl bootout system/com.relayium.serve

اسمح لمُرسِل يستخدم sync --delete بعكس عمليات الحذف

افتراضيًا، لا يقوم serve إلا بإضافة الملفات أو تحديثها — فالمُرسِل الذي يشغّل sync --delete تجاهه لا يزال ينسخ الملفات الجديدة والمتغيّرة، لكن أي عمليات حذف يطلبها تُتخطّى، مع تسجيل تحذير على المُستقبِل. شغّل serve مع --allow-delete للاشتراك في النسخ المطابق الحقيقي، حيث تُحذَف هنا أيضًا الملفات المحذوفة على جانب المُرسِل:

relayium serve --dir /srv/mirror --allow-delete

حين لا ينجح الأمر

في أربع من هذه الإخفاقات الخمسة تبقى الخدمة تعمل وتبدو سليمة — فالمُنصِت الذي يرفض كل شيء يظل مُنصِتًا. ولكلٍّ منها سطر تقرؤه أو أمر تشغّله يحسم المسألة.

العَرَض، الفحص، الإصلاح

تبدأ الخدمة وتظل تعمل، لكن كل دفعة تُرفَض.
journalctl -u relayium-serve -n 20 --no-pager
# warning: no authorized peers and no terminal to approve on; all pushes will be rejected.

الخدمة بلا طرفية، فلا يمكنها أبدًا تنفيذ طلب الموافقة عند أول دفعة، وكل ما تراه بصمة مجهولة. صرّح لكل مرسِل مسبقًا: relayium id على الجهاز المرسِل، وrelayium authorize <البصمة> هنا، بالـ ‎--config-dir‎ نفسه المستخدَم في الوحدة. وهذا التحذير يُطبع عند الإقلاع، فهو موجود في السجل من سطره الأول.

لا تبدأ الخدمة إطلاقًا وتشتكي من أذونات غير آمنة على id.key.
stat -c '%a %U %n' /etc/relayium/id.key
# 400 relayium /etc/relayium/id.key

يجب أن تكون أذونات المفتاح 0600 بالضبط. ليس 0644، والأهم — وهنا يقع أكثر الناس — ليس 0400 أيضًا، فتشديدها أكثر يعطّل الخدمة بالقدر نفسه الذي يعطّلها به تخفيفها. نفّذ chmod 600 على المفتاح وتأكّد أن مالكه هو المستخدم المحدَّد في ‎User=‎ داخل الوحدة.

يبلّغ المرسِل بأن الاتصال قد رُفِض.
relayium push ./build relayium://drop.example.com:9031
# hint: if the peer refused the connection, it may not have authorized this host.

المستقبِل لا يعرف هذا المرسِل. شغّل relayium id على المرسِل، وصرّح لتلك البصمة على المستقبِل بـ relayium authorize. وإن كنت فعلت ذلك سلفًا فتحقّق أنك فعلته تحت ‎--config-dir‎ الخاص بالوحدة: فملف الثقة مرتبط بالدليل، والبصمة المُصرَّح بها في ‎~/.config/relayium‎ غير موجودة أصلًا بالنسبة لخدمة تقرأ ‎/etc/relayium‎.

الدفع ينجح حين تشغّل serve يدويًا، لكنه يفشل عبر الخدمة أو من جهاز آخر.
sudo ss -tlnp | grep 9031

سببان مختلفان يفصل بينهما فحص واحد. إن لم يكن هناك أي إنصات فالوحدة غير مفعَّلة — استخدم systemctl is-enabled relayium-serve. وإن كانت تُنصِت فالمنفذ مغلق: افتح 9031 في جدار حماية المضيف وفي أي مجموعة أمان سحابية. وأي ‎--port‎ غير افتراضي يجب أن يطابق المنفذ في ‎relayium://host:N‎ لدى المرسِل.

عمليات الحذف التي يطلبها مرسِل sync --delete لا تحدث على هذا الجهاز أبدًا.
journalctl -u relayium-serve | grep -i delete

الحذف اختيار يفعّله الطرف المستقبِل وهو معطَّل افتراضيًا: الملفات الجديدة والمعدَّلة تُنسخ كالمعتاد، وكل عملية حذف متخطَّاة تُسجَّل هنا كتحذير. أضف ‎--allow-delete‎ إلى ExecStart في الوحدة وأعد التشغيل. ولا يكفي أن يطلبها المرسِل، وهذا التفاوت مقصود — فالمستقبِل لا يفقد ملفات بسبب راية كُتبت في مكان آخر.

الأسئلة الشائعة

ما المنفذ الذي يستمع إليه serve افتراضيًا؟

9031. غيّره بـ --port على كلٍّ من المُستمِع (serve --port N) وهدف الجهة الدافعة (relayium://host:N).

هل عليّ الموافقة على كل دفعة يدويًا؟

الدفعة الأولى فقط من بصمة معيّنة، وفقط حين يعمل serve مع طرفية موصولة. وتُحفَظ بعد ذلك. أما تشغيل serve بشكل غير تفاعلي (systemd، أو أنبوب) فيتخطّى المطالبة كليًا ويرفض النظراء المجهولين — ففوّضهم مسبقًا بـ relayium authorize بدلًا من ذلك.

هل يستطيع مُرسِل حذف ملفات على مُستقبِلي الدائم التشغيل؟

فقط إذا بدأت serve بـ --allow-delete وكان المُرسِل يشغّل sync --delete. بدون --allow-delete، تُتخطّى عمليات الحذف بصمت وينتقل كل شيء آخر كالمعتاد.

هل تشغيل مُستقبِل دائم التشغيل مجاني؟

نعم. relayium serve جزء من واجهة سطر الأوامر (CLI) المجانية القابلة للاستضافة الذاتية — بلا حساب، وبلا فئة مدفوعة، على أي من طرفي الاتصال.

أين يحفظ serve هويته وقائمة نظرائه؟

في ~/.config/relayium افتراضيًا (id.key/id.crt لهوية هذا المضيف، وauthorized_fingerprints لقائمة السماح). وجّه --config-dir إلى مكان ثابت، مثل /etc/relayium، لخدمة systemd.

كيف أشغّل serve عند الإقلاع على macOS؟

لا يملك macOS نظام systemd — استخدم launchd. ثبّت serve كـ LaunchDaemon في /Library/LaunchDaemons (يبدأ عند الإقلاع؛ اضبط UserName ليعمل باسمك)، أو كـ LaunchAgent في ~/Library/LaunchAgents (يبدأ عند تسجيل الدخول). يحتوي هذا الدليل على ملف plist جاهز للتحرير؛ ولا توجد خدمة Homebrew. فوّض الجهات الدافعة مسبقًا بـ relayium authorize أولًا، لأن launchd لا يمنح serve أي طرفية للمطالبة عليها.

حوّل أي آلة تملكها إلى مُستقبِل مجاني دائم التشغيل — عمليات دفع مباشرة عبر TLS مثبَّت، دون أي مُرحِّل.

احصل على واجهة سطر الأوامر (CLI)

تابع القراءة