Введение
Это руководство создано на основе реального опыта развёртывания 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
Проблемы этого подхода:
- Неправильное экранирование в sed:
\$pвместо$p - Подстановка
$(...)может обрезать многострочный вывод - Heredoc с подстановками некорректно обрабатывает спецсимволы в PEM
- Даже при ошибке 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
Проблемы:
sedс неправильным экранированием (\$pвместо$p)- Подстановка
$(...)может обрезать многострочный вывод - Heredoc с интерполяцией искажает специальные символы
- Результат: битые 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)
- Установите OpenVPN Connect или Passepartout из App Store
- Отправьте .ovpn файл через AirDrop или Files
- Откройте файл → выберите приложение VPN
- Импортируйте профиль и подключитесь
macOS
- Установите Tunnelblick или OpenVPN Connect
- Импортируйте .ovpn файл
- Подключитесь к VPN
Android
- Установите OpenVPN for Android
- Импортируйте .ovpn через меню приложения
- Подключитесь
Windows
- Установите OpenVPN GUI
- Скопируйте .ovpn в
C:\Program Files\OpenVPN\config\ - Запустите 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
Типичные ошибки:
- PEM routines::no start line
- Битый .ovpn профиль
- Решение: пересоздать через
make_client.sh
- TLS Error: TLS key negotiation failed
- Неправильный tls-crypt ключ
- Решение: проверить совпадение ключа
- Connection timeout
- Порт заблокирован
- Решение:
ufw allow 11940/udp
- 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.
Ключевые выводы
- ✅ Всегда используйте EASYRSA_BATCH=1
- ✅ Не передавайте CN для server/client сертификатов
- ✅ Используйте iptables для NAT, даже на nftables системах
- ✅ Собирайте .ovpn через последовательные cat, не через sed
- ✅ Проверяйте профили через openssl перед отправкой
- ✅ Разделяйте установку и генерацию клиентов
- ✅ Делайте резервные копии PKI
Два готовых скрипта
СКРИПТ №1 (bootstrap_openvpn.sh) — полная установка с нуля
СКРИПТ №2 (make_client.sh) — создание клиентских конфигов
Оба скрипта проверены в боевых условиях и работают без ошибок.
Версия: 3.0 (финальная с двумя полными скриптами)
Дата: Ноябрь 2025
Автор: На основе практического опыта развёртывания VPN-инфраструктуры