Прокси для Signal Messenger c помощью Nginx

Signal использует довольно изящную схему с двумя TLS-туннелями, поэтому для того, чтобы поднять прокси для него, хватит самого обычного Nginx.

Пример конфига:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
}

http {
    server {
        listen 127.0.0.1:8443 ssl;
        root /var/www/html;
        ssl_certificate /etc/letsencrypt/live/YOUR_SITE_DOMAIN/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/YOUR_SITE_DOMAIN/privkey.pem;
    }
}


stream {
    resolver 1.1.1.1 8.8.8.8 valid=300s;

    log_format stream_log '$remote_addr [$time_local] "$protocol" '
                      '$ssl_preread_server_name'
                      '$status $bytes_sent $bytes_received '
                      '$session_time "$upstream_addr"';
    upstream relay {
         server 127.0.0.1:445;
    }

    server {
        listen                127.0.0.1:444 ssl;
        proxy_pass            relay;
        access_log            /var/log/nginx/access_term.log stream_log;
        error_log             /var/log/nginx/error_term.log info;

        ssl_certificate /etc/letsencrypt/live/YOUR_PROXY_DOMAIN/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/YOUR_PROXY_DOMAIN/privkey.pem;
     }

     map $ssl_preread_server_name $sig_name {
        chat.signal.org                         signal-service;
        ud-chat.signal.org                      signal-service;
        storage.signal.org                      storage-service;
        cdn.signal.org                          signal-cdn;
        cdn2.signal.org                         signal-cdn2;
        cdn3.signal.org                         signal-cdn3;
        cdsi.signal.org                         cdsi;
        contentproxy.signal.org                 content-proxy;
        sfu.voip.signal.org                     sfu;
        svr2.signal.org                         svr2;
        svrb.signal.org                         svrb;
        updates.signal.org                      updates;
        updates2.signal.org                     updates2;
        default                                 deny;
    }


     map $ssl_preread_server_name $local_name {
        YOUR_PROXY_DOMAIN                       signal;
        default                                 local;
    }

    upstream signal-service {
         server chat.signal.org:443;
    }

    upstream storage-service {
        server storage.signal.org:443;
    }

    upstream signal-cdn {
        server cdn.signal.org:443;
    }

    upstream signal-cdn2 {
        server cdn2.signal.org:443;
    }

    upstream signal-cdn3 {
        server cdn3.signal.org:443;
    }

    upstream cdsi {
        server cdsi.signal.org:443;
    }

    upstream content-proxy {
        server contentproxy.signal.org:443;
    }

    upstream sfu {
        server sfu.voip.signal.org:443;
    }

    upstream svr2 {
        server svr2.signal.org:443;
    }

    upstream svrb {
        server svrb.signal.org:443;
    }

    upstream updates {
        server updates.signal.org:443;
    }

    upstream updates2 {
        server updates2.signal.org:443;
    }

    upstream local {
        server 127.0.0.1:8443;
    }

    upstream signal {
        server 127.0.0.1:444;
    }

    upstream deny {
        server 127.0.0.1:9;
    }

    server {
        listen                127.0.0.1:445;
        proxy_pass            $sig_name;
        ssl_preread           on;
        access_log            /var/log/nginx/access_sig.log stream_log;
        error_log             /var/log/nginx/error_sig.log info;
     }

    server {
        listen                443;
        proxy_pass            $local_name;
        ssl_preread           on;
        access_log            /var/log/nginx/access_main.log stream_log;
        error_log             /var/log/nginx/error_main.log info;

     }

}

Здесь
YOUR_PROXY_DOMAIN - это домен для прокси. Можно использовать любой, даже с afraid.org или dynu.com или sslip.io
YOUR_SITE_DOMAIN - это домен для сайта, который вы можете хостить на том же сервере. Сертификат для него также будет отдаваться по умолчанию если стукнуться на 443 порт с пустым SNI.

Прокси-домен может быть поддоменом домена сайта.

Сертификаты можно сгенерить с

 certbot certonly --standalone   --deploy-hook "systemctl restart nginx"  -d YOUR_PROXY_DOMAIN
 certbot certonly --standalone   --deploy-hook "systemctl restart nginx"  -d YOUR_SITE_DOMAIN

После генерации сертификатов и перезапуска Nginx вставляем в Signal ссылку типа https://signal.tube/#YOUR_PROXY_DOMAIN , тыкаем, он добавляет прокси и все работает.

Вместо своего сайта можно в upstream local указать домен и 443 порт какого-нибудь другого сайта - тогда ваш сервер тупо будет проксировать все HTTPS-запросы на него (но будьте осторожны с CDN, чтобы не повторилась история как вот здесь). Cекцию “http” в таком случае можно выкинуть, как и сертификат для сайта.

А еще можно на том же сервере вместо сайта захостить еще и Telegram-прокси с FakeTLS, например 9seconds/mtg: Highly opinionated MTPROTO proxy for Telegram - аналогично в конфиге Nginx меняем в upstream local порт 8443 на порт вашего Telegram-прокси.