Двойной OpenVPN. Установка и настройка

11.12.2024

Теги: LinuxUbuntuVPNКлиентКлючНастройкаСерверУстановка

Суть этой технологии в том, что интернет‑трафик проходит через два VPN-сервера вместо одного. Сначала трафик приходит на первый VPN-сервер, и оттуда направляется на второй VPN-сервер. Для примера, компьютер в домашней сети соединяется с VPN-сервером в России, а этот сервер соединяется c VPN-сервером за рубежом. При этом сервер в России будет одновременно — VPN-сервером для домашнего компа и VPN-клиентом для сервера за рубежом.

OpenVPN поддерживает два варианта установления соединения

  • PSK (PreSharedKey или static key mode) — с симметричным ключом, который генерируется и записывается на все машины в процессе настройки VPN. Сгенерированный файл ключа содержит две пары 512 битных случайных ключей (в каждой паре ключ для шифрования и ключ для HMAC), записанные один за другим и закодированные в HEX. Если для директивы secret не задать параметр direction, то будет использоваться только первая пара, т.е. в обе стороны трафик будет шифроваться и подписываться одинаковыми ключами.
  • TLS (Transport Layer Security) — основан на инфраструктуре открытых ключей (PKI). Вначале устанавливается TLS соединение с аутентификацией обеих сторон по сертификатам, через которое производится обмен ключевым материалом. Из этого ключевого материала генерируются симметричные ключи и трафик внутри VPN шифруется уже этими ключами так же как в режиме PSK. Внутри TLS канала пользовательского трафика нет — исключительно служебная информация самого OpenVPN.

Рассмотрим пять варианта настройки двойного OpenVPN

  1. OpenVPN, точка-точка, PSK (static key), протокол UDP, порт 1194
  2. OpenVPN, точка-точка, PSK (static key), протокол TCP, порт 1234
  3. OpenVPN, точка-точка, TLS (finger print), протокол UDP, порт 1194
  4. OpenVPN, точка-точка, TLS (finger print), протокол TCP, порт 1234
  5. OpenVPN, сервер-клиенты, TLS (finger print), протокол TCP, порт 443
Директива secret была объявлена deprecated в OpenVPN 2.6 и будет удалена в OpenVPN 2.7 — так что лучше использовать TLS вместе с finger print.

Все серверы и компьютеры будут под управлением операционной системы Ubuntu Server. Роль VPN-клиента в домашней сети будет играть виртуальная машина. Роль VPN-клиентов ivanov и petrov в пятом варианте — облачные серверы разных провайдеров.

Установка пакета OpenVPN

В самом простом случае можно установить OpenVPN из репозитория Ubuntu

# apt install openvpn

Чтобы установить самую последнюю версию OpenVPN или наоборот, какую-то старую версию — нужно добавить репозиторий. Пакеты в репозитории подписаны закрытым OpenPGP ключом репозитория, а чтобы проверить их подлинность, потребуется открытый OpenPGP ключ. Каждый репозиторий доверяет только собственному ключу, а сами ключи помещаются в специальное хранилище /usr/share/keyrings, к которому имеет доступ только суперпользователь.

Ключ может быть в двух форматах — текстовом (расширение файла .asc) и бинарном (расширение файла .gpg). Текстовые ключи наиболее распространены, так как этот формат более удобен при передаче. Но ключ в хранилище должны быть в бинарном формате, то есть, потребуется преобразование.

Скачать ключ, преобразовать в бинарный формат и записать в хранилище

# curl -fsSL https://swupdate.openvpn.net/repos/repo-public.gpg | gpg --dearmor > /usr/share/keyrings/openvpn.gpg

Теперь нужно создать файл .list в директории /etc/apt/sources.list.d

# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/openvpn.gpg] \
> https://build.openvpn.net/debian/openvpn/stable $(lsb_release -cs) main" > \
> /etc/apt/sources.list.d/openvpn.list

Теперь получим данные о новых, доступных к установке, пакетах

$ sudo apt update

Посмотрим, какая последняя версия доступна для установки

# apt-cache policy openvpn
openvpn:
  Установлен: (отсутствует)
  Кандидат:   2.6.12-jammy0
  Таблица версий:
     2.6.12-jammy0 500
        500 https://build.openvpn.net/debian/openvpn/stable jammy/main amd64 Packages
     2.6.11-jammy0 500
        500 https://build.openvpn.net/debian/openvpn/stable jammy/main amd64 Packages
     2.6.10-jammy0 500
        500 https://build.openvpn.net/debian/openvpn/stable jammy/main amd64 Packages
     2.6.9-jammy0 500
        500 https://build.openvpn.net/debian/openvpn/stable jammy/main amd64 Packages
     2.6.8-jammy0 500
        500 https://build.openvpn.net/debian/openvpn/stable jammy/main amd64 Packages
..........

Установим последнюю доступную версию OpenVPN — это 2.6.12

# apt install openvpn

Директивы конфигурации OpenVPN

Чтобы не запутаться в директивах конфигурации — следует помнить о всех вариантах настройки

  1. OpenVPN может работать в режиме «точка-точка» (mode p2p) или в режиме «сервер-клиенты» (mode server)
  2. OpenVPN может использовать PSK (общий ключ шифрования известен каждой стороне заранее) или TLS (общий ключ шифрования создается каждой стороной в процессе обмена — с использованием алгоритма Diffie-Hellman)
  3. OpenVPN может работать по протоколу UDP или по протоколу TCP, хотя предпочтительный вариант — UDP

Директивы mode и topology

Директива mode p2p|server задает основной режим работы OpenVPN. По умолчанию OpenVPN работает в режиме p2p, то есть «точка-точка». Относительно новый режим server реализует возможность сервера с множеством клиентов.

Директива topology p2p|net30|subnet задает топологию виртуальной адресации при использовании dev tun. Эта директива не имеет значения при использовании dev tap, который всегда использует топологию subnet. В режиме «точка-точка» (mode p2p) — используется топология p2p, в режиме «сервер-клиенты» (mode server) — используется топология net30 или subnet.

Универсальным решением для режима «сервер-клиенты» является net30 — это значение по умолчанию. Сервер будет работать со всеми версиями Windows, Linux, Mikrotik. Каждый клиент работает в маленькой сети на четыре ip-адреса, внутри этой сети используется режим точка-точка, два ip-адреса внутри этой сети не используются (адрес сети и широковещательный). Топология net30 фактически устарела и сохраняется исключительно для поддержки старых Windows клиентов.

Значение subnet рекомендуется для режима «сервер-клиенты», когда клиентами являются Linux и Windows 8.2 и выше. Устройство tun будет настроено на использование ip-адреса и маски сети как «традиционная» широковещательная сеть. Сетевой и широковещательный ip-адреса не должны использоваться — хотя tun не имеет понятия о широковещании, клиенты Windows не смогут правильно использовать эти адреса. Все остальные ip-адреса в сети доступны для использования.

Значение p2p не может использоваться в системах Windows и не подходит, если сервер или любой клиент может быть Windows. В этой топологии все узлы настроены как настоящие двухточечные ссылки — каждый ip-адрес может использоваться, включая первый и последний. Другими словами, в сети 10.8.0.0/24 в топологии p2p можно использовать все 256 ip-адресов. Но Windows считает первый и последний ip-адреса сетевым и широковещательным адресами.

Директивы ifconfig и route

Директива ifconfig local remote в режиме p2p задает два серых ip-адреса локальной и удаленной конечных точек VPN-туннеля. Эти ip-адреса будет привязаны к tun-интерфейсам, которые создаются на этапе запуска службы OpenVPN.

Директива ifconfig ip-addr netmask в режиме server задает ip-адрес и маску подсети tun-интерфейса. Директива ifconfig-push позволяет назначить статический ip-адрес клиенту, используется вместе с директивой client-config-dir.

Директива route позволяет добавить маршрут в таблицу маршрутизации после установки соединения. Можно указать несколько маршрутов. Маршруты будут автоматически удалены в обратном порядке перед закрытием устройства tun/tap. Если значение netmask не задано — используется значение по умолчанию 255.255.255.255. Если значение gateway не задано — используется значение route-gateway или второго аргумента ifconfig.

route network/ip-addr
route network/ip-addr netmask
route network/ip-addr netmask gateway
route network/ip-addr netmask gateway metric

Директива route-gateway задает значение gateway для директивы route. Директива route-metric задает значение metric для директивы route.

Директива client-to-client

Директива client-to-client позволяет каждому клиенту «видеть» других клиентов, которые в данный момент подключены. В противном случае каждый клиент будет видеть только сервер. При этом пакеты от клиентов не попадают в сетевой стек сервера, где установлен OpenVPN сервер — речь идет о внутренней маршрутизации OpenVPN. Кроме использования директивы client-to-client можно разрешить пересылку пакетов между сетевыми интерфейсами. Это будет работать медленнее, но позволит задействовать всю мощь netfilter для фильтрации пакетов.

# sysctl -w -q net.ipv4.ip_forward=1
# iptables -P FORWARD DROP
# iptables -A FORWARD -i tun0 -o tun0 -j ACCEPT

Директива dh (Diffie-Hellman)

Директива dh file|none задет файл, который содержит параметры Diffie-Hellman в формате .pem. Директива используется только в файле конфигурации сервера, в режиме tls-server. Значение none предписывает не использовать файл Diffie-Hellman, а использовать протокол на элиптических кривых ECDH (Elliptic curve Diffie-Hellman) для получения общего ключа, которым будут шифроваться данные. Но для этого требуется, чтобы одноранговые узлы использовали библиотеку SSL, которая поддерживает наборы шифров ECDH TLS (например, OpenSSL 1.0.1+ или mbed TLS 2.0+).

Директивы iroute и client-config-dir

В большинстве случаев директива iroute не нужна, потребность в ней возникает, когда сетям за узлами VPN нужно обмениваться данными.

Предположим, что нужно установить связь между сетями 192.168.1.0/24 и 192.168.2.0/24, а также между 192.168.1.0/24 и 192.168.3.0/24 — тогда файлы конфигурации vpn_server будут выглядеть примерно так.

# cat /etc/openvpn/server/config.conf
dev tun
proto udp
port 1194
local 123.123.123.123

mode server
topology subnet
tls-server

ifconfig 10.8.0.1 255.255.255.0
# сообщить клиентам, что сеть 192.168.1.0/24 доступна через хост 10.8.0.1
push "route 192.168.1.0 255.255.255.0 10.8.0.1"

client-config-dir /etc/openvpn/ccd
# cat /etc/openvpn/ccd/client_one
# назначить клиенту client_one второй ip-адрес виртуальной VPN-сети
ifconfig-push 10.8.0.2 255.255.255.0
# сообщить серверу, что сеть 192.168.2.0/24 доступна через хост 10.8.0.2
route 192.168.2.0 255.255.255.0 10.8.0.2
# сообщить серверу, что за этим клиентом есть сеть 192.168.2.0/24
iroute 192.168.2.0 255.255.255.0
# cat /etc/openvpn/ccd/client_two
# назначить клиенту client_two третий ip-адрес виртуальной VPN-сети
ifconfig-push 10.8.0.3 255.255.255.0
# сообщить серверу, что сеть 192.168.3.0/24 доступна через хост 10.8.0.3
route 192.168.3.0 255.255.255.0 10.8.0.3
# сообщить серверу, что за этим клиентом есть сеть 192.168.3.0/24
iroute 192.168.3.0 255.255.255.0

Файл конфигурации client_one

# cat /etc/openvpn/client/config.conf
dev tun
proto udp

pull
tls-client
topology subnet

remote 123.123.123.123 1194

Файл конфигурации client_two

# cat /etc/openvpn/client/config.conf
dev tun
proto udp

pull
tls-client
topology subnet

remote 123.123.123.123 1194

Директива iroute сообщает OpenVPN о необходимости создания «внутреннего» маршрута OpenVPN к указанной сети через определенный узел.

Причина, по которой необходимы два маршрута, заключается в том, что директива route направляет пакет из ядра в OpenVPN. После попадания в OpenVPN — директива iroute направляет пакет к определенному клиенту. Этот фрагмент конфигурации спецефичен для каждого клиента (потому что за каждым клиентом могут быть разные сети), поэтому правильное место для добавления этой информации — каталог файлов конфигурации клиентов client-config-dir.

Вместо директивы iroute можно использовать SNAT на клиентах — но это потребует определенных накладных расходов на маскарадинг.

# iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o tun0 -j MASQUERADE # на vpn-клиенте client_one
# iptables -t nat -A POSTROUTING -s 192.168.3.0/24 -o tun0 -j MASQUERADE # на vpn-клиенте client_two

Директива client-config-dir задает каталог для файлов конфигурации клиентов. После аутентификации подключающегося клиента OpenVPN будет искать в этом каталоге файл с тем же именем, что и CommonName X509 клиента. Если соответствующий файл существует, он будет открыт и проанализирован на предмет параметров конфигурации, специфичных для клиента. Если соответствующий файл не найден, OpenVPN попытается открыть и проанализировать файл по умолчанию с именем DEFAULT, который может быть предоставлен, но не является обязательным. При этом файлы конфигурации должны быть доступны OpenVPN для чтения после сброса привилегий root.

Директивы remote и local

Директива remote задает хост, протокол, порт сервера, к которому клиент должен подключиться. При использовании протокола TCP директива работает как фильтр, отклоняя соединения с любого хоста, который не соответствует host. При использовании протокола UDP — OpenVPN будет принимать пакеты с любых адресов, но не будет их использовать, пока пакеты не пройдут аутентификацию (очень лекко подделать ip-адрес источника в UDP пакете).

remote host
remote host port
remote host port proto

Директива local задает ip-адрес сетевого интерфейса, который нужно простушивать. Если директива не задана — будут прослушиваться все сетевые интерфейсы.

Директивы proto и port

Директива proto задает протокол и может принимать значения udp, tcp-client, tcp-server. Для работы по UDP необходимо указать proto udp на сервере и на клиенте (это значение по умолчанию). Для работы по TCP один узел должен использовать значение tcp-server, а все прочие — значение tcp-client. Узел tcp-server будет бесконечно ожидать входящего соединения. Узел tcp-client будет пытаться подключиться с заданным интервалом между попытками (директива connect-retry). И будет делать это бесконечно или заданное кол-во раз (директива connect-retry-max).

Директива port задает номер порта TCP/UDP как для локального, так и для удаленного хоста, по умолчанию 1194. Другими словами, устанавливает значения директив lport и rport.

В файле конфигурации сервера директива lport устанавливает значение, на котором сервер будет принимать пакеты от клиента. В файле конфигурации клиента директива lport устанавливает значение, с которого клиент будет отправлять сообщения серверу. Директива lport на клиенте несовместима с директивой nobind.

Директива rport задает значение port для директивы remote.

Директива nobind предписывает не использовать фиксированный номер порта. Операционная ситема выделит динамический порт для приема пакетов, которые приходят с сервера. Поскольку значение динамического порта не может быть известно заранее, директива может быть использована только на клиенте. Директива nobind несовместима с директивой lport.

Директивы data-ciphers и auth

Директива data-ciphers задает набор алгоритмов шифрования для канала передачи данных. Если директива не задана, то для OpenVPN 2.5 и выше — значение по умолчанию будет AES-256-GCM:AES-128-GCM. Сервер выбирает первый шифр в этом списке, который также есть на стороне клиента. Если общий шифр не найден, клиент отклоняется с сообщением AUTH_FAILED. Для OpenVPN 2.5 можно дополнить этот список с помощью директивы cipher. Для OpenVPN 2.6 этот список можно дополнить, если указана директива compat-mode.

Директива auth alg|none позволяет добавлять подпись HMAC для всех пакетов канала передачи данных с использованием алгоритма alg (по умолчанию SHA1). В режиме шифрования со статическим ключом ключ HMAC включается в файл ключа. В режиме TLS ключ HMAC динамически генерируется и передается между узлами через канал управления TLS. Если OpenVPN получает пакет с плохим HMAC — этот пакет сразу отбрасывается. Обычно HMAC добавляет 16 или 20 байт на пакет. Чтобы отключить HMAC — нужно установить значение none.

Директива tls-auth позволяет добавлять подпись HMAC для всех пакетов канала управления TLS для смягчения DoS-атак и атак на стек TLS. Директива включает своего рода «брандмауэр HMAC» на порту TCP/UDP OpenVPN, где пакеты канала управления TLS, содержащие неверную подпись HMAC, могут быть немедленно отброшены без ответа. Рекомендуется использовать при запуске OpenVPN в режиме, в котором он прослушивает пакеты с любого ip-адреса — например, когда директива remote не указана.

Директивы user и group

Директивы user и group позволяют понизить права службы сервера и клиента — это нужно для повышения безопасности. Директивы persist-tun и persist-key обеспечивают правильную работу после понижения прав.

Директива keepalive

Директива keepalive является макрокомандой и будет преобразована в директивы ping и ping-restart. В режиме p2p директиву нужно использовать как на сервере, так и на клиенте. В режиме server директиву нужно указывать только на сервере — сервер сам отправит клиенту ping и ping-restart. При этом значения с сервера переопределят локальные значения клиента, если они были установлены.

keepalive interval timeout

Например, директива keepalive 10 60 будет преобразована по следующему алгоритму

if mode server:
    ping 10                    # Argument: interval
    ping-restart 120           # Argument: timeout*2
    push "ping 10"             # Argument: interval
    push "ping-restart 60"     # Argument: timeout
else
    ping 10                    # Argument: interval
    ping-restart 60            # Argument: timeout

Директива ping n предписывает пинговать удаленный узел по каналу управления, если пакеты не отправлялись как минимум последние n секунд. Директиву нужно задавать как на одном, так и на другом конце VPN-туннеля — поскольку ping OpenVPN не отражается эхом.

Директива ping-restart n в файле конфигурации клиента предписывает подключиться к серверу снова, если прошло n секунд без получения ping или пакета данных. Для клиента значение по умолчанию равно 120 секунд (если не было получено другое значение с сервера). Директива ping-restart n в файле конфигурации сервера предписывает отключить этого клиента, если прошло n секунд без получения ping или пакета данных.

Директива explicit-exit-notify

Директива explicit-exit-notify предписывает серверу и клиенту уведомлять друг друга о завершеннии работы службы OpenVPN. Клиент, при получении такого сообщения — попытается подключиться снова. Сервер, при получении такого сообщения — закроет соединение с этим клиентом. Значение по умолчнию — единица (то есть, уведомления разрешены).

Примеры конфигурации

Пример файла конфигурации сервера в режиме server с множеством клиентов, TLS (Transport Layer Security), протокол UDP

dev tun
proto udp
lport 1194

# сертификат Центра Сертификации
ca /etc/openvpn/keys/ca.crt
# приватный ключ сервера
key /etc/openvpn/keys/server.key
# сертификат сервера
cert /etc/openvpn/keys/server.crt

# режим сервер + много клиентов
mode server
# это сервер при TLS handshake
tls-server
# топология виртуальной сети
topology subnet

# ip-адрес и маска сервера
ifconfig 10.8.0.1 255.255.255.0
# диапазон адресов для клиентов
ifconfig-pool 10.8.0.2 10.8.0.100
# шлюз по умолчанию для сети
route-gateway 10.8.0.1
# клиенты видят друг друга
client-to-client

# сообщить клиентам топологию
push "topology subnet"
# сообщить клиентам шлюз сети
push "route-gateway 10.8.0.1"

keepalive 10 60
user nobody
group nogroup
persist-key
persist-tun

Пример файла конфигурации клиента, когда для сервера установлен режим server, TLS (Transport Layer Security), протокол UDP

dev tun
proto udp

# сертификат Центра Сертификации
ca /etc/openvpn/keys/ca.crt
# приватный ключ клиента
key /etc/openvpn/keys/client.key
# сертификат клиента
cert /etc/openvpn/keys/client.crt

# принимать от сервера директивы
pull
# это клиент при TLS handshake
tls-client
# ip-адрес и порт сервера
remote 123.123.123.123 1194
# динамический номер порта
nobind

user nobody
group nogroup
persist-key
persist-tun

1. OpenVPN, точка-точка, PSK (static key), протокол UDP, порт 1194

Это вариант настройки OpenVPN с использованием static key. Мы даже не будем создавать два файла ключей static.key, а ограничимся одним. То есть, трафик между клиентом и первым VPN-сервером и трафик между первым VPN-сервером и вторым VPN-сервером будут шифроваться с использованием одного файла static.key.

Создать ключ можно с помощью команды

# openvpn --genkey secret /etc/openvpn/keys/static.key
# cat /etc/openvpn/keys/static.key
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
ae6d0316156ef7ee7afe15448dd95a59
de286c12d4c18fbab8ae3b22f5f8e7c9
27794d3b2a116a35c7eab0716e3c9f03
bf7dd359ccf26983465687ec13c7d05c
86e2318b53e7e7d5c71491b338db0237
e4944e8fbbed421b8b6cabc8318f298c
f06f6de53024057792a797e33bb73c57
934dd97ac1f2e8d78ccb84e3749dc3d5
301afa1c4640cf2126b775e4d2af91b2
27267603e59bc8d42ffb65b1c9b83041
f0151531148e65100d48e378c9aa7031
e4993fe2e897c8db3054ae7f29140f17
c98e353cffbd14b6641f4b3af0841707
49088cda08d0c507c99f557c7a611fed
000eaaea8fb32eb25fae7cfd8920a383
cf377b7dce4c0b03c90dac80f6288ba5
-----END OpenVPN Static key V1-----

В файлах конфигурации можно указывать путь к этому файлу или разместить ключ прямо внутри конфигурации

secret /etc/openvpn/keys/static.key 0
<secret>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
ae6d0316156ef7ee7afe15448dd95a59
de286c12d4c18fbab8ae3b22f5f8e7c9
27794d3b2a116a35c7eab0716e3c9f03
bf7dd359ccf26983465687ec13c7d05c
86e2318b53e7e7d5c71491b338db0237
e4944e8fbbed421b8b6cabc8318f298c
f06f6de53024057792a797e33bb73c57
934dd97ac1f2e8d78ccb84e3749dc3d5
301afa1c4640cf2126b775e4d2af91b2
27267603e59bc8d42ffb65b1c9b83041
f0151531148e65100d48e378c9aa7031
e4993fe2e897c8db3054ae7f29140f17
c98e353cffbd14b6641f4b3af0841707
49088cda08d0c507c99f557c7a611fed
000eaaea8fb32eb25fae7cfd8920a383
cf377b7dce4c0b03c90dac80f6288ba5
-----END OpenVPN Static key V1-----
</secret>
key-direction 0

Этот ключ нужно скопировать на компьютер VPN-клиента в домашней сети и на два VPN-сервера по пути /etc/openvpn/keys/static.key.

Сервер за рубежом

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_psk_udp_1194.conf
dev tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# на каком сетевом интерфейсе принимать соединение от клиента
local 222.222.222.222
# номер порта, на котором нужно принимать соединение от клиента
lport 1194

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 0
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.201.201.1 10.201.201.2

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/server-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами tun0 и eth0 в двух направлениях
iptables -A FORWARD -i tun0 -o eth0 -s 10.201.201.2 -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -d 10.201.201.2 -j ACCEPT
# SNAT, чтобы клиент использовал ip-адрес сервера для выхода в интернет
iptables -t nat -A POSTROUTING -o eth0 -s 10.201.201.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-up.sh
# nano /etc/openvpn/server-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i tun0 -o eth0 -s 10.201.201.2 -j ACCEPT
iptables -D FORWARD -i eth0 -o tun0 -d 10.201.201.2 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -s 10.201.201.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-dn.sh

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_psk_udp_1194.service
# systemctl enable openvpn-server@p2p_psk_udp_1194.service

Тут меня поджидала неприятность — скрипт server-dn.sh почему-то не выполнялся. Оказалось, что проблема — в понижении прав с использованием директив user и group. По этой причине команды sysctl и iptables не могут быть выполнены. Так что нужно внести изменения в файл конфигурации, чтобы использовать плагин для запуска скрипта server-dn.sh с правами root.

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

Сервер в России

1. VPN-сервер (служба)

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_psk_udp_1194.conf
dev ovpn-server
dev-type tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# на каком сетевом интерфейсе принимать соединение от клиента
local 111.111.111.111
# номер порта, на котором нужно принимать соединение от клиента
lport 1194

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 0
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.101.101.1 10.101.101.2

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/server.log
verb 3

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_psk_udp_1194.service
# systemctl enable openvpn-server@p2p_psk_udp_1194.service

2. VPN-клиент (служба)

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_psk_udp_1194.conf
dev ovpn-client
dev-type tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 1194 udp4
# использовать динамический порт для возвращающихся пакетов
nobind

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 1
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.201.201.2 10.201.201.1

script-security 2
# выполнить эту команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/client-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/client-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/client.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/client-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами ovpn-client и ovpn-server туда-обратно
iptables -A FORWARD -i ovpn-server -o ovpn-client -s 10.101.101.2 -j ACCEPT
iptables -A FORWARD -i ovpn-client -o ovpn-server -d 10.101.101.2 -j ACCEPT

# SNAT, чтобы все пакеты, которые уходят с интерфейса ovpn-client в туннель в
# направлении сервера за рубежом, имели ip-адрес источника, как у ovpn-client
iptables -t nat -A POSTROUTING -s 10.101.101.2 -o ovpn-client -j MASQUERADE

# Для пакетов с адреса 10.101.101.2 — создаем отдельную таблицу маршрутизации
ip rule add from 10.101.101.2 table 151
# Чтобы работал ping от клиента в домашней сети, нужно чтобы ответы уходили
# через сетевой интерфейс ovpn-server, иначе они будут уходить по дефолтному
# маршруту, то есть через интерфейс ovpn-client (см.ниже)
ip route add 10.101.101.2 dev ovpn-server table 151
# Пакеты с адреса 10.101.101.2 — будут уходить через интерфейс ovpn-client
ip route add default dev ovpn-client table 151
# chmod +x /etc/openvpn/client-up.sh
Тут допущена некоторая вольность — если политика для цепочки FORWARD была ACCEPT, то она изменяется на DROP. Но в общем случае, политику ACCEPT использовать нежелательно, более правильно использовать политику DROP. Проходят только те пакеты, для которых нашлось правило -j ACCEPT, остальные пакеты отбрасываются. Политика по умолчанию ACCEPT подразумевает, что лишние пакеты нужно отбрасывать с помощью правил -j DROP — а это значительно труднее.
# nano /etc/openvpn/client-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i ovpn-server -o ovpn-client -s 10.101.101.2 -j ACCEPT
iptables -D FORWARD -i ovpn-client -o ovpn-server -d 10.101.101.2 -j ACCEPT
iptables -t nat -D POSTROUTING -s 10.101.101.2 -o ovpn-client -j MASQUERADE
ip rule del from 10.101.101.2 table 151
ip route del 10.101.101.2 dev ovpn-server table 151
ip route del default dev ovpn-client table 151
# chmod +x /etc/openvpn/client-dn.sh

Служба VPN-клиента зависит от службы VPN-сервера — скрипт client-up.sh ожидает, что сетевой интерфейс ovpn-server будет существовать и может быть использован в команде iptables. Это значит, что мы должны обеспечить правильный порядок запуска двух служб — сначала VPN-сервер, потом VPN-клиент.

# cp /usr/lib/systemd/system/openvpn-client@.service /etc/systemd/system
# nano /etc/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=network-online.target
Wants=network-online.target
# служба VPN-клиента будет запущена после службы VPN-сервера
Requires=openvpn-server@p2p_psk_udp_1194.service
After=openvpn-server@p2p_psk_udp_1194.service
# systemctl daemon-reload

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_psk_udp_1194.service
# systemctl enable openvpn-client@p2p_psk_udp_1194.service

Смотрим сетевые интерфейсы и ip-адреса

# ip addr
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
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 9a:90:05:dd:ca:f0 brd ff:ff:ff:ff:ff:ff
    inet 111.111.111.111/24 metric 100 brd 111.111.111.255 scope global dynamic eth0
       valid_lft 85840sec preferred_lft 85840sec
    ..........
3: ovpn-server: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.101.101.1 peer 10.101.101.2/32 scope global ovpn-server
       valid_lft forever preferred_lft forever
    ..........
4: ovpn-client: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.201.201.2 peer 10.201.201.1/32 scope global ovpn-client
       valid_lft forever preferred_lft forever
    ..........

Клиент в домашней сети

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_psk_udp_1194.conf
dev tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 1194 udp4
# использовать динамический порт для возвращающихся пакетов
nobind

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 1
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.101.101.2 10.101.101.1

# использовать VPN-туннель для маршрутизации всего трафика
redirect-gateway def1 bypass-dhcp
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
dhcp-option DNS 208.67.220.220
dhcp-option DNS 208.67.222.222
# все DNS-запросы отправлять в туннель для избежания утечки
dhcp-option DOMAIN-ROUTE .

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановке службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_psk_udp_1194.service
# systemctl enable openvpn-client@p2p_psk_udp_1194.service

2. OpenVPN, точка-точка, PSK (static key), протокол TCP, порт 1234

Здесь есть только два отличия от первого варианта настройки двойного VPN — протокол TCP вместо UDP + порт 1234 вместо 1194. Трафик между клиентом и первым VPN-сервером и трафик между первым VPN-сервером и вторым VPN-сервером будут шифроваться с использованием одного файла static.key.

Сервер за рубежом

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_psk_tcp_1234.conf
dev tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 0
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# на каком сетевом интерфейсе принимать соединение от клиента
local 222.222.222.222
# номер порта, на котором нужно принимать соединение от клиента
lport 1234

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.202.202.1 10.202.202.2

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/server-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами tun0 и eth0 в двух направлениях
iptables -A FORWARD -i tun0 -o eth0 -s 10.202.202.2 -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -d 10.202.202.2 -j ACCEPT
# SNAT, чтобы клиент использовал ip-адрес сервера для выхода в интернет
iptables -t nat -A POSTROUTING -o eth0 -s 10.202.202.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-up.sh
# nano /etc/openvpn/server-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i tun0 -o eth0 -s 10.202.202.2 -j ACCEPT
iptables -D FORWARD -i eth0 -o tun0 -d 10.202.202.2 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -s 10.202.202.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-dn.sh

Запускаем две службы и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_psk_tcp_1234.service
# systemctl enable openvpn-server@p2p_psk_tcp_1234.service

Сервер в России

На сервере будут работать две службы — VPN-сервера и VPN-клиента.

1. VPN-сервер (служба)

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_psk_tcp_1234.conf
dev ovpn-server
dev-type tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# на каком сетевом интерфейсе принимать соединение от клиента
local 111.111.111.111
# номер порта, на котором нужно принимать соединение от клиента
lport 1234

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 0
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.102.102.1 10.102.102.2

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/server.log
verb 3

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_psk_tcp_1234.service
# systemctl enable openvpn-server@p2p_psk_tcp_1234.service

2. VPN-клиент (служба)

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_psk_tcp_1234.conf
dev ovpn-client
dev-type tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 1234 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 1
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.202.202.2 10.202.202.1

script-security 2
# выполнить эту команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/client-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/client-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/client.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/client-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами ovpn-client и ovpn-server туда-обратно
iptables -A FORWARD -i ovpn-server -o ovpn-client -s 10.102.102.2 -j ACCEPT
iptables -A FORWARD -i ovpn-client -o ovpn-server -d 10.102.102.2 -j ACCEPT

# SNAT, чтобы все пакеты, которые уходят с интерфейса ovpn-client в туннель в
# направлении сервера за рубежом, имели ip-адрес источника, как у ovpn-client
iptables -t nat -A POSTROUTING -s 10.102.102.2 -o ovpn-client -j MASQUERADE

# Для пакетов с адреса 10.102.102.2 — создаем отдельную таблицу маршрутизации
ip rule add from 10.102.102.2 table 152
# Чтобы работал ping от клиента в домашней сети, нужно чтобы ответы уходили
# через сетевой интерфейс ovpn-server, иначе они будут уходить по дефолтному
# маршруту, то есть через интерфейс ovpn-client (см.ниже)
ip route add 10.102.102.2 dev ovpn-server table 152
# Пакеты с адреса 10.102.102.2 — будут уходить через интерфейс ovpn-client
ip route add default dev ovpn-client table 152
# chmod +x /etc/openvpn/client-up.sh
# nano /etc/openvpn/client-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i ovpn-server -o ovpn-client -s 10.102.102.2 -j ACCEPT
iptables -D FORWARD -i ovpn-client -o ovpn-server -d 10.102.102.2 -j ACCEPT
iptables -t nat -D POSTROUTING -s 10.102.102.2 -o ovpn-client -j MASQUERADE
ip rule del from 10.102.102.2 table 152
ip route del 10.102.102.2 dev ovpn-server table 152
ip route del default dev ovpn-client table 152
# chmod +x /etc/openvpn/client-dn.sh

Служба VPN-клиента зависит от службы VPN-сервера — скрипт client-up.sh ожидает, что сетевой интерфейс ovpn-server будет существовать и может быть использован в команде iptables. Это значит, что мы должны обеспечить правильный порядок запуска двух служб — сначала VPN-сервер, потом VPN-клиент.

# cp /usr/lib/systemd/system/openvpn-client@.service /etc/systemd/system
# nano /etc/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=network-online.target
Wants=network-online.target
# служба VPN-клиента будет запущена после службы VPN-сервера
Requires=openvpn-server@p2p_psk_tcp_1234.service
After=openvpn-server@p2p_psk_tcp_1234.service
# systemctl daemon-reload

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_psk_tcp_1234.service
# systemctl enable openvpn-client@p2p_psk_tcp_1234.service

Клиент в домашней сети

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_psk_tcp_1234.conf
dev tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 1234 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# секретный ключ и направление (0 — для сервера, 1 — для клиента)
secret /etc/openvpn/keys/static.key 1
# включить поддержку устаревших алгоритмов шифрования данных
providers legacy default

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.102.102.2 10.102.102.1

# использовать VPN-туннель для маршрутизации всего трафика
redirect-gateway def1 bypass-dhcp
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
dhcp-option DNS 208.67.220.220
dhcp-option DNS 208.67.222.222
# все DNS-запросы отправлять в туннель для избежания утечки
dhcp-option DOMAIN-ROUTE .

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_psk_tcp_1234.service
# systemctl enable openvpn-client@p2p_psk_tcp_1234.service

3. OpenVPN, точка-точка, TLS (finger print), протокол UDP, порт 1194

Традиционная настройка OpenVPN с использованием TLS (Transport Layer Security) подразумевает использование Центра Сертификации (CA). Вначале устанавливается TLS соединение с аутентификацией обеих сторон по сертификатам, через которое производится обмен открытыми ключами. Каждая сторона генерирует общие симметричные ключи и трафик внутри VPN шифруется уже этими ключами так же, как в режиме PSK. Сертификат сервера и сертификат клиента подписаны Центром Сертификации, которому доверяют обе стороны.

TLS также допускают более простой режим, в котором вместо проверки сертификатов с использованием Центра сертификации (CA), сам сертификат хэшируется и сравнивается с заранее известным набором приемлемых хэшей. Это обычно называется проверкой отпечатков пальцев (finger print). В этом случае не требуется подписывать сертификаты сервера и клиента в Центре Сертификации. Потому как в файле конфигурации сервера и клиентов есть отпечатки сертфикатов, которым можно доверять.

Директива secret была объявлена deprecated в OpenVPN 2.6 и будет удалена в OpenVPN 2.7. Использование static key больше не является достаточно безопасным для современных условий. Вместо static key рекомендуется использовать режим TLS. Директива peer-fingerprint делает настройку режима TLS такой же простой, как и при использовании директивы secret.

У нас два VPN-туннеля — между сервером за рубежом и сервером в России + между сервером в России и клиентом в домашней сети. Другими словами — два VPN-сервера и два VPN-клиента. Соответственно, нам нужны — ключ и сертификат сервера для 222.222.222.222, ключ и сертификат клиента для 111.111.111.111, ключ и сертификат сервера для 111.111.111.111, ключ и сертификат клиента в домашней сети.

Но мы можем немного облегчить себе жизнь, если будем использовать одну пару ключ-сертификат сервера + одну пару ключ-сертификат клиента — как уже использовали один файл static.key.

Создаем ключ и сертификат для сервера — файлы server.key и server.crt. Эти ключ и сертификат копируем на сервер 222.222.222.222 и на сервер 111.111.111.111 — в директорию /etc/openvpn/keys.

# openssl req -x509 \
>    -newkey ec:<(openssl ecparam -name secp384r1) \
>    -keyout server.key \
>    -out server.crt \
>    -nodes \
>    -sha256 \
>    -days 3650 \
>    -subj '/CN=server'

Создаем SHA256 отпечаток файла сертификата сервера

# openssl x509 -fingerprint -sha256 -in server.crt -noout
sha256 Fingerprint=D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

Создаем ключ и сертификат для клиента — файлы client.key и client.crt. Эти ключ и сертификат копируем на сервер 111.111.111.111 и на машину клиента в домашней сети — в директорию /etc/openvpn/keys.

# openssl req -x509 \
>    -newkey ec:<(openssl ecparam -name secp384r1) \
>    -keyout client.key \
>    -out client.crt \
>    -nodes \
>    -sha256 \
>    -days 3650 \
>    -subj '/CN=client'

Создаем SHA256 отпечаток файла сертификата клиента

# openssl x509 -fingerprint -sha256 -in client.crt -noout
sha256 Fingerprint=68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61

Сервер за рубежом

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_tls_udp_1194.conf
dev tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# на каком сетевом интерфейсе принимать соединение от клиента
local 222.222.222.222
# номер порта, на котором нужно принимать соединение от клиента
lport 1194

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, у нас сейчас только один клиент
<peer-fingerprint>
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим point-to-point (p2p), этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.203.203.1 10.203.203.2

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/server-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами tun0 и eth0 в двух направлениях
iptables -A FORWARD -i tun0 -o eth0 -s 10.203.203.2 -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -d 10.203.203.2 -j ACCEPT
# SNAT, чтобы клиент использовал ip-адрес сервера для выхода в интернет
iptables -t nat -A POSTROUTING -o eth0 -s 10.203.203.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-up.sh
# nano /etc/openvpn/server-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i tun0 -o eth0 -s 10.203.203.2 -j ACCEPT
iptables -D FORWARD -i eth0 -o tun0 -d 10.203.203.2 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -s 10.203.203.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-dn.sh

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_tls_udp_1194.service
# systemctl enable openvpn-server@p2p_tls_udp_1194.service

Сервер в России

На сервере будут работать две службы — VPN-сервера и VPN-клиента.

1. VPN-сервер (служба)

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_tls_udp_1194.conf
dev ovpn-server
dev-type tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# на каком сетевом интерфейсе принимать соединение от клиента
local 111.111.111.111
# номер порта, на котором нужно принимать соединение от клиента
lport 1194

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, у нас сейчас только один клиент
<peer-fingerprint>
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим point-to-point (p2p), этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.103.103.1 10.103.103.2

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/server.log
verb 3

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_tls_udp_1194.service
# systemctl enable openvpn-server@p2p_tls_udp_1194.service

2. VPN-клиент (служба)

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_tls_udp_1194.conf
dev ovpn-client
dev-type tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 1194 udp4
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера за рубежом 222.222.222.222
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.203.203.2 10.203.203.1

script-security 2
# выполнить эту команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/client-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/client-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/client.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/client-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами ovpn-client и ovpn-server туда-обратно
iptables -A FORWARD -i ovpn-server -o ovpn-client -s 10.103.103.2 -j ACCEPT
iptables -A FORWARD -i ovpn-client -o ovpn-server -d 10.103.103.2 -j ACCEPT

# SNAT, чтобы все пакеты, которые уходят с интерфейса ovpn-client в туннель в
# направлении сервера за рубежом, имели ip-адрес источника, как у ovpn-client
iptables -t nat -A POSTROUTING -s 10.103.103.2 -o ovpn-client -j MASQUERADE

# Для пакетов с адреса 10.103.103.2 — создаем отдельную таблицу маршрутизации
ip rule add from 10.103.103.2 table 153
# Чтобы работал ping от клиента в домашней сети, нужно чтобы ответы уходили
# через сетевой интерфейс ovpn-server, иначе они будут уходить по дефолтному
# маршруту, то есть через интерфейс ovpn-client (см.ниже)
ip route add 10.103.103.2 dev ovpn-server table 153
# Пакеты с адреса 10.103.103.2 — будут уходить через интерфейс ovpn-client
ip route add default dev ovpn-client table 153
# chmod +x /etc/openvpn/client-up.sh
# nano /etc/openvpn/client-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i ovpn-server -o ovpn-client -s 10.103.103.2 -j ACCEPT
iptables -D FORWARD -i ovpn-client -o ovpn-server -d 10.103.103.2 -j ACCEPT
iptables -t nat -D POSTROUTING -s 10.103.103.2 -o ovpn-client -j MASQUERADE
ip rule del from 10.103.103.2 table 153
ip route del 10.103.103.2 dev ovpn-server table 153
ip route del default dev ovpn-client table 153
# chmod +x /etc/openvpn/client-dn.sh

Служба VPN-клиента зависит от службы VPN-сервера — скрипт client-up.sh ожидает, что сетевой интерфейс ovpn-server будет существовать и может быть использован в команде iptables. Это значит, что мы должны обеспечить правильный порядок запуска двух служб — сначала VPN-сервер, потом VPN-клиент.

# cp /usr/lib/systemd/system/openvpn-client@.service /etc/systemd/system
# nano /etc/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=network-online.target
Wants=network-online.target
# служба VPN-клиента будет запущена после службы VPN-сервера
Requires=openvpn-server@p2p_tls_udp_1194.service
After=openvpn-server@p2p_tls_udp_1194.service
# systemctl daemon-reload

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_tls_udp_1194.service
# systemctl enable openvpn-client@p2p_tls_udp_1194.service

Клиент в домашней сети

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_tls_udp_1194.conf
dev tun
# для протокола UDP опция должна быть на клиенте и на сервере
proto udp4

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 1194 udp4
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера в России 111.111.111.111
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.103.103.2 10.103.103.1

# использовать VPN-туннель для маршрутизации всего трафика
redirect-gateway def1 bypass-dhcp
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
dhcp-option DNS 208.67.220.220
dhcp-option DNS 208.67.222.222
# все DNS-запросы отправлять в туннель для избежания утечки
dhcp-option DOMAIN-ROUTE .

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_tls_udp_1194.service
# systemctl enable openvpn-client@p2p_tls_udp_1194.service

4. OpenVPN, точка-точка, TLS (finger print), протокол TCP, порт 1234

Здесь есть только два отличия от предыдущего варианта настройки двойного VPN — использование протокола TCP вместо UDP + порт 1234 вместо 1194.

Сервер за рубежом

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_tls_tcp_1234.conf
dev tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# на каком сетевом интерфейсе принимать соединение от клиента
local 222.222.222.222
# номер порта, на котором нужно принимать соединение от клиента
lport 1234

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, у нас сейчас только один клиент
<peer-fingerprint>
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим point-to-point (p2p), этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.204.204.1 10.204.204.2

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/server-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами tun0 и eth0 в двух направлениях
iptables -A FORWARD -i tun0 -o eth0 -s 10.204.204.2 -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -d 10.204.204.2 -j ACCEPT

# SNAT, чтобы клиент использовал ip-адрес сервера для выхода в интернет
iptables -t nat -A POSTROUTING -o eth0 -s 10.204.204.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-up.sh
# nano /etc/openvpn/server-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i tun0 -o eth0 -s 10.204.204.2 -j ACCEPT
iptables -D FORWARD -i eth0 -o tun0 -d 10.204.204.2 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -s 10.204.204.2 -j MASQUERADE
# chmod +x /etc/openvpn/server-dn.sh

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_tls_tcp_1234.service
# systemctl enable openvpn-server@p2p_tls_tcp_1234.service

Сервер в России

На сервере будут работать две службы — VPN-сервера и VPN-клиента.

1. VPN-сервер (служба)

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/p2p_tls_tcp_1234.conf
dev ovpn-server
dev-type tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# на каком сетевом интерфейсе принимать соединение от клиента
local 111.111.111.111
# номер порта, на котором нужно принимать соединение от клиента
lport 1234

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, у нас сейчас только один клиент
<peer-fingerprint>
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим point-to-point (p2p), этот режим используется по умолчанию
mode p2p
# ip-адрес сервера и клиента в виртуальной приватной сети (VPN)
ifconfig 10.104.104.1 10.104.104.2

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/server.log
verb 3

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@p2p_tls_tcp_1234.service
# systemctl enable openvpn-server@p2p_tls_tcp_1234.service

2. VPN-клиент (служба)

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_tls_tcp_1234.conf
dev ovpn-client
dev-type tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 1234 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера за рубежом 222.222.222.222
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.204.204.2 10.204.204.1

script-security 2
# выполнить эту команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/client-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/client-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/client.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/client-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами ovpn-client и ovpn-server туда-обратно
iptables -A FORWARD -i ovpn-server -o ovpn-client -s 10.104.104.2 -j ACCEPT
iptables -A FORWARD -i ovpn-client -o ovpn-server -d 10.104.104.2 -j ACCEPT

# SNAT, чтобы все пакеты, которые уходят с интерфейса ovpn-client в туннель в
# направлении сервера за рубежом, имели ip-адрес источника, как у ovpn-client
iptables -t nat -A POSTROUTING -s 10.104.104.2 -o ovpn-client -j MASQUERADE

# Для пакетов с адреса 10.104.104.2 — создаем отдельную таблицу маршрутизации
ip rule add from 10.104.104.2 table 154
# Чтобы работал ping от клиента в домашней сети, нужно чтобы ответы уходили
# через сетевой интерфейс ovpn-server, иначе они будут уходить по дефолтному
# маршруту, то есть через интерфейс ovpn-client (см.ниже)
ip route add 10.104.104.2 dev ovpn-server table 154
# Пакеты с адреса 10.104.104.2 — будут уходить через интерфейс ovpn-client
ip route add default dev ovpn-client table 154
# chmod +x /etc/openvpn/client-up.sh
# nano /etc/openvpn/client-dn.sh
#!/bin/bash

# Восстанавливаем значение, которое было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i ovpn-server -o ovpn-client -s 10.104.104.2 -j ACCEPT
iptables -D FORWARD -i ovpn-client -o ovpn-server -d 10.104.104.2 -j ACCEPT
iptables -t nat -D POSTROUTING -s 10.104.104.2 -o ovpn-client -j MASQUERADE
ip rule del from 10.104.104.2 table 154
ip route del 10.104.104.2 dev ovpn-server table 154
ip route del default dev ovpn-client table 154
# chmod +x /etc/openvpn/client-dn.sh

Служба VPN-клиента зависит от службы VPN-сервера — скрипт client-up.sh ожидает, что сетевой интерфейс ovpn-server будет существовать и может быть использован в команде iptables. Это значит, что мы должны обеспечить правильный порядок запуска двух служб — сначала VPN-сервер, потом VPN-клиент.

# cp /usr/lib/systemd/system/openvpn-client@.service /etc/systemd/system
# nano /etc/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=network-online.target
Wants=network-online.target
# служба VPN-клиента будет запущена после службы VPN-сервера
Requires=openvpn-server@p2p_psk_tcp_1234.service
After=openvpn-server@p2p_psk_tcp_1234.service
# systemctl daemon-reload

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_psk_tcp_1234.service
# systemctl enable openvpn-client@p2p_psk_tcp_1234.service

Клиент в домашней сети

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/p2p_tls_tcp_1234.conf
dev tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 1234 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера в России 111.111.111.111
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# режим point-to-point, этот режим используется по умолчанию
mode p2p
# ip-адрес клиента и сервера в виртуальной приватной сети (VPN)
ifconfig 10.104.104.2 10.104.104.1

# использовать VPN-туннель для маршрутизации всего трафика
redirect-gateway def1 bypass-dhcp
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
dhcp-option DNS 208.67.220.220
dhcp-option DNS 208.67.222.222
# все DNS-запросы отправлять в туннель для избежания утечки
dhcp-option DOMAIN-ROUTE .

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@p2p_tls_tcp_1234.service
# systemctl enable openvpn-client@p2p_tls_tcp_1234.service

5. OpenVPN, сервер-клиенты, TLS (finger print), протокол TCP, порт 443

Вместо режима «точка-точка» (mode p2p) будем использовать режим «сервер-клиенты» (mode server) — потому что у сервера за рубежом и у сервера в России — теперь по два клиента. Эти два новых клиента будут отправлять весь трафик в VPN-туннель — то есть, выходить в интернет через VPN-сервер за рубежом.

Компьютер ivanov

Создаем ключ и сертификат для клиента — файлы ivanov.key и ivanov.crt. Эти ключ и сертификат копируем на компьютер ivanov — в директорию /etc/openvpn/keys.

# openssl req -x509 \
>    -newkey ec:<(openssl ecparam -name secp384r1) \
>    -keyout ivanov.key \
>    -out ivanov.crt \
>    -nodes \
>    -sha256 \
>    -days 3650 \
>    -subj '/CN=ivanov'

Создаем SHA256 отпечаток файла сертификата клиента ivanov

# openssl x509 -fingerprint -sha256 -in ivanov.crt -noout
sha256 Fingerprint=82:68:0F:99:F6:DD:E3:C0:42:60:D1:2C:B9:3B:73:6E:27:B4:D0:3C:B0:D7:F5:34:B2:AB:16:C2:28:59:79:25

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/srv_tls_tcp_443.conf
dev tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 443 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента ivanov.key и ivanov.crt
key /etc/openvpn/keys/ivanov.key
cert /etc/openvpn/keys/ivanov.crt
# здесь отпечаток сертификата сервера за рубежом 222.222.222.222
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# директиву можно использовать только в режиме «сервер-клиенты» в
# файле конфигурации клиента; она разрешает принимать от сервера
# директивы конфигурации, которые тот отправляет с помощью push
pull

# этот маршрут нужен, чтобы иметь доступ к этому серверу по ssh
route 123.123.123.123 255.255.255.255 net_gateway

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

В файле конфигурации есть директива route, которая добавляет маршрут до 123.123.123.123 через физический сетевой интерфейс. У меня роль компьютера ivanov играет облачный сервер, к которому есть доступ по ssh с ip-адреса 123.123.123.123. Эта директива нужна, чтобы не потерять ssh-доступ к серверу — ответы должны уходить через физический сетевой интерфейс. Для обычного VPN-клиента ivanov, который просто выходит в интернет через сервер за рубежом — эта директива не нужна.

Было бы правильно настроить Policy-based Routing (PBR) — чтобы на входящее ssh-соединение, которое пришло на физический сетевой интерфейс, ответ уходил через тот же физический интерефейс, вместо маршрута по умолчанию. Но в данном случае подразумевается, что ivanov — обычный пользователь, компьютер которого не имеет белого ip-адреса, так что и подключиться к его компу невозможно. И лучше для такого пользователя создать ovpn файл конфигурации, в который включить содержимое ivanov.key и ivanov.crt.

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@srv_tls_tcp_443.service
# systemctl enable openvpn-client@srv_tls_tcp_443.service

Компьютер petrov

Создаем ключ и сертификат для клиента — файлы petrov.key и petrov.crt. Эти ключ и сертификат копируем на компьютер petrov — в директорию /etc/openvpn/keys.

# openssl req -x509 \
>    -newkey ec:<(openssl ecparam -name secp384r1) \
>    -keyout petrov.key \
>    -out petrov.crt \
>    -nodes \
>    -sha256 \
>    -days 3650 \
>    -subj '/CN=petrov'

Создаем SHA256 отпечаток файла сертификата клиента petrov

# openssl x509 -fingerprint -sha256 -in petrov.crt -noout

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/srv_tls_tcp_443.conf
dev tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 443 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента petrov.key и petrov.crt
key /etc/openvpn/keys/petrov.key
cert /etc/openvpn/keys/petrov.crt
# здесь отпечаток сертификата сервера в России 111.111.111.111
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# директиву можно использовать только в режиме «сервер-клиенты» в
# файле конфигурации клиента; она разрешает принимать от сервера
# директивы конфигурации, которые тот отправляет с помощью push
pull

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@srv_tls_tcp_443.service
# systemctl enable openvpn-client@srv_tls_tcp_443.service

Сервер за рубежом

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/srv_tls_tcp_443.conf
dev tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# на каком сетевом интерфейсе принимать соединения от клиентов
local 222.222.222.222
# номер порта, на котором нужно принимать соединения от клиентов
lport 443

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, теперь два клиента вместо одного
<peer-fingerprint>
# первый клиент, сервер в России
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
# второй клиент, компьютер ivanov
82:68:0F:99:F6:DD:E3:C0:42:60:D1:2C:B9:3B:73:6E:27:B4:D0:3C:B0:D7:F5:34:B2:AB:16:C2:28:59:79:25
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим «сервер-клиенты» вместо режима по умолчанию «точка-точка»
mode server
# топология «subnet» для режима «сервер-клиенты» вместо топологии
# «p2p», которая используется в режиме по умолчанию «точка-точка»
topology subnet

# ip-адрес и маска сервера в виртуальной сети «сервер-клиенты»
ifconfig 10.205.205.1 255.255.255.0
# шлюз по умолчанию для этой виртуальной сети (это VPN-сервер)
route-gateway 10.205.205.1

# серверу в России назначим статический ip-адрес 10.205.205.2
client-config-dir /etc/openvpn/ccd

# остальным клиентам будем назначать адреса из этого диапазона
ifconfig-pool 10.205.205.3 10.205.205.254 255.255.255.0
# сохранять за клиентамм постоянные адреса, хранить их в файле
ifconfig-pool-persist /var/log/openvpn/ipp.txt

# При подключении клиентов — отправлять им директивы настройки:

# использовать топологию «subnet» для этой виртуальной сети
push "topology subnet"
# шлюз по умолчанию для этой виртуальной сети (это VPN-сервер)
push "route-gateway 10.205.205.1"
# использовать VPN-туннель для маршрутизации всего трафика
push "redirect-gateway def1 bypass-dhcp"
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
push "dhcp-option DNS 208.67.220.220"
push "dhcp-option DNS 208.67.222.222"
# все DNS-запросы отправлять в туннель для избежания утечки
push "dhcp-option DOMAIN-ROUTE ."

script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/server-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/server-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Файл конфигурации клиента в директории client-config-dir, который будет использован в момент подключения клиента client. Этот файл должен быть доступен для чтения службе OpenVPN-сервера, когда уже отброшены права root и служба работает от имени nobody и nogroup.

# mkdir /etc/openvpn/ccd
# nano /etc/openvpn/ccd/client
# серверу в России назначим статический ip-адрес
ifconfig-push 10.205.205.2 255.255.255.0

Скрипты при запуске/остановке службы

# nano /etc/openvpn/server-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами tun0 и eth0 в двух направлениях
iptables -A FORWARD -i tun0 -o eth0 -s 10.205.205.0/24 -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -d 10.205.205.0/24 -j ACCEPT

# SNAT, чтобы клиенты использовали адрес сервера для выхода в интернет
iptables -t nat -A POSTROUTING -o eth0 -s 10.205.205.0/24 -j MASQUERADE
# chmod +x /etc/openvpn/server-up.sh
# nano /etc/openvpn/server-dn.sh
#!/bin/bash

# Восстанавливаем значение, которые было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i tun0 -o eth0 -s 10.205.205.0/24 -j ACCEPT
iptables -D FORWARD -i eth0 -o tun0 -d 10.205.205.0/24 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -s 10.205.205.0/24 -j MASQUERADE
# chmod +x /etc/openvpn/server-dn.sh

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@srv_tls_tcp_443.service
# systemctl enable openvpn-client@srv_tls_tcp_443.service

Сервер в России

На сервере будут работать две службы — VPN-сервера и VPN-клиента.

1. VPN-сервер (служба)

Файл конфигурации службы VPN-сервера

# nano /etc/openvpn/server/srv_tls_tcp_443.conf
dev ovpn-server
dev-type tun
# для протокола TCP для сервера опция имеет значение tcp-server
proto tcp4-server

# на каком сетевом интерфейсе принимать соединения от клиентов
local 111.111.111.111
# номер порта, на котором нужно принимать соединения от клиентов
lport 443

# эта конечная точка будет представляться сервером при handshake
tls-server
# файлы ключа и сертификата сервера server.key и server.crt
key /etc/openvpn/keys/server.key
cert /etc/openvpn/keys/server.crt
# отпечатки пальцев клиентов, теперь два клиента вместо одного
<peer-fingerprint>
# первый клиент в домашней сети
68:AA:B5:98:F2:DB:5F:E7:48:07:DB:E7:EF:99:9A:F2:0D:D9:6B:B4:0D:39:36:C2:A2:3C:5D:DA:07:39:00:61
# второй клиент, компьютер petrov
72:12:3F:0F:24:4D:97:D6:4E:59:CB:61:65:81:CF:B6:0D:27:AC:7A:F1:47:E5:23:D8:62:B7:81:66:50:4C:BD
</peer-fingerprint>
# не использовать файл Diffie-Hellman, а использовать протокол
# на элиптических кривых ECDH (Elliptic curve Diffie-Hellman)
dh none

# режим «сервер-клиенты» вместо режима по умолчанию «точка-точка»
mode server
# топология «subnet» для режима «сервер-клиенты» вместо топологии
# «p2p», которая используется в режиме по умолчанию «точка-точка»
topology subnet

# ip-адрес и маска сервера в виртуальной сети «сервер-клиенты»
ifconfig 10.105.105.1 255.255.255.0
# шлюз по умолчанию для этой виртуальной сети (это VPN-сервер)
route-gateway 10.105.105.1

# VPN-клиенту в домашней сети назначим статический ip-адрес
client-config-dir /etc/openvpn/ccd

# остальным клиентам будем назначать адреса из этого диапазона
ifconfig-pool 10.105.105.3 10.105.105.254 255.255.255.0
# сохранять за клиентамм постоянные адреса, хранить их в файле
ifconfig-pool-persist /var/log/openvpn/ipp.txt

# При подключении клиентов — отправлять им директивы настройки:

# использовать топологию «subnet» для этой виртуальной сети
push "topology subnet"
# шлюз по умолчанию для этой виртуальной сети (это VPN-сервер)
push "route-gateway 10.105.105.1"
# использовать VPN-туннель для маршрутизации всего трафика
push "redirect-gateway def1 bypass-dhcp"
# использовать DNS-сервера 208.67.220.220 и 208.67.222.222
push "dhcp-option DNS 208.67.220.220"
push "dhcp-option DNS 208.67.222.222"
# все DNS-запросы отправлять в туннель для избежания утечки
push "dhcp-option DOMAIN-ROUTE ."

keepalive 10 60
user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/server.log
verb 3

Файл конфигурации клиента в директории client-config-dir, который будет использован в момент подключения клиента client. Этот файл должен быть доступен для чтения службе OpenVPN-сервера, когда уже отброшены права root и служба работает от имени nobody и nogroup.

# mkdir /etc/openvpn/ccd
# nano /etc/openvpn/ccd/client
# VPN-клиенту в домашней сети назначим статический ip-адрес
ifconfig-push 10.105.105.2 255.255.255.0

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-server@srv_tls_tcp_443.service
# systemctl enable openvpn-server@srv_tls_tcp_443.service

2. VPN-клиент (служба)

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/srv_tls_tcp_443.conf
dev ovpn-client
dev-type tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 222.222.222.222 443 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера за рубежом 222.222.222.222
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# директиву можно использовать только в режиме «сервер-клиенты» в
# файле конфигурации клиента; она разрешает принимать от сервера
# директивы конфигурации, которые тот отправляет с помощью push
pull

# этот клиент не должен отправлять весь свой трафик в VPN-туннель;
# отбрасываем все директивы от сервера, которые это предписывают
pull-filter ignore "redirect-gateway def1 bypass-dhcp"
pull-filter ignore "dhcp-option DNS 208.67.220.220"
pull-filter ignore "dhcp-option DNS 208.67.222.222"
pull-filter ignore "dhcp-option DOMAIN-ROUTE ."

script-security 2
# выполнить эту команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/client-up.sh
# выполнить команду или скрипт при остановке устройства tun/tap
plugin /usr/lib/openvpn/openvpn-plugin-down-root.so /etc/openvpn/client-dn.sh
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/client.log
verb 3

Скрипты при запуске/остановке службы

# nano /etc/openvpn/client-up.sh
#!/bin/bash

# Разрешаем пакеты между интерфейсами, если это запрещено. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
forward=$(cat /proc/sys/net/ipv4/ip_forward)
if [[ $forward == '0' ]]; then
    echo '0' > /etc/openvpn/forward.txt
    sysctl -w -q net.ipv4.ip_forward=1
else
    echo '1' > /etc/openvpn/forward.txt
fi

# Изменяем на DROP политику по умолчанию для цепочки FORWARD. При этом
# запоминаем значение, чтобы при остановке службы вернуть как было.
iptables -L | grep 'Chain FORWARD (policy ACCEPT)'
if [[ $? == 0 ]]; then
    echo 'ACCEPT' > /etc/openvpn/policy.txt
    iptables -P FORWARD DROP
else
    echo 'DROP' > /etc/openvpn/policy.txt
fi

# Разрешаем пакеты между интерфейсами ovpn-client и ovpn-server туда-обратно
iptables -A FORWARD -i ovpn-server -o ovpn-client -s 10.105.105.0/24 -j ACCEPT
iptables -A FORWARD -i ovpn-client -o ovpn-server -d 10.105.105.0/24 -j ACCEPT

# SNAT, чтобы все пакеты, которые уходят с интерфейса ovpn-client в туннель в
# направлении сервера за рубежом, имели ip-адрес источника, как у ovpn-client
iptables -t nat -A POSTROUTING -s 10.105.105.0/24 -o ovpn-client -j MASQUERADE

# Для пакетов из сети 10.105.105.0/24 — создаем отдельную таблицу маршрутизации
ip rule add from 10.105.105.0/24 table 155
# Чтобы работал ping от клиента в домашней сети, нужно чтобы ответы уходили
# через сетевой интерфейс ovpn-server, иначе они будут уходить по дефолтному
# маршруту, то есть через интерфейс ovpn-client (см.ниже)
ip route add 10.105.105.0/24 dev ovpn-server table 155
# Пакеты из сети 10.105.105.0/24 — будут уходить через интерфейс ovpn-client
ip route add default dev ovpn-client table 155
# chmod +x /etc/openvpn/client-up.sh
# nano /etc/openvpn/client-dn.sh
#!/bin/bash

# Восстанавливаем значение, которые было до момента запуска службы
if [[ -f /etc/openvpn/forward.txt ]]; then
    forward=$(cat /etc/openvpn/forward.txt)
    if [[ $forward == '0' ]]; then
        sysctl -w -q net.ipv4.ip_forward=0
    fi
    rm /etc/openvpn/forward.txt
else
    sysctl -w -q net.ipv4.ip_forward=0
fi

# Восстанавливаем политику, которая была до момента запуска службы
if [[ -f /etc/openvpn/policy.txt ]]; then
    policy=$(cat /etc/openvpn/policy.txt)
    if [[ $policy == 'ACCEPT' ]]; then
        iptables -P FORWARD ACCEPT
    fi
    rm /etc/openvpn/policy.txt
else
    iptables -P FORWARD ACCEPT
fi

# Удаляем правила маршрутизации пакетов, добавленные при запуске службы
iptables -D FORWARD -i ovpn-server -o ovpn-client -s 10.105.105.0/24 -j ACCEPT
iptables -D FORWARD -i ovpn-client -o ovpn-server -d 10.105.105.0/24 -j ACCEPT
iptables -t nat -D POSTROUTING -s 10.105.105.0/24 -o ovpn-client -j MASQUERADE
ip rule del from 10.105.105.0/24 table 155
ip route del 10.105.105.0/24 dev ovpn-server table 155
ip route del default dev ovpn-client table 155
# chmod +x /etc/openvpn/client-dn.sh

Служба VPN-клиента зависит от службы VPN-сервера — скрипт client-up.sh ожидает, что сетевой интерфейс ovpn-server будет существовать и может быть использован в команде iptables. Это значит, что мы должны обеспечить правильный порядок запуска двух служб — сначала VPN-сервер, потом VPN-клиент.

# cp /usr/lib/systemd/system/openvpn-client@.service /etc/systemd/system
# nano /etc/systemd/system/openvpn-client@.service
[Unit]
Description=OpenVPN tunnel for %I
After=network-online.target
Wants=network-online.target
# служба VPN-клиента будет запущена после службы VPN-сервера
Requires=openvpn-server@srv_tls_tcp_443.service
After=openvpn-server@srv_tls_tcp_443.service
# systemctl daemon-reload

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@srv_tls_tcp_443.service
# systemctl enable openvpn-client@srv_tls_tcp_443.service

Клиент в домашней сети

Файл конфигурации службы VPN-клиента

# nano /etc/openvpn/client/srv_tls_tcp_443.conf
dev tun
# для протокола TCP для клиента опция имеет значение tcp-client
proto tcp4-client

# ip-адрес, порт и протокол сервера для установления соединения
remote 111.111.111.111 443 tcp4-client
# использовать динамический порт для возвращающихся пакетов
nobind

# эта конечная точка будет представляться клиентом при handshake
tls-client
# файлы ключа и сертификата клиента client.key и client.crt
key /etc/openvpn/keys/client.key
cert /etc/openvpn/keys/client.crt
# здесь отпечаток сертификата сервера в России 111.111.111.111
peer-fingerprint D4:0A:C6:1C:70:7C:83:71:59:48:C4:DC:AB:F3:CE:28:9F:36:56:99:01:94:AD:67:A3:2A:F9:E5:3A:1F:CB:6A

# директиву можно использовать только в режиме «сервер-клиенты» в
# файле конфигурации клиента; она разрешает принимать от сервера
# директивы конфигурации, которые тот отправляет с помощью push
pull

# следующие четыре директивы нужны для изменения используемых
# DNS-серверов на клиенте при запуске/остановки службы
script-security 2
# выполнить команду или скрипт при запуске устройства tun/tap
up /etc/openvpn/update-systemd-resolved
# выполнить команду или скрипт при остановке устройства tun/tap
down /etc/openvpn/update-systemd-resolved
# выполнить команду из down перед, а не после остановки tun/tap
down-pre

user nobody
group nogroup
persist-tun
persist-key

# логирование нужно только на этапе отладки, потом можно отключить
log /var/log/openvpn/openvpn.log
verb 3

Чтобы получить скрипт /etc/openvpn/update-systemd-resolved — нужно установить пакет openvpn-systemd-resolved

# apt install openvpn-systemd-resolved

Запускаем службу и добавляем в автозагрузку

# systemctl start openvpn-client@srv_tls_tcp_443.service
# systemctl enable openvpn-client@srv_tls_tcp_443.service

Немного пояснений

Сервер в России весь трафик, который приходит на сетевой интерфейс ovpn-server, перебрасывает на сетевой интерфейс ovpn-client — откуда он уходит в направлении сервера за рубежом. При этом свой трафик сервер в России отправляет с физического интерфейса eth0 — то есть, выходит в интернет самостоятельно. Два клиента VPN-сервера в России имеют одинаковые настройки — оба отправляют весь свой трафик с сетевого интерфейса tun0, то есть в VPN-туннель.

Клиент ivanov весь свой трафик отправляет с интерфейса tun0, то есть выходит в интернет через сервер за рубежом. Подразумевается, что таких клиентов может быть много, поэтому в файл конфигурации VPN-сервера за рубежом мы добавляем директивы push, которые предписывают клиентам отправлять весь трафик в VPN-туннель. Но для VPN-клиента, который запущен на сервере в России — эти директивы не нужны. Поэтому в файле конфигурации службы этого VPN-клиента — используем директиву pull-filter.

Директива client-config-dir задает директорию для хранения файлов конфигурации клиентов, которые используются VPN-сервером только при подключении конкретного клиента. В этих файлах можно использовать директиву push — чтобы отправить клиенту индивидуальные настройки. С другой стороны, в файле конфигурации клиента можно использовать директиву pull-filter — чтобы принять или отбросить директивы, отправленные сервером с помощью push.

В файлах конфигурации клиентов мы не используем директиву keepalive, потому что в режиме «сервер-клиенты» — VPN-сервер сам отправит клиентам директивы ping и ping-restart с помощью push. Но в файлах конфигурации клиентов должна быть директива pull — которая разрешает принимать от сервера директивы конфигурации.

Поиск: Linux • Ubuntu • VPN • Клиент • Ключ • Настройка • Сервер • Установка • OpenVPN

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.