Что такое OpenConnect и как его установить
Пошаговая инструкция по установке и настройке сервера OpenConnect.
OpenConnect (ocserv) — это open-source VPN-решение, которое обеспечивает безопасный удаленный доступ к внутренним ресурсам организации за счет построения SSL/TLS-туннеля. Он поддерживает различные методы аутентификации, а также является бесплатной альтернативной коммерческому Cisco AnyConnect.
В статье рассматривается VPN исключительно как инструмент для обеспечения безопасности и защиты данных внутри организации.
Ключевые особенности OpenConnect:
- безопасность — SSL/TLS шифрование защищает передаваемые данные от перехвата при корректной настройке соединения;
- гибкость — наличие кросс-платформенных клиентов Windows, Linux, macOS, iOS и Android;
- не требует сложной настройки файрвола, работает по общедоступным протоколам TCP/UDP 443, HTTPS;
- поддерживает различные методы аутентификации: RADIUS, 2FA (в том числе с OTP) и локальную (по паролю);
- совместим с клиентами Cisco AnyConnect.
Какую задачу решает и что потребуется для развертывания
Задача OpenConnect — обеспечить безопасный удаленный доступ из корпоративной или домашней сети к инфраструктуре, построенной в публичном облаке на базе VMware.
В тестовом стенде мы организуем доступ из домашней сети по VPN+RDP к виртуальной машине на базе Windows Server 2025, развернутой в инфраструктуре Selectel.
Мы покажем пример одного из возможных вариантов развертывания и настройки. При этом не будем подробно останавливаться на создании организации, виртуального дата-центра и Direct Connected-подсети, но оставим ссылки на подробные инструкции в нашей вечнозеленой документации.
Что потребуется для выполнения:
- наличие организации и виртуального дата-центра (vDC);
- Direct Connected-подсеть;
- локальная сеть и виртуальная машина с Windows Server 2025, к которой настраивается доступ;
- виртуальная машина с ОС Ubuntu 24.04 LTS — на ней мы будем разворачивать сервер OpenConnect;
- доменное имя — в рамках статьи используется лабораторный домен vpn.landfield.ru, делегированный в DNS-хостинг Selectel.
Логическая схема работы
Ниже представлена типичная клиент-серверная схема.

В качестве клиентов выступают пользователи, имеющие доступ в интернет, и приложение, совместимое с OpenConnect. В качестве сервера — сам OpenConnect-сервер, развернутый на виртуальной машине в инфраструктуре Selectel.
Между клиентом и сервером поднят защищенный SSL VPN-туннель, обеспечивающий связность между этими двумя точками.
Приступим к созданию ВМ.
- Создаем vApp и ВМ: Data Centers → vApps → New vApp → Add Virtual Machine:


Чекбокс Power On не ставим, так как перед включением нам потребуется добавить второй сетевой интерфейс для виртуальной машины. Это позволит избежать ручной настройки интерфейсов и рекастомизации ВМ.
2. На этапе добавления ВМ указываем имя, hostname, шаблон Ubuntu-24.04-LTS и Storage Policy:

Для сетевого интерфейса задаем имеющуюся подсеть Direct Connected:

Указываем IP mode Static — IP Pool:


3. Сразу создадим isolated сеть service_VMs 10.10.10.0/24: Data Centers → Networks → New:

У нас только один vDC, поэтому выбираем Current:

Тип сети Isolated:

В качестве внутренней сети будет использоваться service_VMs 10.10.10.0/24, шлюзом для которой станет 10.10.10.1/24:

Задаем пул адресов:

Секцию с DNS пропускаем → Finish:

4. Добавим созданную сеть в vApp OpenConnect: vApps → OpenConnect → Networks → New:

5. Создадим ВМ Terminal с Windows Server вне нашего vApp OpenConnect (можно и в том же vApp): Virtual Machines → New:

Указываем необходимые параметры и помещаем ВМ в созданную ранее сеть service_VMs:

6. Возвращаемся к ВМ ocserv и добавляем второй сетевой интерфейс: Virtual Machines → ocserv → NICs → Edit → New:

7. Включаем ВМ ocserv и ожидаем загрузки ОС. Пароль от root прописывается в профиле кастомизации в Details → Virtual Machines → ocserv → Guest OS Customization → Edit → Поле Specify password:



8. Подключаемся к виртуальной машине через консоль и проверяем, что ВМ получила IP-адрес из пула Direct Connected:

9. Убедимся, что локальный интерфейс также сконфигурировался:
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:50:56:01:61:35 brd ff:ff:ff:ff:ff:ff
altname enp11s0
inet 31.184.214.130/29 brd 31.184.214.135 scope global ens192
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe01:6135/64 scope link
valid_lft forever preferred_lft forever
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:50:56:01:61:38 brd ff:ff:ff:ff:ff:ff
altname enp19s0
inet 10.10.10.3/24 brd 10.10.10.255 scope global ens224
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe01:6138/64 scope link
valid_lft forever preferred_lft forever
В итоге мы имеем два сетевых интерфейса:
- ens192 — публичный интерфейс (WAN) с IP-адресом 31.184.214.130/29 из подсети Direct Connected, через который будет организован доступ к OpenConnect-серверу извне.
- ens224 — внутренний интерфейс (LAN) с IP-адресом 10.10.10.3/24 из подсети service_VMs. В этой подсети находится ВМ Terminal, до которой мы настраиваем доступ.
Далее выполним предварительную настройку ОС.
1. Для удобства подключимся по SSH. Можно работать и через консоль в Cloud Director, но настройка займет дольше времени ввиду отсутствия возможности копирования и вставки:
ssh root@31.184.214.130
2. Первоначально пропишем публичные DNS-серверы. В рамках данной инструкции мы укажем DNS-серверы Selectel, но можно использовать любые другие.
Откройте конфигурационный файл resolved.conf в текстовом редакторе nano:
nano /etc/systemd/resolved.conf
Раскомментируйте строки DNS и FallbackDNS и укажите IP-адреса 188.93.16.19, 188.93.17.19:

Сохраните изменения (Ctrl+O → Enter) и выйдите из редактора (Ctrl+X).
Перезапустим службу DNS, чтобы применить изменения, и выведем результат для проверки:
systemctl restart systemd-resolved && resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
DNS Servers: 188.93.16.19
Fallback DNS Servers: 188.93.17.19
Link 2 (ens192)
Current Scopes: none
Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Link 3 (ens224)
Current Scopes: none
Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
3. Укажем NTP-серверы Selectel. Для этого откройте конфигурационный файл timesyncd.conf:
nano /etc/systemd/timesyncd.conf
Раскомментируйте строки NTP, FallbackNTP и пропишите адреса ближайших NTP-серверов.
Мы будем использовать NTP-серверы СПб, поскольку наш vDC расположен в этом регионе. В качестве FallbackNTP укажем публичный ntp.msk-ix.ru:

Сохраните изменения (Ctrl+O → Enter) и выйдите из редактора (Ctrl+X).
Перезапустите службу systemd-timesyncd и проверьте, что синхронизация успешна:
systemctl restart systemd-timesyncd && timedatectl timesync-status
Server: 188.93.16.172 (0.spb.ntp.selectel.ru)
Poll interval: 1min 4s (min: 32s; max 34min 8s)
Leap: normal
Version: 4
Stratum: 3
Reference: 5CFF7E04
Precision: 1us (-25)
Root distance: 6.149ms (max: 5s)
Offset: +2.495ms
Delay: 1.433ms
4. Обновим ОС и пакеты до актуальных версий:
apt update && apt full-upgrade -y
Если вы подключались к виртуальной машине по SSH, то появится предупреждение «What do you want to do about modified configuration file sshd_config» — нажимаем Enter.
Выполните перезагрузку для применения обновлений:
reboot now
Удалите неиспользуемые пакеты после обновления:
apt --purge autoremove -y
5. Для корректной маршрутизации трафика необходимо включить пересылку трафика между сетевыми интерфейсами:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-sysctl.conf
6. [Опционально] Для оптимизации сетевого стека отключим IPv6, а также включим алгоритм TCP BBR (Bottleneck Bandwidth and RTT), чтобы повысить пропускную способность TCP.
echo "net.ipv6.conf.all.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
echo "net.ipv6.conf.default.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
echo "net.ipv6.conf.lo.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
echo "net.core.default_qdisc = fq" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
echo "net.ipv4.tcp_congestion_control = bbr" | sudo tee -a /etc/sysctl.d/99-sysctl.conf
7. Для применения изменений в системе выполните команду:
sysctl -p
В выводе должны отобразиться все внесенные изменения:
net.ipv4.ip_forward = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
Далее можно приступать к установке сервера OpenConnect.
Установка и настройка сервера OpenConnect (ocserv)
1. Для начала установим все необходимые пакеты. Во время установки появится запрос на сохранение существующих правил iptables — нажимаем Enter:
apt install -y ocserv certbot iptables iptables-persistent netfilter-persistent
Здесь:
- ocserv — OpenConnect VPN server;
- certbot — утилита для выпуска SSL-сертификата Let’s Encrypt;
- iptables — утилита для настройки и управления встроенным в Linux файрволом Netfilter;
- iptables-persistent и netfilter-persistent — утилиты для автоматизации сохранения правил iptables.
2. Сделаем резервную копию стандартного конфига ocserv.conf и создадим чистый рабочий конфиг без комментариев к параметрам:
cp /etc/ocserv/ocserv.conf{,.bak}
cat /etc/ocserv/ocserv.conf.bak | grep -v '^#' | sed '/^$/d' > /etc/ocserv/ocserv.conf
3. Выпустим SSL-сертификат Let’s Encrypt. Для его выпуска необходимо:
- наличие действующего почтового ящика;
- DNS A-запись, указывающая на IP-адрес нашего сервера 31.184.214.130 (инструкция по добавлению ресурсной записи в Selectel);
- открытый порт TCP/80. У нас UFW выключен по умолчанию, а iptables пока не настраивался, поэтому дополнительных действий не потребуется.
В нашем тестовом стенде будет использоваться домен vpn.landfield.ru с соответствующей А-записью:
root@ocserv:~# dig vpn.landfield.ru
; <<>> DiG 9.18.39-0ubuntu0.24.04.3-Ubuntu <<>> vpn.landfield.ru
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65012
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;vpn.landfield.ru. IN A
;; ANSWER SECTION:
vpn.landfield.ru. 55 IN A 31.184.214.130
Воспользуемся certbot:
certbot certonly --standalone --agree-tos --email example@email.ru -d vpn.landfield.ru
Вместо example@email.ru укажите существующий почтовый ящик, а vpn.landfield.ru замените на ваш домен.
Успешный вывод команды должен выглядеть следующим образом:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N
Account registered.
Requesting a certificate for vpn.landfield.ru
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/vpn.landfield.ru/fullchain.pem
Key is saved at: /etc/letsencrypt/live/vpn.landfield.ru/privkey.pem
This certificate expires on 2026-07-08.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OpenConnect также поддерживает и сертификат self-signed. Настроить его можно с помощью certtool.
4. Настроим автоматический перевыпуск сертификата Let’s Encrypt. Certbot автоматически создает задание renew в cron для перевыпуска сертификата. Проверить можно командой:
cat /etc/cron.d/certbot
Однако для применения изменений со стороны ocserv необходимо перезапускать соответствующую службу. Для этого создадим renewal-hook в certbot:
4.1. Создайте файл restart-ocserv.sh:
nano /etc/letsencrypt/renewal-hooks/deploy/restart-ocserv.sh
4.2. Вставьте команду и сохраните файл:
#!/bin/sh
systemctl restart ocserv
4.3. Сделайте файл исполняемым:
chmod +x /etc/letsencrypt/renewal-hooks/deploy/restart-ocserv.sh
Теперь сервис ocserv будет автоматически перезапускаться сразу после перевыпуска сертификата (renew срабатывает за 30 дней до истечения срока действия сертификата).
4.4. [Опционально] Проверить работу renewal-hook можно с помощью команды (certbot должен иметь версию >=2.6.0):
certbot renew --dry-run --run-deploy-hooks
Флаг –dry-run симулирует перевыпуск сертификата LE и запускает наш deploy-hook.
Флаг –run-deploy-hooks форсированно запускает скрипт restart-ocserv.sh, который мы создали в п. 4.
В случае успеха вы получите следующий вывод:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/vpn.landfield.ru.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for vpn.landfield.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/vpn.landfield.ru/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Если скрипт restart-ocserv.sh отработал, в статусе сервиса будет обновленный аптайм и событие о старте:
root@ocserv:~# systemctl status ocserv
● ocserv.service - OpenConnect SSL VPN server
Loaded: loaded (/usr/lib/systemd/system/ocserv.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-04-10 15:24:26 UTC; 4s ago
Docs: man:ocserv(8)
Main PID: 13174 (ocserv-main)
Tasks: 2 (limit: 2262)
Memory: 1.4M (peak: 1.5M)
CPU: 8ms
CGroup: /system.slice/ocserv.service
├─13174 ocserv-main
└─13175 ocserv-sm
Apr 10 15:24:26 ocserv systemd[1]: Started ocserv.service - OpenConnect SSL VPN server.
Apr 10 15:24:26 ocserv ocserv[13174]: note: skipping 'pid-file' config option
Apr 10 15:24:26 ocserv ocserv[13174]: note: vhost:default: setting 'plain' as primary authentication method
Apr 10 15:24:26 ocserv ocserv[13174]: note: setting 'file' as supplemental config option
Apr 10 15:24:26 ocserv ocserv[13174]: listening (TCP) on 0.0.0.0:443
5. Настроим конфигурационный файл ocserv.conf. Ниже будут приведены только те параметры, которые были изменены, остальные оставлены по умолчанию. Исходные значения и описание параметров можно посмотреть в созданном ранее резервном файле конфигурации ocserv.conf.bak или в документации OpenConnect.
nano /etc/ocserv/ocserv.conf
5.1. Указываем тип авторизации на VPN-сервере. При параметре plain будут использоваться учетные записи, сгенерированные с помощью команды ocpasswd и занесенные в файл /etc/ocserv/ocpasswd в зашифрованном виде.
Важно. По умолчанию в конфигурации указан путь до /passwd, но креды генерируются в /ocpasswd. Необходимо исправить на ocpasswd, иначе в дальнейшем авторизация на сервере не пройдет.
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
5.2. По умолчанию ocserv использует TCP/443 и UDP/443. Мы будем использовать только TCP/443, поэтому параметр udp-port закомментируем. Краткое практическое сравнение обоих вариантов будет в конце инструкции.
tcp-port = 443
#udp-port = 443
5.3. Добавляем пути до сгенерированных Let’s Encrypt сертификатов:
server-cert = /etc/letsencrypt/live/vpn.landfield.ru/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.landfield.ru/privkey.pem
5.4. Ограничиваем количество активных клиентов на сервере. При значении 0 лимит отсутствует:
max-clients = 50
5.5. Задаем количество устройств, с которых клиент может одновременно подключиться под одной и той же учетной записью (например, с ПК и смартфона). При значении 0 лимит отсутствует.
max-same-clients = 2
5.6. Для снижения вероятности разрыва соединения с сервером уменьшим значение интервала отправки keepalive-packets до 60 секунд:
keepalive = 60
5.7. Включаем MTU discovery. В некоторых кейсах это повышает производительность и стабильность VPN-сессий:
try-mtu-discovery = true
5.8. Отключаем устаревшие протоколы TLS 1.0 и TLS.1.1, у нас будут использоваться TLS 1.2 и TLS 1.3:
tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1"
5.9. Указываем домен нашего сервера:
default-domain = vpn.landfield.ru
5.10. Указываем клиентскую сеть. Клиенты будут получать IP-адреса именно из этого пула при подключении к серверу. Можно использовать любую серую сеть, главное — чтобы она не пересекалась с существующими сетями в вашей инфраструктуре или пользовательской сети:
ipv4-network = 10.11.11.0
ipv4-netmask = 255.255.255.0
5.11. Указываем DNS-серверы. Здесь могут быть как публичные DNS, так и внутренние (например, адрес контроллера домена с ролью DNS).
Дополнительно добавляем параметр для отправки всех DNS-запросов в VPN-туннель:
dns = 188.93.16.19
dns = 188.93.17.19
dns = 8.8.8.8
tunnel-all-dns = true
5.12. Укажем тип маршрутизации трафика в VPN-туннеле.
Есть три варианта:
- default — весь трафик пойдет через VPN-туннель (используется по умолчанию);
- split VPN —только указанные явно подсети и адреса будут «заворачиваться» в VPN-туннель;
- no route — только указанные явно подсети и адреса не будут «заворачиваться» в VPN-туннель.
Мы будем использовать default. Остальные строки route потребуется удалить или закомментировать:
#route = 10.0.0.0/8
#route = 172.16.0.0/12
#route = 192.168.0.0/16
route = default
Сохраняем все изменения (Ctrl + O → Enter) и выходим (Ctrl + X).
Итоговая конфигурация:
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
tcp-port = 443
#udp-port = 443
server-cert = /etc/letsencrypt/live/vpn.landfield.ru/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.landfield.ru/privkey.pem
run-as-user = ocserv
run-as-group = ocserv
socket-file = /run/ocserv-socket
chroot-dir = /var/lib/ocserv
isolate-workers = true
max-clients = 50
max-same-clients = 2
rate-limit-ms = 100
server-stats-reset-time = 604800
keepalive = 60
dpd = 90
mobile-dpd = 1800
switch-to-tcp-timeout = 25
try-mtu-discovery = true
cert-user-oid = 0.9.2342.19200300.100.1.1
tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1"
auth-timeout = 240
min-reauth-time = 300
max-ban-score = 80
ban-reset-time = 1200
cookie-timeout = 300
deny-roaming = false
rekey-time = 172800
rekey-method = ssl
use-occtl = true
pid-file = /run/ocserv.pid
log-level = 1
device = vpns
predictable-ips = true
default-domain = vpn.landfield.ru
ipv4-network = 10.11.11.0
ipv4-netmask = 255.255.255.0
dns = 188.93.16.19
dns = 188.93.17.19
dns = 8.8.8.8
tunnel-all-dns = true
ping-leases = false
#route = 10.0.0.0/8
#route = 172.16.0.0/12
#route = 192.168.0.0/16
route = default
cisco-client-compat = true
dtls-legacy = true
client-bypass-protocol = false
6. Настроим iptables.
6.1. Добавим разрешающие правила (INPUT):
iptables -A INPUT -i lo -j ACCEPT -m comment --comment "Allow loopback traffic for internal services"
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow replies to outgoing requests"
iptables -A INPUT -p tcp --dport 22 -j ACCEPT -m comment --comment "Allow SSH TCP/22"
iptables -A INPUT -p tcp --dport 443 -j ACCEPT -m comment --comment "Allow TCP/443 traffic"
iptables -A INPUT -p udp --sport 53 -j ACCEPT -m comment --comment "ALlow DNS UDP/53"
iptables -A INPUT -p udp --sport 123 -j ACCEPT -m comment --comment "Allow NTP UDP/123"
iptables -A INPUT -p icmp -j ACCEPT -m comment --comment "Allow Ping/ICMP"
Если вы используете конфигурацию TCP+UDP, добавьте правило для UDP:
iptables -A INPUT -p udp --dport 443 -j ACCEPT -m comment --comment "Allow UDP/443 traffic"
6.2. Настроим маршрутизацию трафика (FORWARD):
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow established VPN traffic"
iptables -A FORWARD -i vpns+ -s 10.11.11.0/24 -j ACCEPT -m comment --comment "Allow traffic from VPN clients"
Здесь:
- vpns+ — имя нашего tun-интерфейса в ocserv.conf из параметра device;
- 10.11.11.0/24 — подсеть VPN-клиентов из параметра ipv4-network.
6.3. Настроим NAT (POSTROUTING):
iptables -t nat -A POSTROUTING -s 10.11.11.0/24 -o ens192 -j SNAT --to-source 31.184.214.130 -m comment --comment "SNAT for VPN to WAN"
iptables -t nat -A POSTROUTING -s 10.11.11.0/24 -o ens224 -j SNAT --to-source 10.10.10.2 -m comment --comment "SNAT for VPN to LAN"
Без настройки SNAT VPN to LAN сервер не сможет корректно маршрутизировать обратные пакеты клиентам. Данное правило не требуется, если на целевых узлах или шлюзе сети есть возможность настроить статический обратный маршрут.
Правило VPN to WAN используется в кейсах, когда требуется, чтобы клиенты выходили в интернет под IP-адресом сервера.
6.4. Опционально. Настроим MSS Clamping:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -m comment --comment "MSS Clamping for TCP"
6.5. Установим политики по принципу «запрещено все, что не разрешено»:
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
6.6. Сохраним конфигурацию iptables. Без этого действия все правила после перезагрузки сервера пропадут.
netfilter-persistent save
Посмотреть действующие правила можно с помощью команд:
iptables -L -n -v --line-numbers
iptables -t nat -L -n -v --line-numbers
iptables -t mangle -L -n -v --line-numbers
7. Создадим пользователя selectel для авторизации на сервере OpenConnect:
ocpasswd -c /etc/ocserv/ocpasswd selectel
После выполнения команды необходимо будет задать пароль. Логин хранится в открытом виде, а пароль — в зашифрованном:
root@vpn:~# cat /etc/ocserv/ocpasswd
selectel:*:$5$L6S.HJFUkoe/Y6FC$pXZcoOzt6pfXRsL7RfKvxFhdhVelXiWhFyZpsAXurG1
8. Запускаем сервер, добавляем сервис в автозагрузку и проверяем, что он активен и работает:
systemctl enable --now ocserv && systemctl status ocserv
ocserv.service - OpenConnect SSL VPN server
Loaded: loaded (/usr/lib/systemd/system/ocserv.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-04-09 11:18:43 UTC; 14s ago
Docs: man:ocserv(8)
Main PID: 3801 (ocserv-main)
Tasks: 2 (limit: 2262)
Memory: 1.4M (peak: 1.7M)
CPU: 12ms
CGroup: /system.slice/ocserv.service
├─3801 ocserv-main
└─3802 ocserv-sm
Apr 09 11:18:43 vpn.landfield.ru systemd[1]: Started ocserv.service - OpenConnect SSL VPN server.
Apr 09 11:18:43 vpn.landfield.ru ocserv[3801]: note: skipping 'pid-file' config option
Apr 09 11:18:43 vpn.landfield.ru ocserv[3801]: note: vhost:default: setting 'plain' as primary authentication method
Apr 09 11:18:43 vpn.landfield.ru ocserv[3801]: note: setting 'file' as supplemental config option
Apr 09 11:18:43 vpn.landfield.ru ocserv[3801]: listening (TCP) on 0.0.0.0:443...
Сервис запущен, сервер готов принимать подключения по TCP 443. На этом настройка сервера завершена.
Можно приступать к настройке клиента и проверке наличия доступа к нашей ВМ Terminal.
Настройка клиента OpenConnect и подключение к OpenConnect-серверу
В качестве клиента для ОС Windows будем использовать open-source решение OpenConnect VPN.
1.Загружаем клиент с официального сайта.
2. Запускаем исполняемый файл и нажимаем Далее → Установить:

3. Запускаем OpenConnect VPN graphical client → Нажимаем на шестеренку → New Profile (advanced).
Указываем имя, адрес нашего сервера, протокол, а также ставим чекбокс Disable UDP.
Если при настройке ocserv в п. 5.2. вы оставляли и UDP, и TCP порт, то чекбокс ставить не нужно.

На этом настройка завершена. Для подключения к нашему серверу нажимаем Connect.
Если вы используете Cisco AnyConnect Secure Mobility Client v4.x, то никаких дополнительных настроек не потребуется, достаточно ввести адрес сервера и логин-пароль:

Отметим, что при прямом сравнении обоих клиентов OpenConnect VPN в текущей конфигурации выдает результаты по скорости в ~2 раза выше, чем Cisco AnyConnect.
Проверка работы VPN-сервера и наличия доступа к тестовой ВМ
1.Подключаемся к нашему OpenConnect-серверу и вводим пароль от пользователя selectel:

2. Проверяем, что IP-адрес и DNS-серверы получены те, что мы указали в ocserv.conf:

3. Проверяем доступность нашей ВМ Terminal 10.10.10.2 по RDP порту через PowerShell (ping не используем, т.к. по умолчанию ICMP-трафик заблокирован в брандмауэре Windows):
tnc 10.10.10.2 -p 3389
ComputerName : 10.10.10.2
RemoteAddress : 10.10.10.2
RemotePort : 3389
InterfaceAlias : vpn.landfield.ru_4c4a4d2b
SourceAddress : 10.11.11.163
TcpTestSucceeded : True
Порт доступен.
Подключение по RDP проходит успешно:

Сравнение пропускной способности VPN-канала на конфигурациях TCP+UDP 443 и только TCP/443:
TCP/443 + UDP/443:

TCP/443:

На тестовом стенде при использовании конфигурации без UDP/443 исходящая скорость возрастает в ~3,5 раза. Тем не менее итоговый результат зависит от условий тестирования и клиентской или серверной части, поэтому для достижения оптимального соотношения производительности и стабильности канала потребуется потратить некоторое время на проверку различных вариантов конфигураций.
Бонус: развертываем OpenConnect-сервер с помощью Ansible
Для установки OpenConnect посредством Ansible нам потребуется любая виртуальная машина с доступом по SSH, которая будет выступать в роли control-node. Мы в качестве примера возьмем ВМ на базе Ubuntu 24.04 LTS.
Установка Ansible простая и выполняется в несколько команд:
sudo apt update && sudo apt install software-properties-common sshpass -y
sudo add-apt-repository --yes --update ppa:ansible/ansible && sudo apt install ansible -y
Проверяем, что установка прошла успешно:
ansible --version
ansible [core 2.16.3]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
Далее устанавливаем Git и клонируем репозиторий:
sudo apt install git -y && git clone https://github.com/venberg-slctl/ocserv.git
После заполнения всех необходимых переменных, описанных в Readme, запускаем плейбук ocserv_setup.yml и вводим пароль:
ansible-playbook -i hosts ocserv_setup.yml -u root -k
Обращаем ваше внимание, что данный плейбук подразумевает деплой OpenConnect-сервера на чистой ВМ. Перед деплоем на уже рабочих виртуальных машинах внимательно ознакомьтесь с содержанием ролей Ansible.
Ожидаем завершения работы плейбука:
PLAY [Create and configure OpenConnect-server] ************************************************************************************************************
TASK [basic_setup : Configure DNS-servers] ****************************************************************************************************************
changed: [ocserv]
TASK [basic_setup : Configure NTP-servers] ****************************************************************************************************************
changed: [ocserv]
TASK [basic_setup : Force handlers for DNS and NTP] *******************************************************************************************************
RUNNING HANDLER [basic_setup : Restart systemd-resolved] **************************************************************************************************
changed: [ocserv]
RUNNING HANDLER [basic_setup : Restart systemd-timesyncd] *************************************************************************************************
changed: [ocserv]
TASK [basic_setup : Update packages and upgrade kernel to the latest version] *****************************************************************************
changed: [ocserv]
TASK [basic_setup : Force reboot if upgrade needed] *******************************************************************************************************
RUNNING HANDLER [basic_setup : Reboot virtual machine] ****************************************************************************************************
changed: [ocserv]
...
RUNNING HANDLER [ocserv : Restart and enable ocserv.serivce] **********************************************************************************************
changed: [ocserv]
TASK [Reboot VM] ******************************************************************************************************************************************
changed: [ocserv]
PLAY RECAP ************************************************************************************************************************************************
ocserv : ok=31 changed=29 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Если процесс завершился без ошибок, сервер готов принимать подключения.