دامنه، HTTPS و پروکسی معکوس

Antimatter را روی یک نام دامنه با HTTPS قرار دهید، با استفاده از پروفایل Caddy در فایل compose یا یک پروکسی معکوس اختصاصی، و آدرس سایت و آدرس‌های کلاینت را درست تنظیم کنید.

آدرس سایت

آدرس سایت (ServiceSettings.SiteURL) آدرسی است که افراد برای دسترسی به Antimatter از آن استفاده می‌کنند، مانند https://chat.example.com. سرور از این آدرس در پیوندهای ایمیل‌ها و اعلان‌ها، در هدایت‌های ورود (OAuth، OpenID Connect، SAML)، برای اپلیکیشن‌های موبایل و دسکتاپ، و برای بررسی مبدأ درخواست‌ها استفاده می‌کند. آن را دقیقاً مطابق با آدرسی که در نوار آدرس مرورگر نمایش داده می‌شود تنظیم کنید: اسکیم، دامنه و پورت (اگر پیش‌فرض نباشد)، بدون اسلش در انتها.

  • با استفاده از فایل compose سایت: SITE_URL در .env.
  • در جای دیگر: AM_SERVICESETTINGS_SITEURL، یا کنسول سیستم › محیط › وب سرور › آدرس سایت.

اگر آدرس سایت اشتباه باشد، ورود با ارائه‌دهنده هویت ناموفق می‌ماند، پیوندهای ایمیل‌ها به مکان اشتباه اشاره می‌کنند و اپلیکیشن‌ها ممکن است نتوانند اتصال برقرار کنند. پس از تغییر دامنه، آن را در اینجا و در آدرس‌های هدایت همه ارائه‌دهندگان هویت به‌روزرسانی کنید.

HTTPS با پروفایل Caddy همراه با نرم‌افزار

فایل compose.yaml سایت یک سرویس Caddy در پروفایل https شامل می‌شود. این سرویس گواهی از Let's Encrypt دریافت می‌کند، به‌طور خودکار آن را تمدید می‌کند، HTTP را به HTTPS هدایت می‌کند و همه چیز، از جمله وب‌سوکت‌ها را به Antimatter فوروارد می‌کند.

  1. یک رکورد DNS (A و AAAA برای IPv6) از دامنه خود را به سرور اشاره دهید.
  2. پورت‌های 80/tcp، 443/tcp و 443/udp (HTTP/3) را در فایروال باز کنید. Let's Encrypt باید بتواند از اینترنت به پورت 80 یا 443 دسترسی پیدا کند.
  3. دامنه را به .env اضافه کنید و آدرس سایت را تنظیم کنید:
    echo "DOMAIN=chat.example.com" >> .env
    sed -i 's|^SITE_URL=.*|SITE_URL=https://chat.example.com|' .env
  4. با پروفایل شروع کنید:
    docker compose --profile https up -d

--profile https را به هر دستور بعدی docker compose up اضافه کنید، یا COMPOSE_PROFILES=https را در .env قرار دهید تا دستور ساده docker compose up -d نیز آن را شامل شود. Caddy گواهی‌های خود را در حجم https نگه می‌دارد.

پورت اختصاصی Antimatter همچنان روی میزبان منتشر می‌شود (HTTP_PORT، به‌طور پیش‌فرض 8065). با وجود Caddy در جلوی آن، این پورت را فقط برای خود سرور نگه دارید:

echo "HTTP_PORT=127.0.0.1:8065" >> .env
docker compose --profile https up -d

Caddy از طریق شبکه داخلی edge به Antimatter دسترسی پیدا می‌کند، نه از طریق آن پورت، بنابراین این تغییر هیچ تأثیری بر کاربران شما ندارد.

با پروکسی معکوس اختصاصی (nginx)

اگر سرور از قبل nginx یا یک پروکسی دیگر را اجرا می‌کند، پروفایل https را غیرفعال نگه دارید و پروکسی را به پورت 8065 آنتی‌متر تنظیم کنید. پروکسی باید:

  • ارتقاء‌های websocket را عبور دهد (اپلیکیشن وب و اپلیکیشن‌های موبایل یک websocket را روی /api/v4/websocket باز نگه می‌دارند و برخی اپلیکیشن‌ها websocket اختصاصی خود را باز می‌کنند)؛
  • دریافت بدنه‌های درخواست با اندازه‌ای حداقل به بزرگی بزرگ‌ترین بارگذاری (حداکثر اندازه فایل، به‌طور پیش‌فرض ۱۰۰ مگابایت)؛
  • اتصالات طولانی‌مدت را باز نگه دارد (websockets، بارگذاری‌ها و دانلودهای بزرگ)؛
  • هدر Host و آدرس کلاینت را عبور دهد.

یک بلوک سرور کامل، تطبیق‌یافته از قالب تولیدی در antimatter-docker. دامنه و مسیرهای گواهی را جایگزین کنید:

upstream antimatter {
    server 127.0.0.1:8065;
    keepalive 64;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      '';
}

proxy_cache_path /var/cache/nginx/antimatter levels=1:2 keys_zone=antimatter_cache:10m
                 max_size=3g inactive=120m use_temp_path=off;

server {
    listen 80;
    listen [::]:80;
    server_name chat.example.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name chat.example.com;

    ssl_certificate     /etc/ssl/chat.example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/chat.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:AntimatterSSL:10m;
    ssl_session_tickets off;

    add_header Strict-Transport-Security "max-age=31536000" always;

    # At least FileSettings.MaxFileSize (100 MB by default).
    client_max_body_size 100M;

    proxy_http_version 1.1;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade           $http_upgrade;
    proxy_set_header Connection        $connection_upgrade;
    proxy_buffers 256 16k;
    proxy_buffer_size 16k;

    location ~ ^/api/v[0-9]+/(users/)?websocket$ {
        client_body_timeout 60s;
        send_timeout 300s;
        lingering_timeout 5s;
        proxy_connect_timeout 90s;
        proxy_send_timeout 300s;
        proxy_read_timeout 90s;
        proxy_pass http://antimatter;
    }

    location / {
        proxy_read_timeout 600s;
        proxy_cache antimatter_cache;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 2;
        proxy_cache_use_stale timeout;
        proxy_cache_lock on;
        proxy_pass http://antimatter;
    }
}

فایل را با nginx -t بررسی کنید و با systemctl reload nginx اعمال کنید. سرور به‌طور خودکار X-Content-Type-Options، Referrer-Policy، Permissions-Policy و X-Frame-Options را ارسال می‌کند؛ تنها HSTS بر عهده پروکسی است. پس از کارکردن HTTPS، max-age را افزایش دهید و includeSubDomains را فقط در صورتی اضافه کنید که همه زیردامنه‌ها از HTTPS استفاده کنند.

با Docker Compose و nginx روی میزبان، upstream بالا به پورت منتشرشده 8065 اشاره می‌کند. آن را فقط روی 127.0.0.1 منتشر کنید (HTTP_PORT=127.0.0.1:8065) تا هیچ‌کس نتواند پروکسی را دور بزند.

مخزن antimatter-docker یک راه‌اندازی کامل با nginx در یک کانتینر و Let's Encrypt از طریق certbot را در deploy/compose دارد.

پروکسی‌های دیگر

هر پروکسی‌ای کار می‌کند اگر چهار نکته بالا را برآورده کند. صدا و ویدئوی مکالمه هرگز از طریق پروکسی عبور نمی‌کنند: آن‌ها از پورت اختصاصی خود استفاده می‌کنند، به مکالمه و صدا مراجعه کنید.

آدرس‌های کلاینت پشت پروکسی

پشت یک پروکسی، به نظر می‌رسد همه درخواست‌ها از سمت پروکسی می‌آیند. برای ثبت آدرس واقعی کلاینت، اعمال محدودیت نرخ به ازای هر کلاینت و استفاده از فیلتر IP، به سرور بگویید کدام هدر آدرس را حمل می‌کند و به کدام پروکسی‌ها می‌تواند اعتماد کند. هیچ‌کدام از این تنظیمات فیلدی در کنسول سیستم ندارند: آن‌ها را در config.json یا با متغیرها تنظیم کنید.

کلید و متغیرمقدار پیش‌فرضعملکرد
ServiceSettings.TrustedProxyIPHeader, AM_SERVICESETTINGS_TRUSTEDPROXYIPHEADERخالی: سرور از آدرس اتصال استفاده می‌کندهدرهایی که آدرس کلاینت را حمل می‌کنند، برای مثال X-Forwarded-For. اولین هدر موجود در یک درخواست استفاده می‌شود.
ServiceSettings.TrustedProxyIPs, AM_SERVICESETTINGS_TRUSTEDPROXYIPSخالیآدرس‌ها یا بازه‌های CIDR پروکسی‌های شما، برای مثال 172.29.71.0/28. هدرها فقط برای درخواست‌هایی که از یکی از این پروکسی‌ها می‌آیند، معتبر هستند.

در یک متغیر، چند مقدار را با فاصله جدا کنید: AM_SERVICESETTINGS_TRUSTEDPROXYIPHEADER="X-Forwarded-For X-Real-IP". سرور از پذیرش پیکربندی‌ای که در TrustedProxyIPs یک ورودی نه به‌صورت آدرس IP و نه به‌صورت محدوده CIDR باشد، خودداری می‌کند.

نحوه یافتن آدرس کلاینت توسط سرور

هر پروکسی آدرسی که درخواست را از آن دریافت کرده است را به سمت راست X-Forwarded-For اضافه می‌کند. هر چیزی که کلاینت در خود هدر فرستاده باشد، در سمت باقی می‌ماند. بنابراین سرور هدر را از سمت راست می‌خواند، آدرس‌های پروکسی‌های مورد اعتماد شما را رد می‌کند و اولین آدرس دیگر را به‌عنوان آدرس کلاینت در نظر می‌گیرد. کلاینت نمی‌تواند با ارسال هدر خودش، آدرس خود را انتخاب کند.

  • در پشت یک پروکسی، TrustedProxyIPHeader به‌تنهایی آدرس صحیح را ارائه می‌دهد: سرور آدرس سمت راست هدر را می‌گیرد. تا زمانی که TrustedProxyIPs را هم تنظیم نکنید، هنگام راه‌اندازی یک هشدار ثبت می‌شود. بدون این تنظیم، هر کسی که مستقیماً به پورت 8065 دسترسی داشته باشد می‌تواند هدر را تنظیم کند، بنابراین این پورت را فقط روی 127.0.0.1 یا در یک شبکه خصوصی منتشر کنید.
  • در پشت چند پروکسی، برای مثال یک CDN یا باربالانس در جلوی پروکسی خودتان، همه آن‌ها را در TrustedProxyIPs فهرست کنید. در غیر این صورت، سرور آدرس پروکسی بیرونی را به‌عنوان آدرس کلاینت در نظر می‌گیرد.
  • پروکسی می‌تواند هدر را با آدرسی که می‌بیند جایگزین کند، همان‌طور که در مثال nginx بالا انجام شده است (X-Forwarded-For $remote_addr)، یا به آن اضافه کند (با $proxy_add_x_forwarded_for در nginx). هر دو روش کار می‌کنند.

کدام آدرس‌ها را فهرست کنید

آدرسی که درخواست‌های پروکسی از آن می‌آیند را، همان‌طور که Antimatter آن را می‌بیند، فهرست کنید.

  • با فایل compose سایت و Caddy، این کار از پیش انجام شده است: Caddy از طریق شبکه edge به Antimatter دسترسی پیدا می‌کند و فایل compose، TrustedProxyIPHeader را روی X-Forwarded-For و TrustedProxyIPs را روی محدوده آن شبکه، EDGE_SUBNET (مگر اینکه در .env آن را تغییر دهید، 172.29.71.0/28) تنظیم می‌کند. اگر EDGE_SUBNET با یکی از شبکه‌های شما هم‌پوشانی دارد، آن را تغییر دهید.
  • پیکربندی تولید در antimatter-docker کار مشابهی را برای کانتینر nginx خود انجام می‌دهد، با استفاده از FRONTEND_SUBNET.
  • با nginx روی میزبان و Antimatter در Docker، درخواست‌ها از طریق پورت منتشرشده به Antimatter می‌رسند، معمولاً از آدرس دروازه (gateway) شبکه پروژه compose (با docker network inspect قابل مشاهده است). AM_SERVICESETTINGS_TRUSTEDPROXYIPS را در compose.override.yaml روی آن آدرس تنظیم کنید.
  • بدون Docker، در صورتی که nginx روی همان میزبان اجرا شده باشد، آدرس 127.0.0.1 است (و در صورت اتصال nginx از طریق IPv6، ::1).

TLS بدون پروکسی

سرور همچنین می‌تواند خود HTTPS را ارائه دهد، در کنسول سیستم › محیط › وب سرور: امنیت اتصال را روی TLS تنظیم کنید (ServiceSettings.ConnectionSecurity)، همراه با فایل گواهی TLS و فایل کلید TLS (ServiceSettings.TLSCertFile، ServiceSettings.TLSKeyFile)، یا از Let's Encrypt استفاده کنید (ServiceSettings.UseLetsEncrypt). در این صورت سرور باید روی پورت ۴۴۳ گوش دهد (آدرس گوش دادن، ServiceSettings.ListenAddress، به‌طور پیش‌فرض :8065) و ServiceSettings.Forward80To443 پورت ۸۰ را هدایت می‌کند. استفاده از یک پروکسی معکوس برای اجرا و تمدید گواهی آسان‌تر است و این راهنما بر همین فرض استوار است.

مهلت‌های سرور و اندازه درخواست

تنظیمات وب سرور خود سرور، در کنسول سیستم › محیط › وب سرور:

تنظیمکلیدمقدار پیش‌فرض
آدرس گوش دادنServiceSettings.ListenAddress:8065
خواندن تایم اوتServiceSettings.ReadTimeout۳۰۰ ثانیه
نوشتن تایم اوتServiceSettings.WriteTimeout۳۰۰ ثانیه
مهلت بیکاری (فیلدی در کنسول سیستم ندارد)ServiceSettings.IdleTimeout۶۰ ثانیه
حجم حداکثری Payload (بایت)ServiceSettings.MaximumPayloadSizeBytesبه امنیت مراجعه کنید

مهلت‌های خود پروکسی را برای درخواست‌های عادی، حداقل به اندازه این مقادیر تنظیم کنید و اندازه بدنه (Body) را حداقل به اندازه حداکثر اندازه فایل در نظر بگیرید.