在與 HAProxy 相同的機器上運行 OpenConnect VPN 服務器和 Apache/Nginx


本教程展示瞭如何在與 HAProxy 相同的機器上運行 OpenConnect VPN 服務器 (ocserv) 和 Apache/Nginx。 OpenConnect (ocserv) 是 Cisco AnyConnect VPN 協議的開源實現。

先決條件

遵循本教程假設您已經使用 Let’s Encrypt TLS 服務器證書設置了 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 在 CentOS 8/RHEL 8 上設置 OpenConnect VPN 服務器 (ocserv)

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

默認情況下,OpenConnect VPN 服務器偵聽端口 443。如果您已經讓 Apache/Nginx 監聽 443 端口,則 ocserv 將無法綁定 443 端口。儘管可以將 ocserv 配置為偵聽不同的端口,但它需要最終用戶在客戶端軟件中指定端口,如果用戶體驗受到關注,則應避免使用。此外,TCP 端口 443 上的 TLS 流量通常具有更高的 QoS(服務質量)優先級,速度更快。

一個端口通常只能由一個進程使用。但是,您可以通過 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

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

sudo systemctl restart ocserv

其次,我們還需要確保我們的 Web 服務器只監聽 localhost,而不是我們的公共 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(服務器名稱指示)功能來區分 VPN 流量和常規 HTTPS 流量。

  • 什麼時候 vpn.example.com 對於 TLS Client Hello,HAProxy 將流量重定向到 ocserv 後端。
  • 什麼時候 www.example.com 對於 TLS Client Hello,HAProxy 將流量重定向到 apache/nginx 後端。
  • 如果客戶端沒有在 TLS Client Hello 中指定服務器名稱,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 應用程序不支持 TLS SNI,我們建議對其進行配置。 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 因此,一旦您在 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

UFW 防火牆上的 IPv6 偽裝

默認情況下,UFW 禁用數據包轉發。您可以允許在私有 IPv6 網絡上轉發。查出 ufw6-before-forward 如果源 IP 或目標 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

您可以查看偽裝規則。

在 ocserv openconnect vpn 中啟用 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 僅保護一種協議”警告應該消失。

測試連接 IPv6 的 ocserv VPN

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

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

包起來

我希望本教程可以幫助您在同一個機器上運行 OpenConnect VPN 服務器和 Apache/Nginx。與往常一樣,如果您發現這篇文章有幫助,請註冊我們的免費新聞通訊以獲取提示和技巧。照顧好自己?