OpenVPN на Ubuntu : Полное руководство без граблей (готовые скрипты, установка в два шага)

Введение

Это руководство создано на основе реального опыта развёртывания OpenVPN-сервера с подробным разбором всех подводных камней. Особое внимание уделено критической проблеме повреждения клиентских конфигураций при генерации, которая приводит к невозможности подключения iOS-клиентов.

Что мы получим в итоге

Серверная часть:

  • Ubuntu 24.04 с OpenVPN 2.6.14
  • Easy-RSA 3.1.7 для управления PKI
  • Порт: 11940/UDP (настраиваемый)
  • Виртуальная подсеть: 10.9.0.0/24
  • Шифрование: AES-128-GCM с SHA256
  • DNS: AdGuard DNS (94.140.14.14, 94.140.15.15)
  • Полный NAT и маршрутизация через VPN

Клиентская часть:

  • Корректные .ovpn профили для всех платформ
  • Поддержка роутеров, iPhone, Android, macOS, Windows
  • Проверенная работа с Passepartout и OpenVPN Connect

Анатомия проблем и их решения

Проблема №1: ./easyrsa: No such file or directory

Суть: Пакет easy-rsa установлен, но скрипты не копируются в рабочий каталог автоматически.

Решение:

install -d -m 700 /etc/openvpn/easy-rsa
if [ ! -f /etc/openvpn/easy-rsa/easyrsa ]; then
  cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
fi

Проблема №2: No Easy-RSA ‘vars’ configuration file exists

Суть: Это предупреждение, а не ошибка. Easy-RSA 3 работает без vars файла.

Ошибка, которой нужно избегать:

# ❌ НЕПРАВИЛЬНО - вызовет "Option conflict"
EASYRSA_REQ_CN="server" ./easyrsa build-server-full server nopass

Правильно:

# ✅ CA создаём с CN
EASYRSA_BATCH=1 ./easyrsa build-ca nopass

# ✅ Серверный и клиентские сертификаты - БЕЗ внешнего CN
EASYRSA_BATCH=1 ./easyrsa build-server-full server nopass
EASYRSA_BATCH=1 ./easyrsa build-client-full client1 nopass

Проблема №3: Битые клиентские конфигурации (КРИТИЧЕСКАЯ!)

Это самая коварная проблема, которая приводила к тому, что iOS-клиенты вообще не могли подключиться.

Симптомы:

  • iOS-клиенты (Passepartout, OpenVPN Connect) зависают на «Активация»
  • Ошибка: PEM routines::no start line
  • В серверных логах НЕТ попыток подключения
  • Роутеры подключаются нормально (используют старые профили)

Почему так происходило:

Старая версия скрипта пыталась вставить сертификаты через sed и подстановки:

# ❌ НЕПРАВИЛЬНО - приводит к битым сертификатам!
cat >profile.ovpn <<EOF
<cert>
$(sed -ne '/BEGIN CERTIFICATE/,\$p' "$CRT")
</cert>
EOF

Проблемы этого подхода:

  1. Неправильное экранирование в sed: \$p вместо $p
  2. Подстановка $(...) может обрезать многострочный вывод
  3. Heredoc с подстановками некорректно обрабатывает спецсимволы в PEM
  4. Даже при ошибке sed файл записывается, но с битым содержимым

Диагностика проблемы:

# Проверка сертификатов в PKI (должны быть OK)
openssl x509 -in /etc/openvpn/easy-rsa/pki/ca.crt -noout -text | head -5
# ✅ Работает

# Проверка CA в .ovpn профиле
awk '/<ca>/{flag=1;next}/<\/ca>/{flag=0}flag' client1.ovpn | \
  openssl x509 -noout -text | head -5
# ✅ CA в профиле OK

# Проверка клиентского сертификата в .ovpn
awk '/<cert>/{flag=1;next}/<\/cert>/{flag=0}flag' client1.ovpn | \
  openssl x509 -noout -text | head -5
# ❌ Unable to load certificate - БИТЫЙ!

Правильное решение:

# ✅ ПРАВИЛЬНО - гарантирует корректные PEM-блоки
cat >profile.ovpn <<'EOF'
<cert>
EOF

cat "$CRT" >> profile.ovpn

cat >>profile.ovpn <<'EOF'
</cert>
EOF

Ключевые моменты:

  • <<'EOF' — одинарные кавычки отключают подстановки
  • cat "$CRT" >> — прямое добавление без обработки
  • Никакого sed, никаких подстановок $(...), никакого парсинга

Проблема №4: Конфликт nftables и iptables-nft

Суть: На системах с iptables-nft команды nft вызывают предупреждение:

Warning: table ip nat is managed by iptables-nft, do not touch!

Решение: Использовать только iptables команды:

WAN_IF="$(ip route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')"
iptables -t nat -A POSTROUTING -s 10.9.0.0/24 -o "$WAN_IF" -j MASQUERADE
netfilter-persistent save

Архитектура инфраструктуры

Internet
    │
    ├─→ VPS Server (X.X.X.X)
    │   ├─→ OpenVPN Server (11940/UDP)
    │   │   ├─→ tun0 (10.9.0.1/24)
    │   │   ├─→ NAT → eth0
    │   │   └─→ PKI (Easy-RSA)
    │   │
    │   └─→ /root/
    │       ├─→ bootstrap_openvpn.sh (первоначальная установка)
    │       ├─→ make_client.sh (создание клиентов)
    │       └─→ ovpn/
    │           ├─→ client1.ovpn
    │           ├─→ iphone-ios.ovpn
    │           └─→ laptop.ovpn
    │
    └─→ Clients
        ├─→ Router (10.9.0.2)
        ├─→ iPhone (10.9.0.3)
        ├─→ Laptop (10.9.0.4)
        └─→ ...

СКРИПТ №1: Полная автоматическая установка

Этот скрипт выполняет полную установку OpenVPN-сервера с нуля и создаёт первый клиентский конфиг.

Создание скрипта bootstrap_openvpn.sh

cat >/root/bootstrap_openvpn.sh <<'BOOTSTRAP'
#!/usr/bin/env bash
set -euo pipefail

# --- Настройки, можно изменить перед запуском ---
PORT="${PORT:-11940}"
SUBNET="${SUBNET:-10.9.0.0/24}"
DNS1="${DNS1:-94.140.14.14}"
DNS2="${DNS2:-94.140.15.15}"
CLIENT_NAME="${CLIENT_NAME:-client1}"

echo "==> Установка пакетов"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y openvpn easy-rsa iptables-persistent curl

# --- Easy-RSA / PKI ---
echo "==> Настройка Easy-RSA и PKI"
install -d -m 700 /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa

# Если скрипты Easy-RSA не скопированы — копируем из /usr/share/easy-rsa
if [ ! -f "./easyrsa" ]; then
  echo "==> Копирую шаблон Easy-RSA"
  cp -r /usr/share/easy-rsa/* .
fi

# Инициализируем PKI, если её ещё нет
if [ ! -d "pki" ]; then
  echo "==> init-pki"
  ./easyrsa init-pki
fi

# CA
if [ ! -f "pki/ca.crt" ]; then
  echo "==> build-ca"
  EASYRSA_BATCH=1 ./easyrsa build-ca nopass
fi

# Серверный сертификат
if [ ! -f "pki/issued/server.crt" ]; then
  echo "==> build-server-full server"
  EASYRSA_BATCH=1 ./easyrsa build-server-full server nopass
fi

# DH
if [ ! -f "pki/dh.pem" ]; then
  echo "==> gen-dh"
  ./easyrsa gen-dh
fi

# CRL
if [ ! -f "pki/crl.pem" ]; then
  echo "==> gen-crl"
  ./easyrsa gen-crl
fi

install -d -m 755 /etc/openvpn/easy-rsa/pki
install -m 644 pki/crl.pem /etc/openvpn/easy-rsa/pki/crl.pem

# --- tls-crypt и каталоги OpenVPN ---
echo "==> tls-crypt и каталоги OpenVPN"
install -d -m 755 /etc/openvpn/server
install -d -m 755 /etc/openvpn/ccd
install -d -m 755 /var/log/openvpn

if [ ! -f /etc/openvpn/server/tls-crypt.key ]; then
  openvpn --genkey --secret /etc/openvpn/server/tls-crypt.key
fi

# --- server.conf ---
echo "==> Создаю /etc/openvpn/server/server.conf"
BASE_NET="${SUBNET%/*}"

cat >/etc/openvpn/server/server.conf <<CONF
port ${PORT}
proto udp
dev tun

user nobody
group nogroup
persist-key
persist-tun
keepalive 10 120
topology subnet

server ${BASE_NET} 255.255.255.0

push "redirect-gateway def1"
push "dhcp-option DNS ${DNS1}"
push "dhcp-option DNS ${DNS2}"

tls-crypt /etc/openvpn/server/tls-crypt.key
dh /etc/openvpn/easy-rsa/pki/dh.pem
crl-verify /etc/openvpn/easy-rsa/pki/crl.pem
ca  /etc/openvpn/easy-rsa/pki/ca.crt
cert /etc/openvpn/easy-rsa/pki/issued/server.crt
key  /etc/openvpn/easy-rsa/pki/private/server.key

auth SHA256
cipher AES-128-GCM
ncp-ciphers AES-128-GCM
tls-server
tls-version-min 1.2

client-config-dir /etc/openvpn/ccd
status /var/log/openvpn/status.log
verb 3
CONF

# --- IPv4 forwarding ---
echo "==> Включаю IPv4 forwarding"
sysctl -w net.ipv4.ip_forward=1 >/dev/null
echo 'net.ipv4.ip_forward=1' >/etc/sysctl.d/99-openvpn.conf

# --- NAT через iptables ---
echo "==> Настройка NAT (iptables)"
WAN_IF="$(ip route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')"
echo "    WAN_IF=${WAN_IF}"

# Маскарадинг для подсети VPN
if ! iptables -t nat -C POSTROUTING -s "${SUBNET}" -o "${WAN_IF}" -j MASQUERADE 2>/dev/null; then
  iptables -t nat -A POSTROUTING -s "${SUBNET}" -o "${WAN_IF}" -j MASQUERADE
fi

# Сохраняем правила
if command -v netfilter-persistent >/dev/null 2>&1; then
  netfilter-persistent save
else
  iptables-save >/etc/iptables/rules.v4
fi

# --- Запуск OpenVPN ---
echo "==> Запуск OpenVPN"
systemctl enable openvpn-server@server
systemctl restart openvpn-server@server

# Даём время на запуск
sleep 2

echo "==> Проверка слушателя (udp/${PORT}) и tun0"
ss -lunp | grep -w ":${PORT}" || echo "ВНИМАНИЕ: порт ${PORT}/udp пока не виден в ss"
ip addr show tun0 || echo "ВНИМАНИЕ: интерфейс tun0 пока не найден"

# --- Скрипт для клиентов /root/make_client.sh ---
echo "==> Создаю /root/make_client.sh"
cat >/root/make_client.sh <<'CLI'
#!/usr/bin/env bash
set -euo pipefail

NAME="${1:-client1}"
OUT_DIR="/root/ovpn"
PORT="${PORT:-11940}"
HOST="${HOST:-$(curl -4 -s ifconfig.me)}"
EASYRSA_DIR="/etc/openvpn/easy-rsa"
TLS_KEY="/etc/openvpn/server/tls-crypt.key"

install -d -m 755 "$OUT_DIR"

cd "$EASYRSA_DIR"

if [ ! -f "pki/issued/${NAME}.crt" ]; then
  echo "==> Выпускаю новый сертификат для клиента: ${NAME}"
  EASYRSA_BATCH=1 ./easyrsa build-client-full "${NAME}" nopass
else
  echo "==> Сертификат для ${NAME} уже существует, использую его"
fi

CRT="pki/issued/${NAME}.crt"
KEY="pki/private/${NAME}.key"
CA="pki/ca.crt"

OUT="${OUT_DIR}/${NAME}.ovpn"

echo "==> Собираю профиль: ${OUT}"

cat >"$OUT" <<EOF
client
dev tun
proto udp
remote ${HOST} ${PORT}
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-128-GCM
auth SHA256
key-direction 1
verb 3

<ca>
EOF

cat "$CA" >>"$OUT"

cat >>"$OUT" <<'EOF'
</ca>
<cert>
EOF

cat "$CRT" >>"$OUT"

cat >>"$OUT" <<'EOF'
</cert>
<key>
EOF

cat "$KEY" >>"$OUT"

cat >>"$OUT" <<'EOF'
</key>
<tls-crypt>
EOF

cat "$TLS_KEY" >>"$OUT"

cat >>"$OUT" <<'EOF'
</tls-crypt>
EOF

echo "✅ Профиль создан: ${OUT}"
echo "   Пример копирования на Mac: scp root@${HOST}:${OUT} ./"
CLI

chmod +x /root/make_client.sh

# --- Первый клиент ---
echo "==> Создаю первого клиента: ${CLIENT_NAME}"
/root/make_client.sh "${CLIENT_NAME}"

echo
echo "✅ Готово!"
echo "  - Статус OpenVPN: systemctl status openvpn-server@server --no-pager -n 20"
echo "  - Порт:           ${PORT}/udp; сеть: ${SUBNET}; DNS: ${DNS1}, ${DNS2}"
echo "  - Клиентский .ovpn: /root/ovpn/${CLIENT_NAME}.ovpn"
echo "  - Скачать на Mac:  scp root@$(curl -4 -s ifconfig.me):/root/ovpn/${CLIENT_NAME}.ovpn ./"
echo
BOOTSTRAP

chmod +x /root/bootstrap_openvpn.sh

Запуск установки

С параметрами по умолчанию:

/root/bootstrap_openvpn.sh

С кастомными параметрами:

# Изменить порт и подсеть
PORT=1194 SUBNET=10.8.0.0/24 CLIENT_NAME=myrouter /root/bootstrap_openvpn.sh

# Использовать другие DNS
DNS1=8.8.8.8 DNS2=8.8.4.4 /root/bootstrap_openvpn.sh

СКРИПТ №2: Генерация клиентских конфигураций

Этот скрипт создаёт новые клиентские конфигурации после установки сервера. Он автоматически создаётся bootstrap скриптом, но вы также можете создать его вручную.

Создание скрипта make_client.sh

cat >/root/make_client.sh <<'MAKECLIENT'
#!/usr/bin/env bash
set -euo pipefail

NAME="${1:-client1}"
OUT_DIR="/root/ovpn"
PORT="${PORT:-11940}"
HOST="${HOST:-$(curl -4 -s ifconfig.me)}"
EASYRSA_DIR="/etc/openvpn/easy-rsa"
TLS_KEY="/etc/openvpn/server/tls-crypt.key"

install -d -m 755 "$OUT_DIR"

cd "$EASYRSA_DIR"

if [ ! -f "pki/issued/${NAME}.crt" ]; then
  echo "==> Выпускаю новый сертификат для клиента: ${NAME}"
  EASYRSA_BATCH=1 ./easyrsa build-client-full "${NAME}" nopass
else
  echo "==> Сертификат для ${NAME} уже существует, использую его"
fi

CRT="pki/issued/${NAME}.crt"
KEY="pki/private/${NAME}.key"
CA="pki/ca.crt"

OUT="${OUT_DIR}/${NAME}.ovpn"

echo "==> Собираю профиль: ${OUT}"

# КРИТИЧЕСКИ ВАЖНО: используем последовательные cat без подстановок!
# Это предотвращает повреждение PEM-блоков, которое приводит к ошибкам
# "PEM routines::no start line" на iOS-клиентах

cat >"$OUT" <<EOF
client
dev tun
proto udp
remote ${HOST} ${PORT}
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-128-GCM
auth SHA256
key-direction 1
verb 3

<ca>
EOF

# Добавляем CA сертификат через cat (НЕ через подстановку $(cat ...) !)
cat "$CA" >>"$OUT"

cat >>"$OUT" <<'EOF'
</ca>
<cert>
EOF

# Добавляем клиентский сертификат через cat (НЕ через sed!)
cat "$CRT" >>"$OUT"

cat >>"$OUT" <<'EOF'
</cert>
<key>
EOF

# Добавляем приватный ключ через cat
cat "$KEY" >>"$OUT"

cat >>"$OUT" <<'EOF'
</key>
<tls-crypt>
EOF

# Добавляем TLS-crypt ключ через cat
cat "$TLS_KEY" >>"$OUT"

cat >>"$OUT" <<'EOF'
</tls-crypt>
EOF

echo "✅ Профиль создан: ${OUT}"
echo "   Пример копирования на Mac: scp root@${HOST}:${OUT} ./"
MAKECLIENT

chmod +x /root/make_client.sh

Использование скрипта

# Создать конфиг для iPhone
/root/make_client.sh iphone-ios

# Создать конфиг для ноутбука
/root/make_client.sh laptop-work

# Создать конфиг для планшета
/root/make_client.sh ipad-home

# Создать конфиг для роутера
/root/make_client.sh router-home

# Проверить созданные конфигурации
ls -lh /root/ovpn/

Использование с переменными окружения

# Использовать другой порт
PORT=443 /root/make_client.sh client-special

# Использовать конкретный IP вместо автоопределения
HOST=192.168.1.100 /root/make_client.sh client-local

# Комбинация параметров
PORT=1194 HOST=my.vpn.server.com /root/make_client.sh mobile-device

Почему именно такой подход?

Проблема старого метода

# ❌ НЕПРАВИЛЬНО - вызывает повреждение PEM-блоков
cat >profile.ovpn <<EOF
<cert>
$(sed -ne '/BEGIN CERTIFICATE/,\$p' "$CRT")
</cert>
EOF

Проблемы:

  1. sed с неправильным экранированием (\$p вместо $p)
  2. Подстановка $(...) может обрезать многострочный вывод
  3. Heredoc с интерполяцией искажает специальные символы
  4. Результат: битые PEM-блоки в .ovpn файлах

Правильное решение

# ✅ ПРАВИЛЬНО - побайтовое копирование без обработки
cat >>"$OUT" <<'EOF'
<cert>
EOF
cat "$CRT" >>"$OUT"
cat >>"$OUT" <<'EOF'
</cert>
EOF

Преимущества:

  • Никакой обработки содержимого файлов
  • Побайтовое копирование сертификатов
  • Все переносы строк сохраняются
  • Работает на всех платформах (iOS, Android, Windows, macOS, Linux)

Пошаговая установка

Шаг 1: Подготовка сервера

# Подключитесь к серверу
ssh root@YOUR_SERVER_IP

# Обновите систему (опционально)
apt-get update && apt-get upgrade -y

Шаг 2: Создание и запуск bootstrap скрипта

# Создайте скрипт (скопируйте содержимое СКРИПТА №1)
nano /root/bootstrap_openvpn.sh

# Или загрузите скрипт одной командой (если он у вас на GitHub/сервере)
# wget -O /root/bootstrap_openvpn.sh https://example.com/bootstrap_openvpn.sh

# Сделайте исполняемым
chmod +x /root/bootstrap_openvpn.sh

# Запустите
/root/bootstrap_openvpn.sh

Шаг 3: Проверка установки

# 1. Статус службы
systemctl status openvpn-server@server --no-pager -n 20
# Ожидаем: active (running) и "Initialization Sequence Completed"

# 2. Сетевой интерфейс
ip addr show tun0
# Ожидаем: inet 10.9.0.1/24

# 3. Прослушиваемый порт
ss -lunp | grep 11940
# Ожидаем: udp UNCONN 0 0 0.0.0.0:11940 ... users:(("openvpn",pid=...))

# 4. IP forwarding
sysctl net.ipv4.ip_forward
# Ожидаем: net.ipv4.ip_forward = 1

# 5. NAT правила
iptables -t nat -L POSTROUTING -n -v | grep 10.9.0.0
# Ожидаем: строку с MASQUERADE для 10.9.0.0/24

# 6. Клиентские конфигурации
ls -lh /root/ovpn/
# Ожидаем: client1.ovpn

Шаг 4: Создание дополнительных клиентов

# Используйте СКРИПТ №2
/root/make_client.sh iphone-ty
/root/make_client.sh laptop-ms
/root/make_client.sh ipad-family

Шаг 5: Проверка корректности профилей

ОБЯЗАТЕЛЬНО проверяйте профили перед отправкой клиентам!

cd /root/ovpn

# Проверка CA (должна быть OK)
awk '/<ca>/{flag=1;next}/<\/ca>/{flag=0}flag' iphone-ty.ovpn | \
  openssl x509 -noout -text | head -5

# Проверка клиентского сертификата (должна быть OK)
awk '/<cert>/{flag=1;next}/<\/cert>/{flag=0}flag' iphone-ty.ovpn | \
  openssl x509 -noout -text | head -5

# Проверка ключа (должна быть OK)
awk '/<key>/{flag=1;next}/<\/key>/{flag=0}flag' iphone-ty.ovpn | \
  openssl rsa -noout -check 2>&1 | head -5

Хорошие результаты:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
        Signature Algorithm: sha256WithRSAEncryption

Плохие результаты (битый профиль!):

unable to load certificate
Could not read certificate from stdin
PEM routines::no start line

Если видите ошибку — пересоздайте профиль через /root/make_client.sh.

Шаг 6: Скачивание конфигураций

На macOS/Linux:

scp root@YOUR_SERVER_IP:/root/ovpn/iphone-ty.ovpn ./

На Windows (PowerShell):

scp root@YOUR_SERVER_IP:/root/ovpn/laptop-ms.ovpn C:\Users\YourName\Downloads\

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

iOS (iPhone/iPad)

  1. Установите OpenVPN Connect или Passepartout из App Store
  2. Отправьте .ovpn файл через AirDrop или Files
  3. Откройте файл → выберите приложение VPN
  4. Импортируйте профиль и подключитесь

macOS

  1. Установите Tunnelblick или OpenVPN Connect
  2. Импортируйте .ovpn файл
  3. Подключитесь к VPN

Android

  1. Установите OpenVPN for Android
  2. Импортируйте .ovpn через меню приложения
  3. Подключитесь

Windows

  1. Установите OpenVPN GUI
  2. Скопируйте .ovpn в C:\Program Files\OpenVPN\config\
  3. Запустите OpenVPN GUI и подключитесь

Linux

sudo openvpn --config client1.ovpn

Роутеры (OpenWrt, DD-WRT, Mikrotik)

Импортируйте .ovpn через веб-интерфейс роутера в разделе VPN/OpenVPN.


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

На клиенте после подключения:

# Проверка VPN-интерфейса
ip addr show tun0
# Должен быть адрес из диапазона 10.9.0.0/24

# Проверка маршрута
ip route | grep tun0
# Должен быть default через tun0

# Проверка публичного IP
curl ifconfig.me
# Должен показать IP VPN-сервера

На iPhone: откройте Safari → https://ifconfig.me (должен показать IP сервера)


Диагностика проблем

Сервер не запускается

# Детальные логи
journalctl -u openvpn-server@server -n 100 --no-pager

# Проверка конфигурации
openvpn --config /etc/openvpn/server/server.conf --test-parse

# Проверка сертификатов
openssl x509 -in /etc/openvpn/easy-rsa/pki/issued/server.crt -noout -text
openssl rsa -in /etc/openvpn/easy-rsa/pki/private/server.key -check

Клиент не может подключиться

Мониторинг логов на сервере:

# Реальное время
tail -f /var/log/openvpn/status.log
journalctl -u openvpn-server@server -f

# Активные подключения
cat /var/log/openvpn/status.log | grep CLIENT_LIST

Типичные ошибки:

  1. PEM routines::no start line
    • Битый .ovpn профиль
    • Решение: пересоздать через make_client.sh
  2. TLS Error: TLS key negotiation failed
    • Неправильный tls-crypt ключ
    • Решение: проверить совпадение ключа
  3. Connection timeout
    • Порт заблокирован
    • Решение: ufw allow 11940/udp
  4. AUTH_FAILED
    • Сертификат отозван
    • Решение: создать новый сертификат

Нет интернета через VPN

# Проверка IP forwarding
sysctl net.ipv4.ip_forward
# Должно быть = 1

# Проверка NAT
iptables -t nat -L POSTROUTING -n -v
# Должно быть MASQUERADE для 10.9.0.0/24

# Тест с клиента
ping -c 3 10.9.0.1  # VPN-шлюз
ping -c 3 8.8.8.8   # Интернет

Обслуживание

Просмотр подключённых клиентов

# Текущий статус
cat /var/log/openvpn/status.log

# Только клиенты
grep "^CLIENT_LIST" /var/log/openvpn/status.log | \
  awk '{print $2, $3, $4, $5}'

Отзыв сертификата

cd /etc/openvpn/easy-rsa

# Отозвать
./easyrsa revoke client-to-revoke

# Обновить CRL
./easyrsa gen-crl
install -m 644 pki/crl.pem /etc/openvpn/easy-rsa/pki/crl.pem

# Перезапустить
systemctl restart openvpn-server@server

Автоматическое обновление CRL

cat > /etc/cron.daily/openvpn-crl <<'EOF'
#!/bin/bash
cd /etc/openvpn/easy-rsa
./easyrsa gen-crl
install -m 644 pki/crl.pem /etc/openvpn/easy-rsa/pki/crl.pem
systemctl reload openvpn-server@server
EOF

chmod +x /etc/cron.daily/openvpn-crl

Резервное копирование

Что сохранять

# Создать архив
tar czf openvpn-backup-$(date +%Y%m%d).tar.gz \
  /etc/openvpn/easy-rsa/pki \
  /etc/openvpn/server/server.conf \
  /etc/openvpn/server/tls-crypt.key \
  /root/make_client.sh \
  /root/bootstrap_openvpn.sh

# Скачать
scp root@SERVER_IP:openvpn-backup-*.tar.gz ./

Восстановление

# Установить пакеты
apt-get install -y openvpn easy-rsa iptables-persistent

# Распаковать
tar xzf openvpn-backup-20240101.tar.gz -C /

# Настроить NAT (из bootstrap скрипта)
# Запустить сервер
systemctl enable --now openvpn-server@server

Чек-лист развёртывания

  • [ ] Сервер Ubuntu 24.04 с root-доступом
  • [ ] Порт открыт в файрволе
  • [ ] Скопирован и запущен bootstrap_openvpn.sh
  • [ ] Служба active (running)
  • [ ] Интерфейс tun0 создан (10.9.0.1/24)
  • [ ] Порт слушается (ss -lunp | grep 11940)
  • [ ] IP forwarding включен (= 1)
  • [ ] NAT правило добавлено
  • [ ] Создан и проверен клиентский профиль
  • [ ] Сертификаты в .ovpn корректны (openssl проверка)
  • [ ] Клиент подключился
  • [ ] Клиент получил IP из VPN подсети
  • [ ] Интернет работает (curl ifconfig.me показывает IP сервера)
  • [ ] Настроено резервное копирование

Заключение

Это руководство основано на реальном опыте с подробным разбором всех проблем. Главная «граблевая» проблема — повреждение PEM-блоков в клиентских конфигурациях при использовании sed с heredoc.

Ключевые выводы

  1. ✅ Всегда используйте EASYRSA_BATCH=1
  2. ✅ Не передавайте CN для server/client сертификатов
  3. ✅ Используйте iptables для NAT, даже на nftables системах
  4. ✅ Собирайте .ovpn через последовательные cat, не через sed
  5. Проверяйте профили через openssl перед отправкой
  6. ✅ Разделяйте установку и генерацию клиентов
  7. ✅ Делайте резервные копии PKI

Два готовых скрипта

СКРИПТ №1 (bootstrap_openvpn.sh) — полная установка с нуля
СКРИПТ №2 (make_client.sh) — создание клиентских конфигов

Оба скрипта проверены в боевых условиях и работают без ошибок.


Версия: 3.0 (финальная с двумя полными скриптами)
Дата: Ноябрь 2025
Автор: На основе практического опыта развёртывания VPN-инфраструктуры