it:server:openvpn

OpenVPN

Pro servisní účely jsem potřeboval rychle rozběhnout OpenVPN. Nejprve jsem se docela trápil s nastavením konfiguračních souborů a certifikátů. Nicméně pak jsem objevil skript, který většinu věcí udělá za mě.

Projekt se skriptem se jmenuje openvpn-install.

Stažení je jednoduché:

curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod +x openvpn-install.sh

A pak už jenom spustit:

./openvpn-install.sh

Zbytkem provede jednoduchý průvodce. Pokud chci vytvářet další uživatele a jejich certifikáty po instalaci, stačí skript spustit znovu a v nabídce se objeví možnost Add a client. Úplně stejně budu postupovat, pokud budu chtít vypnout nějakého klienta.

Skript mi vytvořil soubor /etc/iptables/add-openvpn-rules.sh, ve kterém bylo nachystáno routování do vnitřní sítě. Nemusel jsem se tedy trápit s tím, že když se připojím do VPN sítě, tak se nedostanu do vnitřní sítě.

Tady je obsah souboru:

#!/bin/sh                                                           
iptables -t nat -I POSTROUTING 1 -s 10.8.0.0/24 -o wan -j MASQUERADE
iptables -I INPUT 1 -i tun0 -j ACCEPT                               
iptables -I FORWARD 1 -i wan -o tun0 -j ACCEPT                      
iptables -I FORWARD 1 -i tun0 -o wan -j ACCEPT                      
iptables -I INPUT 1 -i wan -p udp --dport 1194 -j ACCEPT            

Dále pak vytvoří soubor /etc/systemd/system/multi-user.target.wants/iptables-openvpn.service, který nastavuje v systemd spouštění skriptu s iptables:

[Unit]
Description=iptables rules for OpenVPN
Before=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/etc/iptables/add-openvpn-rules.sh
ExecStop=/etc/iptables/rm-openvpn-rules.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

A jako další vytvoří soubor pro spouštění vpnserveru /etc/systemd/system/multi-user.target.wants/openvpn@server.service.

Dále mi ve složce /etc/openvpn vytvořil konfigurační soubor server.conf.

Pokud chci zařídit, aby po připojení k VPN nešel internet přes VPN server, tak je potřeba v konfiguračním souboru serveru zakomentovat tento řádek:

#push "redirect-gateway def1 bypass-dhcp"

Dále je možné mít klidně více instancí OpenVPN serveru. Stačí zkopírovat konfigurační soubor server.conf a vytvořit například server2.conf. V souboru editovat vše potřebné a poté spustit další instanci serveru:

openvpn --config server2.conf

Pokud mám VPN server nastavená tak, že nebude směřovat tok internetu přes server, je potřeba ještě u VPN klienta u připojení zaškrtnout tuto volbu:

Když jsem ji neměl zaškrtnutou, tak mi po připojení k VPN nešel internet.

Při konfiguraci OpenVPN serveru je možné nastavit, jaký DNS server bude klient používat po připojení. To se provádí přidáním následujícího řádku do konfigurace OpenVPN serveru:

push "dhcp-option DNS 192.168.1.50"

Tento příkaz zajistí, že klient po připojení použije DNS server s IP adresou 192.168.1.50. Lze přidat i více DNS serverů, přičemž první uvedený bude primární.

Po připojení přes OpenVPN jsem ověřil nastavení DNS serveru pomocí příkazu:

resolvectl status

Výstup tohoto příkazu zobrazil aktuálně používané DNS servery, což umožňuje ověřit, zda se změna správně projevila.

Měl jsem problém, že ze serveru se mi nedařilo navázat spojení přes SSH u klientského počítače, který byl připojený přes VPN. Přitom ping na počítač fungoval a nmap mi potvrdil, že port s SSH je otevřený. Po delším zkoušení mě to dovedlo k tomu, že patrně dochází k fragmentaci packetů.

OpenVPN ve výchozím nastavení nebrání fragmentaci velkých TCP segmentů uvnitř tun-virt-rozhraní. Vaše MTU (1500 B na tun0) minus kryptografický overhead protokolu UDP/OpenVPN a minus IP/UDP hlavičky vychází někde kolem 1 400 B. Server ale posílá kusy až 1 388 B – to sice vypadá v pořádku, ale když se součet uvnitř šifrovaného UDP tunelu překlene do fragmentů (nebo někde v síti fragmenty zahazují), klient je už nikdy neslepí a TCP je neposkytne uživatelské aplikaci.

Vyřešil jsem to tak, že na konfiguračního souboru serveru jsem přidal:

mssfix 1200
tun-mtu 1400
  • mssfix 1200 přinutí OpenVPN, aby upravilo MSS v TCP handshake na 1200 B, takže SSHKEX paket nikdy nepřesáhne bezpečnou velikost.
  • tun-mtu 1400 pak nastavení tun-rozhraní na 1 400 B, aby zbyl dostatek místa i na OpenVPN hlavičky.

Bylo mi doporučeno to přidat i do konfiguračního souboru klienta, ale tam jsem to nepřidával a zatím to vypadá, že SSH už funguje.

Cílem je zajistit, aby se OpenVPN klient automaticky připojoval po startu systému a zároveň přesměrovával příchozí síťovou komunikaci na konkrétní zařízení ve vnitřní síti.

Klíčové je vložit konfigurační soubor do složky `/etc/openvpn/client/` a zajistit, aby měl příponu `.conf`. OpenVPN sice podporuje i příponu `.ovpn`, ale pouze `.conf` je systemd schopen automaticky spouštět.

Pro ruční spuštění postačí:

openvpn --config myclient.ovpn

Pro automatické spouštění použij:

systemctl start openvpn-client@myclient.service

Tento příkaz hledá konfigurační soubor `/etc/openvpn/client/myclient.conf`.

Doporučení: Chceš-li využívat výhody systemd (např. automatické restartování), přejmenuj soubor na `myclient.conf`. Obsah souboru může zůstat stejný jako `.ovpn`.

Pro stabilní spojení doporučujeme přidat do konfigurace řádek:

keepalive 10 60

To znamená, že klient každých 10 vteřin pošle „ping“ a po 60 vteřinách bez odpovědi restartuje spojení. Tento zápis je zjednodušený alias pro `–ping 10` a `–ping-restart 60`.

Shrnutí postupu:

  • Přejmenuj soubor na `myclient.conf`
  • Přidej (nebo ponech) `keepalive 10 60`
  • Zkontroluj umístění: `/etc/openvpn/client/myclient.conf`
  • Aktivuj a spusť službu:
systemctl enable openvpn-client@myclient
systemctl start openvpn-client@myclient

Ověření funkčnosti:

  • Stav služby:
    systemctl status openvpn-client@myclient
 
  • Aktivní tunel poznáš podle rozhraní `tun0`:
    ip a | grep tun0
 
  • Pro zobrazení logů:
journalctl -u openvpn-client@myclient

Aby bylo možné přeposílat komunikaci z VPN na zařízení v lokální síti, je potřeba povolit IP forwarding.

V souboru `/etc/sysctl.conf` nastav:

net.ipv4.ip_forward=1

Změnu načti pomocí:

sysctl -p

Přesměrování provozu pak zajistí vlastní skripty. Níže je příklad jednoduchého nastavení pro zařízení s IP `192.168.0.120`.

/etc/openvpn/up.sh

#!/usr/bin/env bash
set -euo pipefail
 
# Tento skript nakonfiguruje DNAT z OpenVPN (tun0) na interní stroj 10.112.234.112
# Přesměrování všech portů kromě SSH (port 22) s vyčištěním starých pravidel
 
# Kontrola, zda běží pod rootem
if [[ "$EUID" -ne 0 ]]; then
  echo "Prosím spusťte jako root nebo pomocí sudo." >&2
  exit 1
fi
 
# Proměnné – upravte podle potřeby
VPN_IF="tun0"
INT_IF="eth0"
DEST_IP="192.168.0.120"
EXCLUDE_PORT="22"
 
# 0) Načtení FTP helper modulů
#modprobe nf_conntrack_ftp
#modprobe nf_nat_ftp
 
# 0b) Připojení FTP helperu pro control channel (port 21)
iptables-legacy -t raw -A PREROUTING \
    -i "$VPN_IF" \
    -p tcp --dport 21 \
    -j CT --helper ftp
 
 
# 1) Vyčištění stávajících pravidel NAT a FORWARD
iptables-legacy -t nat -F PREROUTING
iptables-legacy -t nat -F POSTROUTING
iptables-legacy -F FORWARD
 
# 2) Povolit IP forwarding
sysctl -w net.ipv4.ip_forward=1
if ! grep -q '^net.ipv4.ip_forward' /etc/sysctl.conf; then
  echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
fi
 
# 3) DNAT: přesměrování všech TCP portů kromě SSH na interní stroj
iptables-legacy -t nat -A PREROUTING \
    -i "$VPN_IF" \
    -p tcp -m tcp ! --dport "$EXCLUDE_PORT" \
    -j DNAT --to-destination ${DEST_IP}
 
# 4) DNAT: přesměrování všech UDP portů kromě SSH na interní stroj
iptables-legacy -t nat -A PREROUTING \
    -i "$VPN_IF" \
    -p udp -m udp ! --dport "$EXCLUDE_PORT" \
    -j DNAT --to-destination ${DEST_IP}
 
# 5) Povolit forward chain pro směry tun0 → eth0 (nové i navázané relace)
iptables-legacy -A FORWARD \
    -i "$VPN_IF" -o "$INT_IF" -d "$DEST_IP" \
    -j ACCEPT
iptables-legacy -A FORWARD \
    -i "$INT_IF" -o "$VPN_IF" \
    -m state --state ESTABLISHED,RELATED \
    -j ACCEPT
 
# 6) SNAT/MASQUERADE pro interní stroj, pokud nemá přímou zpětnou cestu
iptables-legacy -t nat -A POSTROUTING \
    -o "$INT_IF" \
    -d "$DEST_IP" \
    -j MASQUERADE
 
# Hotovo
echo "Vyčištěna stará pravidla a aplikován DNAT pro všechna porty kromě portu ${EXCLUDE_PORT}."

/etc/openvpn/down.sh

#!/usr/bin/env bash
set -euo pipefail
 
# Tento skript odstraní pravidla DNAT a SNAT z předchozího setupu
 
# Kontrola, zda běží pod rootem
if [[ "$EUID" -ne 0 ]]; then
  echo "Prosím spusťte jako root nebo pomocí sudo." >&2
  exit 1
fi
 
# Proměnné – musí odpovídat setup skriptu
VPN_IF="tun0"
INT_IF="eth0"
DEST_IP="192.168.0.120"
EXCLUDE_PORT="22"
 
# Odstranění raw/FTP helper pravidla
iptables-legacy -t raw -D PREROUTING -i "$VPN_IF" -p tcp --dport 21 -j CT --helper ftp || true
 
# Vyčištění pravidel NAT a FORWARD vztahujících se k tun0 a DEST_IP
iptables-legacy -t nat -D PREROUTING -i "$VPN_IF" -p tcp -m tcp ! --dport "$EXCLUDE_PORT" -j DNAT --to-destination ${DEST_IP} || true
iptables-legacy -t nat -D PREROUTING -i "$VPN_IF" -p udp -m udp ! --dport "$EXCLUDE_PORT" -j DNAT --to-destination ${DEST_IP} || true
iptables-legacy -t nat -D POSTROUTING -o "$INT_IF" -d "$DEST_IP" -j MASQUERADE || true
iptables-legacy -D FORWARD -i "$VPN_IF" -o "$INT_IF" -d "$DEST_IP" -j ACCEPT || true
iptables-legacy -D FORWARD -i "$INT_IF" -o "$VPN_IF" -m state --state ESTABLISHED,RELATED -j ACCEPT || true
 
# Volitelné: vrátit ip_forward do výchozí hodnoty (pokud potřebujete)
# sysctl -w net.ipv4.ip_forward=0
 
echo "Pravidla DNAT/SNAT byla odstraněna."

Poznámka: Pokud síťové rozhraní není `eth0`, uprav `$INTERNAL_IF` podle výstupu příkazu `ip a`.

Skripty je potřeba zpřístupnit pro spuštění:

chmod +x /etc/openvpn/up.sh /etc/openvpn/down.sh

A nakonec je přidej do konfiguračního souboru `myclient.conf`:

script-security 2
up /etc/openvpn/up.sh
down /etc/openvpn/down.sh

Ověření po navázání tunelu:

iptables-legacy -t nat -L -n -v
iptables-legacy -L -n -v
  • it/server/openvpn.txt
  • Poslední úprava: 2025/06/18 12:20
  • autor: Petr Nosek