在與 HAProxy 相同的框中使用 OpenConnect VPN Server 運行 Apache / Nginx


本教程將向您展示如何在與 HAProxy 相同的框中運行 OpenConnect VPN Server (ocserv) 和 Apache / Nginx。 OpenConnect (ocserv) 是 Cisco AnyConnect VPN 協議的開源實現。

先決條件

要遵循本教程,我們假設您已經使用 Let’s EncryptTLS 服務器證書設置了 OpenConnect VPN 服務器。如果沒有,請遵循以下教程之一。

  • 使用 Let’s Encrypt 在 Ubuntu 20.04 上設置 OpenConnect VPN 服務器 (ocserv)
  • 使用 Let’s Encrypt 在 Ubuntu 16.04 / 18.04 上設置 OpenConnect VPN 服務器 (ocserv)
  • 使用 Let’s Encrypt 在 Debian 10 buster 上設置 OpenConnect VPN 服務器 (ocserv)
  • 使用 Let’s Encrypt 在 CentOS8 / RHEL8 上設置 OpenConnect VPN 服務器 (ocserv)

確保 OpenConnect VPN 服務器和 Web 服務器同時使用端口 443

默認情況下,OpenConnect VPN 服務器偵聽端口 443。如果 Apache / Nginx 已經在監聽 443 端口,則 ocserv 將無法綁定 443 端口。可以將 ocserv 配置為偵聽不同的端口,但最終用戶必須在客戶端軟件中指定端口。如果用戶體驗很重要,則應避免這種情況。此外,由於更高的服務質量 (QoS) 優先級,TCP 端口 443 上的 TLS 流量通常更快。

通常,一個端口只能由一個進程使用。但是,您可以使用 HAproxy(高可用性代理)和 SNI(服務器名稱顯示)來強制 ocserv 和 Apache/Nginx 都使用端口 443。

觀察組成

首先,編輯 ocserv 配置文件。

sudo nano /etc/ocserv/ocserv.conf

取消註釋下一行。這允許 ocserv 獲取客戶端 IP 地址而不是 HAproxy IP 地址。

listen-proxy-proto = true

然後找到以下行:

#listen-host = [IP|HOSTNAME]

改成

listen-host = 127.0.0.1

這會導致 HAproxy 稍後偵聽公共 IP 地址,因此 ocserv 將偵聽 127.0.0.1。保存並關閉文件。然後重新啟動 ocserv。

sudo systemctl restart ocserv

其次,您還需要確保 Web 服務器只偵聽本地主機,而不是公共 IP 地址。

Nginx 配置

如果您使用的是 Nginx,請編輯服務器塊文件。

sudo nano /etc/nginx/conf.d/example.com.conf

在 SSL 服務器塊中,找到以下指令:

listen 443 ssl;

改成

listen 127.0.0.2:443 ssl;

這次讓我知道 127.0.0.2:443 因為 127.0.0.1:443 已經被 ocserv 佔用。保存並關閉文件。 Nginx 主配置文件 /etc/nginx/nginx.conf 和默認的服務器塊 /etc/nginx/sites-enabled/default 您可能需要編輯此文件,因為您可能有一個默認的虛擬主機在 443 上偵聽。

然後重啟 Nginx。

sudo systemctl restart nginx

阿帕奇配置

如果您使用 Apache Web 服務器,請編輯虛擬主機文件。

Debian / Ubuntu

sudo nano /etc/apache2/sites-enabled/example.com.conf

CentOS / RHEL

sudo nano /etc/httpd/conf.d/example.com.conf

SSL 虛擬主機上的更改

<VirtualHost *:443>

到達

<VirtualHost 127.0.0.2:443>

這次讓我知道 127.0.0.2:443 因為 127.0.0.1:443 已經被 ocserv 佔用。保存並關閉文件。

然後編輯 /etc/apache2/ports.conf Debian / Ubuntu 上的文件。

sudo nano /etc/apache2/ports.conf

編輯/etc/httpd/conf.d/ssl.conf CentOS / RHEL 上的文件。

sudo nano /etc/httpd/conf.d/ssl.conf

改變

Listen 443

到達

Listen 127.0.0.2:443

保存並關閉文件。 重啟阿帕奇。

sudo systemctl restart apache2

sudo systemctl restart httpd

HAProxy 設置

接下來,安裝 HAProxy。

sudo apt install haproxy

sudo dnf install haproxy

啟動 HAProxy

sudo systemctl start haproxy

編輯配置文件。

sudo nano /etc/haproxy/haproxy.cfg

如果您使用的是 Nginx,請將以下行複制並粘貼到文件末尾:交換 12.34.56.78 使用服務器的公共 IP 地址。交換 vpn.example.com 使用 ocserv 使用的域名和 www.example.com Web 服務器使用的域名。

frontend https
   bind 12.34.56.78:443
   mode tcp
   tcp-request inspect-delay 5s
   tcp-request content accept if { req_ssl_hello_type 1 }

   use_backend ocserv if { req_ssl_sni -i vpn.example.com }
   use_backend nginx if { req_ssl_sni -i www.example.com }
   use_backend nginx if { req_ssl_sni -i example.com }

   default_backend ocserv

backend ocserv
   mode tcp
   option ssl-hello-chk
   # pass requests to 127.0.0.1:443. Proxy protocol (v2) header is required by ocserv.
   server ocserv 127.0.0.1:443 send-proxy-v2

backend nginx
   mode tcp
   option ssl-hello-chk
   server nginx 127.0.0.2:443 check

如果您使用的是 Apache,請將以下行複制並粘貼到文件末尾:交換 12.34.56.78 使用服務器的公共 IP 地址。交換 vpn.example.com 使用 ocserv 使用的域名和 www.example.com Web 服務器使用的域名。

frontend https
   bind 12.34.56.78:443
   mode tcp
   tcp-request inspect-delay 5s
   tcp-request content accept if { req_ssl_hello_type 1 }

   use_backend ocserv if { req_ssl_sni -i vpn.example.com }
   use_backend apache if { req_ssl_sni -i www.example.com }
   use_backend apache if { req_ssl_sni -i example.com }

   default_backend ocserv

backend ocserv
   mode tcp
   option ssl-hello-chk
   # pass requests to 127.0.0.1:443. Proxy protocol (v2) header is required by ocserv.
   server ocserv 127.0.0.1:443 send-proxy-v2

backend apache
    mode tcp
    option ssl-hello-chk
    server apache 127.0.0.2:443 check

保存並關閉文件。然後重啟HAproxy。

sudo systemctl restart haproxy

在上述配置中,使用了 TLS 的 SNI(Server Name Indication)功能來區分 VPN 流量和正常的 HTTPS 流量。

  • 什麼時候 vpn.example.com 使用 TLS Client Hello,HAProxy 將流量重定向到 ocserv 後端。
  • 什麼時候 www.example.com 使用 TLS Client Hello,HAProxy 將流量重定向到 apache / nginx 後端。
  • 如果客戶端沒有使用 TLSClientHello 指定服務器名稱,HAproxy 將使用默認後端 (ocserv)。

你可以使用它 openssl 工具。首先,多次運行以下命令。

echo | openssl s_client -connect your-server-IP:443 | grep subject

因為您沒有在上面的命令中指定服務器名稱,所以 HAproxy 總是將請求傳遞給默認後端(ocserv)並將證書發送到客戶端。然後運行以下兩個命令:

echo | openssl s_client -servername www.example.com -connect your-server-IP:443 | grep subject

echo | openssl s_client -servername vpn.example.com -connect your-server-IP:443 | grep subject

由於您在命令中指定了服務器名稱,HAproxy 會根據您定義的 SNI 規則傳遞請求。 Cisco AnyConnect 應用程序不支持 TLSSNI,因此最好對其進行配置。 ocserv 作為 HAProxy 配置文件的默認後端。

更新您網站的 Let’s Encrypt 證書時,我們建議您使用: http-01 改為挑戰 tls-alpn-01 HAproxy 正在監聽公共 IP 地址的 443 端口,這會干擾更新過程並導致問題。

sudo certbot renew --preferred-challenges http-01

修復了 HAProxy 錯誤

如果 Apache / Nginx 網站沒有出現在您的瀏覽器中,您將在 haproxy 日誌中看到以下消息(/var/log/haproxy.log)。

Server nginx/nginx is DOWN, reason: Socket error, info: "Connection reset by peer

backend nginx has no server available!

Layer6 invalid response

後端 Nginx Web 服務器可能正在使用具有所需 OCSP 主要擴展的 TLS 證書。 Nginx 不會在第一個 HTTP 請求上發送 OCSP 主食信息。為此,請將解析器添加到您的 Nginx 虛擬主機配置中,如下所示。

{
     ....
     ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/chain.pem;
     ssl_stapling on;
     ssl_stapling_verify on;

    resolver 8.8.8.8;
    ....
}

保存並關閉文件。然後重啟 Nginx。

sudo systemctl restart nginx

此外,請考慮使用 HAproxy 刪除後端服務器運行狀況檢查。所以改變

server nginx 127.0.0.2:443 check

到達

server nginx 127.0.0.2:443

保存並關閉文件。然後重啟HAproxy。

sudo systemctl restart haproxy

如何使用 HAProxy 在 ocserv 上啟用 IPv6

一、創建AAAA記錄 vpn.example.com 在 DNS 區域編輯器中,當您使用 ocserv 完成 IPv6 設置時,DNS 記錄需要傳播到 Internet。

測試 IPv6 連接性

要使用 IPv6 協議建立 VPN 隧道,請確保 VPN 服務器具有公共 IPv6 地址。 (VPN 客戶端不需要有公共 IPv6 地址。)要查找,請運行以下命令:

ip addr

找到主網絡接口。如果你能找到一個 inet6 .... scope global 在下一行中,您有一個公共 IPv6 地址。這個 inet6 地址與 scope link 私有 IPv6 地址。

然後轉到 https://test-ipv6.com/ 檢查您的 IPv6 連接。 如果 VPN 客戶端具有公共 IPv6 地址,則 VPN 可能看起來只保護一種協議,而不是同時保護兩種協議。這是因為我們沒有在 ocserv 上啟用 IPv6。

VPN 只保護一種協議,而不是同時保護兩種協議

在 ocserv 上啟用 IPv6

要在 ocserv 上啟用 IPv6,請編輯 ocserv 配置文件。

sudo nano /etc/ocserv/ocserv.conf

找到並取消註釋以下兩行,以便 VPN 客戶端可以獲得私有 IPv6 地址。

ipv6-network = fda9:4efe:7e3b:03ea::/48
ipv6-subnet-prefix = 64

如果您看到以下行

ipv6-network = fda9:4efe:7e3b:03ea::/64

更改如下。

ipv6-network = fda9:4efe:7e3b:03ea::/48

保存並關閉文件。重新啟動 ocserv 以使更改生效。

sudo systemctl restart ocserv

啟用 IPv6 IP 轉發

接下來,您需要在 Linux 內核中啟用 IPv6 IP 轉發。編輯 sysctl.conf 文檔。

sudo nano /etc/sysctl.conf

將以下行添加到此文件的末尾:

net.ipv6.conf.all.forwarding=1

保存並關閉文件。然後使用以下命令應用更改:

sudo sysctl -p

防火牆上的 IPv6 設置(Debian、Ubuntu)

接下來,您需要在 UFW 防火牆中配置 IPv6 偽裝,以使服務器成為 VPN 客戶端的虛擬路由器。

sudo nano /etc/ufw/before6.rules

默認情況下,有一些規則 filter 桌子。將以下行添加到此文件的末尾:交換 ens3 使用您自己的網絡接口名稱。 在 Nano 文本編輯器中,您可以按 Ctrl+W, 所以 Ctrl+V..

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o ens3 -j MASQUERADE

# End each table with the 'COMMIT' line or these rules won't be processed
COMMIT

IPv6 偽裝與 UFW 防火牆

默認情況下,UFW 禁用數據包轉發。您可以允許通過專用 IPv6 網絡進行轉發。查出 ufw6-before-forward 如果它包含源或目標 IP,請鏈接並將以下三行添加到此文件: fda9:4efe:7e3b:03ea::/48 範圍。

# allow forwarding for VPN
-A ufw6-before-forward -s fda9:4efe:7e3b:03ea::/48 -j ACCEPT
-A ufw6-before-forward -d fda9:4efe:7e3b:03ea::/48 -j ACCEPT

ufw 允許在 ipv6 網絡上轉發數據包

保存並關閉文件。您還需要在防火牆的 INPUT 鏈中允許 IPv6 VPN 客戶端。

sudo ufw allow in from fda9:4efe:7e3b:03ea::/48

重新啟動 UFW 以使更改生效。

sudo systemctl restart ufw

現在,如果您在 NAT 表的 POSTROUTING 鏈中列出規則:

sudo ip6tables -t nat -L POSTROUTING

你可以看到偽裝的規則。

使用 ocservopenconnectvpn 啟用 ipv6

斷開當前 VPN 連接並添加 AAAA 記錄 vpn.example.com 重新建立 VPN 連接。然後轉到 https://test-ipv6.com/ 檢查您的 IPv6 連接。

防火牆上的 IPv6 設置 (CentOS)

啟用 IPv6 偽裝。

sudo firewall-cmd --permanent --add-rich-rule="rule family="ipv6" source address="fda9:4efe:7e3b:03ea::/48" masquerade"

允許 INPUT 鏈中的 VPN 客戶端。

sudo firewall-cmd --permanent --add-rich-rule="rule family="ipv6" source address="fda9:4efe:7e3b:03ea::/48" accept"

重新加載 firewalld 以使更改生效。

sudo systemctl reload firewalld

使用 BIND 解析器配置 IPv6

如果您希望您的 VPN 服務器運行自己的 BIND DNS 解析器,您可以: /etc/ocserv/ocserv.conf 將 VPN 服務器配置為 VPN 客戶端的 DNS 解析器的文件。

dns = fda9:4efe:7e3b::1

保存並關閉文件。 要在 IPv6 中查詢 DNS 名稱,您需要配置 BIND 以允許 IPv6 VPN 客戶端。

Debian / Ubuntu

sudo nano /etc/bind/named.conf.options

查出 allow-recursion 設置參數並進行以下更改:

allow-recursion { 127.0.0.1; 10.10.10.0/24; fda9:4efe:7e3b:03ea::/48; };

保存並關閉文件。 重新啟動 BIND9。

sudo systemctl restart bind9

中央操作系統

sudo nano /etc/named.conf

查出 allow-query 設置參數並進行以下更改:

allow-query { 127.0.0.1; 10.10.10.0/24; fda9:4efe:7e3b:03ea::/48; };

保存並關閉文件。 重新啟動 BIND9。

sudo systemctl restart named

HAProxy 中的 IPv6 設置

編輯 HAProxy 配置文件。

sudo nano /etc/haproxy/haproxy.cfg

製作 https 前端偵聽 IPv4 和 IPv6 地址。顯然,您需要使用服務器的公共 IPv6 地址。

frontend https
   bind 12.34.56.78:443
   bind 2607:f8b0:4006:810::200e:443
   mode tcp
   tcp-request inspect-delay 5s
   tcp-request content accept if { req_ssl_hello_type 1 }

找下一個 ocserv 創建後端並添加 IPv6 服務器。

backend ocserv
   mode tcp
   option ssl-hello-chk
   server ocserv 127.0.0.1:443 send-proxy-v2
   server ocserv6 [::1]:443 send-proxy-v2

保存並關閉文件。

讓 ocserv 兩個都聽 127.0.0.1 什麼時候 ::1,編輯 /etc/hosts 文檔。

sudo nano /etc/hosts

編輯條目 127.0.0.1 什麼時候 ::1 如下, vpn.example.com 主機名可以解析為兩個地址。

127.0.0.1   localhost vpn.example.com

::1         ip6-localhost ip6-loopback vpn.example.com

保存並關閉文件。然後編輯 ocserv 配置文件。

sudo nano /etc/ocserv/ocserv.conf

找到下一行。

listen-host = 127.0.0.1

改成

listen-host  = vpn.example.com

ocserv 查找 IPv4 和 IPv6 地址 vpn.example.com 裡面 /etc/hosts 綁定到文件和兩者 127.0.0.1 什麼時候 ::1 地址。保存並關閉文件。然後重啟 ocserv 和 HAProxy

sudo systemctl restart ocserv
sudo systemctl restart haproxy

然後運行以下命令檢查 ocserv 的監聽狀態。你會看到它同時在聽 127.0.0.1 什麼時候 ::1..

sudo ss -lnpt | grep ocserv

sudo ss -lnpt | grep ocserv ipv6

測試 IPv6 連接性

重新啟動 VPN 客戶端並轉到 https://test-ipv6.com/ 以檢查 IPv6 連接。如果一切順利,測試結果應該會顯示 VPN 服務器的 IPv4 和 IPv6 地址。並且“VPN 僅保護一種協議”的警告應該消失。

OcservVPN 測試 IPv6 連接

如果測試結果沒有顯示 VPN 服務器的 IPv6 地址,您可能需要重新啟動 VPN 客戶端並重新建立 VPN 連接。

筆記:VPN 客戶端不需要公共 IPv6 地址。 您可以通過 IPv4 VPN 隧道使用 IPv6。

包起來

我們希望本教程能幫助您在同一個盒子中運行 OpenConnect VPN 服務器和 Apache / Nginx。與往常一樣,如果您覺得這篇文章有用,請訂閱我們的免費時事通訊以獲取更多提示和技巧。照顧好自己?