Перейти к содержимому

Конфигурация сервера

Сервер читает конфигурацию из файла TOML (по умолчанию: server.toml).

Окно терминала
rvpn-server -c /etc/rvpn/server.toml

[server]
bind_address = "0.0.0.0:443"
tls_cert_file = "/etc/letsencrypt/live/your-domain.com/fullchain.pem"
tls_key_file = "/etc/letsencrypt/live/your-domain.com/privkey.pem"
identity_key_file = "/etc/rvpn/server_identity.key"

[server]
bind_address = "0.0.0.0:443"
tls_cert_file = "/etc/letsencrypt/live/example.com/fullchain.pem"
tls_key_file = "/etc/letsencrypt/live/example.com/privkey.pem"
identity_key_file = "/etc/rvpn/server_identity.key"
websocket_path = "/api/v1/ws"
http_port = 80
[server.network]
nat_enabled = true
dhcp_range = "10.200.0.0/24"
dns_servers = ["1.1.1.1", "8.8.8.8"]
[server.rate_limit]
max_connections_per_ip = 500
max_handshakes_per_minute = 2000
[server.tun]
enabled = true
tun_ip = "10.200.0.1/24"
mtu = 1420
interface_name = "tun0"

Выполните эти команды один раз при развёртывании нового сервера:

Окно терминала
cd /etc/rvpn
# Сгенерировать долгосрочный ключ идентификации сервера
rvpn-server keygen
# Сгенерировать набор prekey (используется клиентами для аутентификации)
rvpn-server prekey-bundle

Это создаёт:

  • server_identity.key — пара ключей Ed25519 идентификации сервера. Сделайте резервную копию и храните в секрете.
  • prekey-bundle.json — публичный набор prekey. Распространяйте среди клиентов.
  • prekey-bundle.private.json — приватный подписанный prekey-материал. Храните в секрете.

Ротация prekey не автоматизирована в текущем сервере — регенерируйте набор prekey вручную командой rvpn-server prekey-bundle, когда захотите провести ротацию. Клиентам не нужны обновлённые наборы prekey, когда одноразовые prekey сервера исчерпываются; свежий набор нужен только при смене ключа идентификации сервера.

Существующие клиенты закрепляют ключ идентификации сервера при первом подключении (см. Закрепление идентификации сервера). Чтобы ротовать ключ, не ломая этих клиентов, подпишите новый bundle старым ключом — так клиент сможет проверить цепочку:

Окно терминала
cd /etc/rvpn
# Сохраняем старый ключ, чтобы подписать ротацию
mv server_identity.key old_identity.key
# Генерируем новый
rvpn-server keygen --output server_identity.key
# Публикуем v2 bundle, подписанный old_identity.key
rvpn-server prekey-bundle \
--identity server_identity.key \
--output prekey-bundle.json \
--rotate-from old_identity.key \
--from-version 1

--rotate-from и --from-version обязательны вместе. Выложите новый prekey-bundle.json клиентам как обычно — уже закреплённые клиенты обновятся молча, новые закрепят новый ключ при первом подключении. Заархивируйте old_identity.key после публикации, чтобы иметь возможность подписать следующую ротацию от этой версии.


Сертификаты Let’s Encrypt истекают каждые 90 дней. Certbot автоматически устанавливает cron-задание для обновления.

После обновления перезапустите rVPN, чтобы подхватить новый сертификат:

Окно терминала
sudo systemctl restart rvpn-server

Для автоматизации добавьте deploy-hook:

/etc/letsencrypt/renewal-hooks/deploy/rvpn-reload.sh
#!/bin/bash
systemctl restart rvpn-server
Окно терминала
chmod +x /etc/letsencrypt/renewal-hooks/deploy/rvpn-reload.sh

Сервер автоматически возвращает жёстко зашитую страницу 404 в стиле nginx для любого не-WebSocket запроса. Снаружи это выглядит как ненастроенный веб-сервер, а не как точка VPN. Для полностью кастомного сайта-приманки терминируйте TLS на обратном прокси и пересылайте только /api/* на rVPN — см. Настройка обратного прокси для рецептов Caddy, nginx и HAProxy с настоящим сайтом-приманкой в корне.


Если вы работаете за Caddy, nginx или HAProxy, опустите файлы сертификата/ключа и привяжите к локальному порту:

[server]
bind_address = "127.0.0.1:8443"
websocket_path = "/api/v1/ws"
# Нет tls_cert_file / tls_key_file — TLS терминируется на прокси

См. Настройка обратного прокси для полных конфигураций Caddy, nginx и HAProxy, включая настройку сайта-приманки и балансировку нагрузки между несколькими серверами.


Сервер ограничивает частоту входящих соединений по IP-адресу клиента, чтобы предотвратить злоупотребления.

[server.rate_limit]
max_connections_per_ip = 500
max_handshakes_per_minute = 2000
  • max_connections_per_ip — максимальное количество одновременных соединений с одного IP-адреса.
  • max_handshakes_per_minute — максимальное количество новых попыток рукопожатия с одного IP в минуту.

[!WARNING] В устаревшем (немультиплексированном) SOCKS5-режиме протокол открывает одно WebSocket-соединение на TCP-поток. Современная страница в браузере легко может открыть 20–50 одновременных соединений (HTML, CSS, JS, изображения, вызовы API). Если ваши лимиты слишком низкие, соединения будут молча отбрасываться, а страницы не будут загружаться.

Для серверов, обслуживающих устаревших SOCKS5-клиентов, установите max_connections_per_ip не менее 500, а max_handshakes_per_minuteне менее 2000. Повышайте эти значения в зависимости от ожидаемого числа одновременных соединений на пользователя.

[!NOTE] Мультиплексированный SOCKS5-режим (один WebSocket, множество потоков) — умолчание в современных клиентах. Он полностью снимает проблему ограничения скорости, так как все потоки делят одно соединение. Установите multiplex = true в конфиге клиента, чтобы включить его.

Когда соединение ограничено, сервер логирует Rate limited: <IP> на уровне debug и закрывает соединение без ответной ошибки.


См. Справочник конфигурации сервера для полного списка всех доступных настроек.