Как настроить HTTPS между двумя серверами с использованием Nginx?

<b>Дано</b> <br/> 1. Сервер в локальной сети с IP-адресом 192.168.0.10 (Ubuntu + Nginx) <br/> 2. Роутер, подключенный к интернету, с публичным IP-адресом <b>x.x.x.x</b>, на котором закрыты порты 80 и 443, но открыты и проброшены на локальный сервер порты <i>8080</i> и <i>8443</i> <br/> 3. Арендованный VPS с публичным IP-адресом <b>y.y.y.y</b> (Ubuntu + Nginx) <br/> 4. Домен <b>site.ru</b>, который указывает на VPS с IP <i>y.y.y.y</i> <br/> <br/> <b>Задача</b> <br/> Настроить доступ к <b>site.ru</b> с локального сервера через HTTPS. <br/> <br/> HTTP работает нормально: на VPS настроен проксирующий Nginx, который направляет запросы на другой IP и порт. <br/> <pre><code class="nginx">server {
    listen       80;
    server_name  site.ru www.site.ru;

    location / {
        proxy_pass  http://x.x.x.x:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real_IP  $remote_addr;
   }
}</code></pre> <br/> <br/> В текущей настройке локальный сервер получает полную информацию о клиенте, в то время как клиент не получает информации о конечном сервере. <br/> <br/> Как осуществить эту настройку для HTTPS? <br/> <br/> Насколько я понимаю, здесь будут две зашифрованные связи: <br/> 1. от клиента к VPS (сертификат Let's Encrypt) <br/> 2. от VPS к локальному серверу (требуется самоподписанный сертификат?) <br/> <br/> Таким образом, клиент осуществляет шифрование, проксирующий Nginx расшифровывает, затем шифрует для второй связи, а конечный Nginx снова расшифровывает. <br/> <br/> Меня интересует именно эта вторая связь от проксирующего Nginx к конечному Nginx. Как правильно настроить безопасное шифрование между ними? <br/> <br/> Существуют ли альтернативные способы реализации HTTPS в данной сетевой архитектуре?
  • 1 декабря 2024 г. 8:13
Ответы на вопрос 2
Для настройки HTTPS между двумя серверами с использованием Nginx в вашей архитектуре, вам действительно понадобится настроить две зашифрованные связи. Первая связь — это связь между клиентом и VPS, а вторая — между VPS и вашим локальным сервером. 

### Пошаговая инструкция

#### 1. Настройка HTTPS на VPS

На VPS вам необходимо получить SSL-сертификат. Самый распространенный бесплатный сертификат предоставляется Let's Encrypt. Вот краткие шаги:

1. **Установите certbot** (если он ещё не установлен):

   ```bash
   sudo apt update
   sudo apt install certbot python3-certbot-nginx
   ```

2. **Получите сертификат** для вашего домена:

   ```bash
   sudo certbot --nginx -d site.ru -d www.site.ru
   ```

   Убедитесь, что вы следуете инструкциям и подтверждаете свой домен.

3. **Настройте Nginx на VPS** для поддержки HTTPS:

   В конфигурации вашего Nginx на VPS замените текущую конфигурацию на следующую:

   ```nginx
   server {
       listen 80;
       server_name site.ru www.site.ru;

       # Редирект на HTTPS
       return 301 https://$host$request_uri;
   }

   server {
       listen 443 ssl;
       server_name site.ru www.site.ru;

       # Настройки SSL
       ssl_certificate /etc/letsencrypt/live/site.ru/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/site.ru/privkey.pem;
       ssl_protocols TLSv1.2 TLSv1.3;
       ssl_ciphers 'HIGH:!aNULL:!MD5';

       location / {
           proxy_pass http://x.x.x.x:8080;
           proxy_set_header Host $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Real-IP $remote_addr;
       }
   }
   ```

4. **Перезагрузите Nginx**:

   ```bash
   sudo systemctl reload nginx
   ```

#### 2. Настройка самоподписанного сертификата на локальном сервере

Теперь необходимо создать самоподписанный сертификат на локальном сервере (192.168.0.10):

1. **Создайте самоподписанный сертификат**:

   ```bash
   sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
       -keyout /etc/nginx/ssl/selfsigned.key \
       -out /etc/nginx/ssl/selfsigned.crt
   ```

   Убедитесь, что вы указываете правильные параметры на запрос (Common Name должен совпадать с тем именем, которое будет использовать ваш локальный сервер).

2. **Настройте Nginx на локальном сервере** для работы по HTTPS:

   Пример конфигурации вашего Nginx на локальном сервере:

   ```nginx
   server {
       listen 443 ssl;
       server_name localhost;

       ssl_certificate /etc/nginx/ssl/selfsigned.crt;
       ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

       location / {
           # Директивы для обработки запросов
       }
   }
   ```

3. **Перезагрузите Nginx на локальном сервере**:

   ```bash
   sudo systemctl reload nginx
   ```

#### 3. Настройка проксирования с VPS на локальный сервер

Теперь вам нужно изменить конфигурацию Nginx на VPS для того, чтобы он мог отправлять запросы на локальный сервер по HTTPS.

В разделе `location` вашего Nginx на VPS измените строку `proxy_pass` как показано ниже:

```nginx
location / {
    proxy_pass https://192.168.0.10:443;  # Изменение на HTTPS
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;

    # Установим игнорировать ошибки сертификатов 
    proxy_ssl_verify off;  # Не проверять сертификат
}
```

### Альтернативные способы

1. **Использование VPN**: Если у вас есть возможность установить соединение по VPN между VPS и локальным сервером, вы можете настроить HTTPS только на VPS, а локальный сервер будет доступен по локальному IP без шифрования.

2. **Использование SSH Tunneling**: Если вы не можете использовать VPN, можно использовать SSH-туннелирование для
в принципе всё верно, правда что такое "первая нога" и "вторая нога" не сразу понял 
для такого варианта какой-то сертификат для конечного nginx нужен, но какой именно неважно, ЕМНИП по умолчанию nginx не проверяет валидность сертификатов при proxy_pass на https

можно ещё посмотреть на модуль stream и proxy-протокол, тогда проксирующий nginx будет тупо перенаправлять трафик и ничего расшифровывать и снова шифровать не будет, терминированием ssl-сессии будет заниматься конечный nginx
у этого способа есть свои недостатки — порты на конечном nginx нужны отдельные чтобы принимать proxy-протокол, проксирующий nginx не будет ничего знать о доменах, т.к. по большому способу будет работать на уровне tcp
Похожие вопросы