Нужно направить интернет-трафик ноутбука через собственный VPS. Для этого недостаточно запустить OpenVPN: сервер должен выдавать клиенту адрес, принимать его пакеты, пересылать их в интернет и подменять исходный адрес с помощью NAT.

В результате мы получим один файл macbook-internet.ovpn. Его можно импортировать в Tunnelblick или OpenVPN Connect на macOS.

Гайд рассчитан на Ubuntu 22.04 или 24.04 и OpenVPN Community Edition. Основная конфигурация направляет через VPN весь IPv4-трафик. Настройка двух одновременных VPN вынесена в отдельный раздел в конце.

Что потребуется

  • VPS с Ubuntu и доступом по SSH;
  • публичный IPv4-адрес или проброс UDP-порта через NAT провайдера;
  • открытый входящий порт 1194/UDP;
  • клиент Tunnelblick или OpenVPN Connect.

В примерах используются:

Публичный адрес VPS: 203.0.113.10
VPN-подсеть:         10.90.0.0/24
VPN-сервер:          10.90.0.1
Первый клиент:       macbook

Адрес 203.0.113.10 зарезервирован для документации. Замените его на публичный адрес своего VPS.

VPN-подсеть не должна совпадать с сетью VPS, домашней сетью или другими VPN. Например, если интерфейс VPS находится в 192.168.0.0/24, оставьте для OpenVPN отдельную сеть 10.90.0.0/24.

Установка OpenVPN

Установим OpenVPN, Easy-RSA для выпуска сертификатов и UFW для настройки сетевого экрана:

sudo apt update
sudo apt install -y openvpn easy-rsa ufw

Ubuntu рекомендует пакеты openvpn и easy-rsa в официальной инструкции.

Создание сертификатов

Создадим каталог Easy-RSA и перейдём в root-сессию:

sudo make-cadir /etc/openvpn/easy-rsa
sudo -i
cd /etc/openvpn/easy-rsa

Создадим инфраструктуру открытых ключей (Public Key Infrastructure, PKI):

./easyrsa init-pki
./easyrsa build-ca

Команда build-ca попросит задать пароль центра сертификации и его имя. Пароль понадобится при выпуске и отзыве клиентских сертификатов.

Создадим ключ и сертификат сервера:

./easyrsa gen-req vpn-server nopass
./easyrsa sign-req server vpn-server

При подписании введите yes, затем пароль центра сертификации.

Создадим сертификат первого клиента:

./easyrsa gen-req macbook nopass
./easyrsa sign-req client macbook

Параметр nopass позволяет подключаться без ввода пароля от клиентского ключа. После этого файл .ovpn нужно хранить как секрет: любой, кто получит его копию, сможет подключиться к серверу.

Создадим список отозванных сертификатов:

./easyrsa gen-crl

Установка ключей сервера

Создадим каталог конфигурации и скопируем в него только серверные файлы:

install -d -m 700 /etc/openvpn/server

install -m 644 pki/ca.crt /etc/openvpn/server/ca.crt
install -m 644 pki/issued/vpn-server.crt /etc/openvpn/server/vpn-server.crt
install -m 600 pki/private/vpn-server.key /etc/openvpn/server/vpn-server.key
install -m 644 pki/crl.pem /etc/openvpn/server/crl.pem

Создадим ключ tls-crypt:

openvpn --genkey tls-crypt /etc/openvpn/server/tls-crypt.key
chmod 600 /etc/openvpn/server/tls-crypt.key

tls-crypt шифрует и проверяет управляющий канал OpenVPN. В отличие от tls-auth, он не требует параметра key-direction.

Конфигурация OpenVPN

Создайте файл /etc/openvpn/server/internet.conf:

nano /etc/openvpn/server/internet.conf

Добавьте конфигурацию:

port 1194
proto udp4
dev tun-inet

topology subnet
server 10.90.0.0 255.255.255.0

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/vpn-server.crt
key /etc/openvpn/server/vpn-server.key
crl-verify /etc/openvpn/server/crl.pem

dh none
tls-crypt /etc/openvpn/server/tls-crypt.key
tls-version-min 1.2
remote-cert-tls client

data-ciphers AES-256-GCM:AES-128-GCM

push "redirect-gateway def1"
push "dhcp-option DNS 213.148.0.221"
push "dhcp-option DNS 213.148.0.222"

keepalive 10 120
persist-key
persist-tun

user nobody
group nogroup

explicit-exit-notify 1
verb 3

В примере используются DNS-серверы 213.148.0.221 и 213.148.0.222. Если провайдер выдал другие адреса, замените обе строки dhcp-option DNS.

redirect-gateway def1 создаёт на клиенте маршруты 0.0.0.0/1 и 128.0.0.0/1. Вместе они направляют весь IPv4-трафик через VPN, но сохраняют исходный маршрут по умолчанию. data-ciphers включает современные шифры AES-GCM вместо устаревшей директивы cipher. Эти параметры описаны в руководстве OpenVPN 2.6.

Включение маршрутизации

Linux по умолчанию не пересылает IPv4-пакеты между интерфейсами. Включим пересылку пакетов, или IP forwarding:

echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/70-openvpn-routing.conf
sysctl -p /etc/sysctl.d/70-openvpn-routing.conf

Проверим значение:

sysctl net.ipv4.ip_forward

Ожидаемый результат:

net.ipv4.ip_forward = 1

Настройка NAT и UFW

Сначала определим внешний интерфейс VPS:

ip -4 route show default

Пример результата:

default via 192.168.0.1 dev eth0

В этом случае внешний интерфейс называется eth0. На другом VPS он может называться ens3, ens5 или иначе.

До включения UFW разрешите SSH и OpenVPN:

ufw allow OpenSSH
ufw allow 1194/udp

Если SSH использует нестандартный порт, разрешите его вместо профиля OpenSSH.

Добавьте правило пересылки пакетов из VPN во внешний интерфейс. Замените eth0 на имя своего интерфейса:

ufw route allow in on tun-inet out on eth0 from 10.90.0.0/24

Теперь откройте /etc/ufw/before.rules:

nano /etc/ufw/before.rules

В начало файла, перед существующей секцией *filter, добавьте:

*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.90.0.0/24 -o eth0 -j MASQUERADE
COMMIT

Здесь также замените eth0 на внешний интерфейс VPS.

Правило MASQUERADE меняет адрес клиента 10.90.0.x на адрес сервера. Благодаря этому ответы из интернета возвращаются на VPS, а затем попадают в VPN-туннель. Подробно эта схема разобрана в документации Ubuntu по IP masquerading.

Включите firewall:

ufw enable
ufw reload
ufw status verbose

Не закрывайте текущую SSH-сессию, пока не убедитесь, что правило SSH присутствует в выводе ufw status.

Запуск сервера

Запустим OpenVPN и добавим его в автозагрузку:

systemctl enable --now openvpn-server@internet

Проверим службу, порт и туннельный интерфейс:

systemctl status openvpn-server@internet
ss -lunp | grep 1194
ip address show tun-inet

У интерфейса tun-inet должен быть адрес 10.90.0.1/24.

Если служба не запустилась, выведите журнал:

journalctl -u openvpn-server@internet -n 100 --no-pager

VPS за NAT провайдера

Иногда VPS получает частный адрес, а провайдер связывает его с публичным:

Интернет -> 203.0.113.10 -> 192.168.0.2 -> VPS

В такой схеме:

  • в клиентском профиле указывают публичный адрес 203.0.113.10;
  • NAT OpenVPN использует реальный интерфейс VPS с адресом 192.168.0.2;
  • в конфигурацию сервера не добавляют local 203.0.113.10;
  • провайдер должен направлять 1194/UDP с публичного адреса на VPS.

Если провайдер использует полный 1:1 NAT, проброс обычно работает автоматически. При наличии отдельного firewall или security group разрешите в нём 1194/UDP.

Создание клиентского профиля

Мы уже находимся в root-сессии. Зададим публичный адрес сервера и имя клиента:

PUBLIC_IP="203.0.113.10"
CLIENT="macbook"
OUT="/root/${CLIENT}-internet.ovpn"

Замените 203.0.113.10 на адрес своего VPS.

Создадим основную часть профиля:

cat > "$OUT" <<EOF
client
dev tun
proto udp4
remote ${PUBLIC_IP} 1194

resolv-retry infinite
nobind
persist-key
persist-tun

remote-cert-tls server
verify-x509-name vpn-server name
data-ciphers AES-256-GCM:AES-128-GCM

explicit-exit-notify 1
verb 3

<ca>
EOF

Добавим сертификаты и ключи:

sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' \
    /etc/openvpn/easy-rsa/pki/ca.crt >> "$OUT"
echo '</ca>' >> "$OUT"

echo '<cert>' >> "$OUT"
sed -ne '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' \
    "/etc/openvpn/easy-rsa/pki/issued/${CLIENT}.crt" >> "$OUT"
echo '</cert>' >> "$OUT"

echo '<key>' >> "$OUT"
cat "/etc/openvpn/easy-rsa/pki/private/${CLIENT}.key" >> "$OUT"
echo '</key>' >> "$OUT"

echo '<tls-crypt>' >> "$OUT"
cat /etc/openvpn/server/tls-crypt.key >> "$OUT"
echo '</tls-crypt>' >> "$OUT"

chmod 600 "$OUT"

Получился автономный профиль /root/macbook-internet.ovpn.

Если для SSH используется пользователь ubuntu, скопируйте профиль в его домашний каталог:

install -o ubuntu -g ubuntu -m 600 \
    /root/macbook-internet.ovpn \
    /home/ubuntu/macbook-internet.ovpn

exit

На Mac загрузите файл:

scp ubuntu@203.0.113.10:macbook-internet.ovpn ~/Downloads/

Замените имя пользователя и адрес VPS. После импорта удалите временную копию из домашнего каталога на сервере:

ssh ubuntu@203.0.113.10 'rm ~/macbook-internet.ovpn'

Профиль содержит незашифрованный клиентский ключ. После проверки удалите /root/macbook-internet.ovpn с VPS или перенесите его в зашифрованное резервное хранилище.

Настройка клиента на macOS

Импортируйте macbook-internet.ovpn в Tunnelblick или OpenVPN Connect.

Для Tunnelblick:

  1. Выберите профиль в VPN Details.
  2. Оставьте включённой настройку Set nameserver.
  3. Включите Disable IPv6, чтобы IPv6-трафик не обходил VPN.
  4. Подключите профиль.

Tunnelblick по умолчанию отключает IPv6 для TUN-подключений, но настройку стоит проверить. Это поведение описано в документации Tunnelblick.

Для OpenVPN Connect:

  1. Импортируйте профиль из файла.
  2. В настройках включите Block IPv6.
  3. Включите Seamless Tunnel, если нужно блокировать интернет во время переподключения VPN.
  4. Подключите профиль.

OpenVPN Connect описывает параметры Block IPv6 и Seamless Tunnel в настройках клиента для macOS.

Проверка

Сначала узнайте текущий публичный IPv4 без VPN:

curl -4 https://api.ipify.org
echo

Подключите VPN и повторите команду. Теперь она должна показать публичный адрес VPS.

Проверьте маршрут:

route -n get 1.1.1.1

В поле interface должен быть указан интерфейс utun.

Проверьте DNS:

scutil --dns

В списке должны появиться DNS-серверы, заданные в internet.conf.

Проверьте IPv6:

curl -6 --connect-timeout 5 https://api64.ipify.org

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

На сервере можно проверить передачу пакетов:

ip -s link show tun-inet

Счётчики RX и TX должны увеличиваться при работе клиента.

Если VPN подключился, но интернета нет

Проверьте четыре места:

sysctl net.ipv4.ip_forward
sudo ufw status verbose
sudo iptables -t nat -S POSTROUTING
sudo journalctl -u openvpn-server@internet -n 100 --no-pager

Типичные причины:

  • net.ipv4.ip_forward равен 0;
  • в правиле MASQUERADE указано неправильное имя интерфейса;
  • провайдер не пропускает 1194/UDP;
  • UFW разрешает подключение к OpenVPN, но запрещает forwarding;
  • VPN-подсеть пересекается с локальной сетью клиента.

Опция: два VPN одновременно

Допустим, первый VPN даёт доступ только к сети 10.128.66.0/24, а второй VPN из этого гайда должен обслуживать остальной интернет.

OpenVPN Connect на macOS не поддерживает два одновременных подключения. Для такой схемы используйте Tunnelblick: он умеет держать несколько туннелей, хотя предупреждает о конфликтах маршрутов и DNS. Ограничение OpenVPN Connect указано в его официальном FAQ.

Маршрут первого VPN

Первый профиль должен получать только маршрут к нужной сети:

route 10.128.66.0 255.255.255.0

Если этот маршрут уже присылает первый сервер, добавлять его в профиль не нужно.

Чтобы управляющее соединение первого VPN не попало во второй туннель, добавьте маршрут к адресу первого сервера в оба профиля:

route 198.51.100.20 255.255.255.255 net_gateway

Замените 198.51.100.20 на адрес первого VPN-сервера. net_gateway означает обычный шлюз, который существовал до подключения VPN.

DNS

Только один профиль Tunnelblick должен менять системный DNS:

  • первый VPN для 10.128.66.0/24 - Do not set nameserver;
  • второй интернет-VPN - Set nameserver.

Перед подключением Tunnelblick должен показывать одно соединение с установкой DNS-сервера и одно без неё. Подключайте первый VPN раньше интернет-VPN, а отключайте в обратном порядке. Это снижает риск неправильного восстановления DNS, но Tunnelblick всё равно предупреждает, что автоматическое переподключение одного из туннелей может нарушить порядок настроек.

Если корпоративные ресурсы открываются по внутренним DNS-именам, потребуется отдельная настройка split DNS. Доступ по IP-адресам от этого не зависит.

Порядок подключения

  1. Подключите первый VPN.
  2. Проверьте доступ к 10.128.66.0/24.
  3. Подключите интернет-VPN.

Проверьте маршруты:

route -n get 10.128.66.1
route -n get 198.51.100.20
route -n get 1.1.1.1

Маршрут к 10.128.66.0/24 должен вести в первый utun. Маршрут к серверу первого VPN должен вести через физический интерфейс en0 или en1. Остальной трафик должен идти во второй utun.

Схема работает по правилу самого длинного префикса. Маршрут 10.128.66.0/24 точнее маршрутов 0.0.0.0/1 и 128.0.0.0/1, поэтому трафик корпоративной сети выбирает первый VPN, а остальной IPv4-трафик - второй.

Итог

Рабочий OpenVPN-сервер состоит из четырёх частей:

  1. сертификатов сервера и клиента;
  2. TUN-подсети, которая не пересекается с другими сетями;
  3. включённой пересылки IPv4 и правила MASQUERADE;
  4. клиентского профиля с маршрутом по умолчанию и DNS.

Если эти части настроены отдельно и проверены по порядку, искать ошибку обычно приходится в одном конкретном месте, а не во всей сети сразу.


Комментарии в Telegram-группе!