إنهاء TLS أمام سوكيتات Workerman — إصلاح Socket Connect Error: timeout

السبب (مثبَّت على الإنتاج): التزام c35b350b بتاريخ 2026-07-23 — وهو التزام
تلقائي برسالة "Update: <time>" — أضاف المنفذ للروابط:
  -  'https://jordan-siro.intaleqapp.com'
  +  'https://jordan-siro.intaleqapp.com:2020'
وكانت القيمة العاملة قبل ذلك بلا منفذ (443) فيُنهي البروكسي TLS ويمرّر.

بإضافة :2020 صار التطبيق يضرب حاوية Workerman مباشرة، وهي تفتح المنفذ نصاً
صريحاً (new SocketIO(2020) بلا سياق SSL)، فمصافحة TLS تتجمّد حتى المهلة:
  ❌ Socket Connect Error: timeout
  ❌ Socket Connect Timeout: 20000
ونتيجته أن السائق لا يبعث update_location إطلاقاً ⇒ لا GPS في Redis ⇒ لا
موقع للراكب لا عبر السوكيت ولا عبر الـ polling (كلاهما يقرأ من نفس المصدر).

مثبَّت بالأدلة على السيرفر:
- ss: المنفذان 2020/3030 يملكهما docker-proxy (نص صريح)، و443 nginx.
- curl على 127.0.0.1:2020 يرد {"sid":...,"upgrades":["websocket"]} — أي أن
  الحاوية سليمة تماماً والناقص هو طبقة TLS وحدها.

الحل بلا أي بناء للتطبيقات (وبلا تنزيل مستوى الأمان — الـ JWT يُرسَل في
query string فلا يجوز إطلاقاً تحويله إلى http):
- الحاويتان تُنشران على 127.0.0.1:12020 و 127.0.0.1:13030 فقط.
- nginx على المضيف يستمع على 2020/3030 بشهادة الدومين ويمرّر إليهما مع
  ترقية WebSocket (nginx/siro-sockets-tls.conf).
- proxy_read/send_timeout 3600s: اتصال السائق يعيش ساعات، وبلا ذلك يقطعه
  nginx كل 60ث فتدخل الحاوية حلقة إعادة اتصال دائمة.
- proxy_buffering off و access_log off (نبضات GPS تُغرق القرص).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-27 01:01:42 +03:00
co-authored by Claude Opus 5
parent 6fec88251c
commit afb5189515
2 changed files with 115 additions and 3 deletions
+106
View File
@@ -0,0 +1,106 @@
# ══════════════════════════════════════════════════════════════════
# ‏إنهاء TLS أمام سوكيتات Workerman
# ══════════════════════════════════════════════════════════════════
# ‏يُنسَخ على **المضيف** لا داخل الحاويات:
# /etc/nginx/sites-enabled/siro-sockets-tls.conf
#
# ‏المشكلة التي يحلّها: حاويتا السوكيت تفتحان المنفذين نصاً صريحاً
# (‏new SocketIO(2020)‎ و ‎new SocketIO(3030)‎ بلا سياق SSL)، بينما
# ‏التطبيقان يطلبان ‎https://jordan-siro.intaleqapp.com:2020‎ و ‎:3030‎.
# ‏مصافحة TLS ضد منفذ لا يتكلم TLS تتجمّد حتى المهلة، فيظهر في اللوج:
# Socket Connect Error: timeout
#
# ‏الحل: الحاويتان تُنشران على 127.0.0.1 فقط (12020 / 13030 — انظر
# ‏docker-compose.yml)، و nginx هنا يستمع على 2020 / 3030 بشهادة الدومين
# ‏ويمرّر إليهما مع ترقية WebSocket. النتيجة: روابط التطبيقين تبقى كما هي
# ‏بلا أي بناء جديد، والـ JWT في الـ query string يبقى داخل نفق TLS.
# ══════════════════════════════════════════════════════════════════
# ‏اسم مميّز يتفادى التضارب مع أي map باسم ‎$connection_upgrade‎ قد يكون
# ‏CloudPanel معرِّفه أصلاً في سياق http.
map $http_upgrade $siro_connection_upgrade {
default upgrade;
'' close;
}
# ── سوكيت السائقين — GPS ─────────────────────────────────────────
server {
listen 2020 ssl;
listen [::]:2020 ssl;
http2 on;
server_name jordan-siro.intaleqapp.com;
# ‏عدّل المسارين إن كانت شهادتك في مكان آخر — تحقّق بالأمر:
# grep -rh ssl_certificate /etc/nginx/sites-enabled/ | sort -u
ssl_certificate /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.crt;
ssl_certificate_key /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SiroSock:10m;
ssl_session_timeout 1d;
# ‏لا سجلّ وصول: نبضات GPS تصل كل ثوانٍ وتُغرق القرص
access_log off;
error_log /var/log/nginx/siro-socket-driver-error.log warn;
location / {
proxy_pass http://127.0.0.1:12020;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $siro_connection_upgrade;
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;
# ‏اتصال السائق يعيش ساعات وهو أونلاين — بلا هذه المهل يقطعه nginx
# ‏كل 60 ثانية فتدخل الحاوية في حلقة إعادة اتصال دائمة.
proxy_connect_timeout 10s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
# ‏التخزين المؤقّت يُعطّل الدفع الفوري في WebSocket
proxy_buffering off;
}
}
# ── سوكيت الركاب — حالة الرحلة وموقع السائق ──────────────────────
server {
listen 3030 ssl;
listen [::]:3030 ssl;
http2 on;
server_name jordan-siro.intaleqapp.com;
ssl_certificate /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.crt;
ssl_certificate_key /etc/nginx/ssl-certificates/jordan-siro.intaleqapp.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SiroSock:10m;
ssl_session_timeout 1d;
access_log off;
error_log /var/log/nginx/siro-socket-passenger-error.log warn;
location / {
proxy_pass http://127.0.0.1:13030;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $siro_connection_upgrade;
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_connect_timeout 10s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_buffering off;
}
}