[
  {
    "path": ".github/ISSUE_TEMPLATE/00-bug-report.md",
    "content": "---\nname: Bug report\nabout: Tell us about a problem you are experiencing\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Checklist**\n\n- [ ] I read the [README](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md)\n- [ ] I read the [Important notes](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md#important-notes)\n- [ ] I followed instructions to [configure VPN clients](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md#next-steps)\n- [ ] I checked [IKEv1 troubleshooting](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#ikev1-troubleshooting), [IKEv2 troubleshooting](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md#ikev2-troubleshooting) and [VPN status](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#check-logs-and-vpn-status)\n- [ ] I searched existing [Issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue)\n- [ ] This bug is about the VPN setup scripts, and not IPsec VPN itself\n\n<!---\nIf you found a reproducible bug for the IPsec VPN, open a bug report at https://github.com/libreswan/libreswan. Ask VPN-related questions on the [Libreswan](https://lists.libreswan.org) or [strongSwan](https://lists.strongswan.org) users mailing list, or search e.g. [Stack Overflow](https://stackoverflow.com/questions/tagged/vpn).\n--->\n\n**Describe the issue**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n\n1. ...\n2. ...\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Logs**\n[Check logs and VPN status](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#check-logs-and-vpn-status), and add error logs to help explain the problem, if applicable.\n\n**Server (please complete the following information)**\n- OS: [e.g. Debian 11]\n- Hosting provider (if applicable): [e.g. GCP, AWS]\n\n**Client (please complete the following information)**\n- Device: [e.g. iPhone 12]\n- OS: [e.g. iOS 15]\n- VPN mode: [IPsec/L2TP, IPsec/XAuth (\"Cisco IPsec\") or IKEv2]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/10-bug-report-zh.md",
    "content": "---\nname: 错误报告\nabout: 请使用这个模板来提交 bug\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**任务列表**\n\n- [ ] 我已阅读[自述文件](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md)\n- [ ] 我已阅读[重要提示](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md#重要提示)\n- [ ] 我已按照说明[配置 VPN 客户端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md#下一步)\n- [ ] 我检查了 [IKEv1 故障排除](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#ikev1-故障排除)，[IKEv2 故障排除](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md#ikev2-故障排除)以及 [VPN 状态](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#检查日志及-vpn-状态)\n- [ ] 我搜索了已有的 [Issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue)\n- [ ] 这个 bug 是关于 VPN 安装脚本，而不是 IPsec VPN 本身\n\n<!---\n如果你发现了 IPsec VPN 的一个可重复的程序漏洞，请在 https://github.com/libreswan/libreswan 提交一个错误报告。VPN 的相关问题可在 [Libreswan](https://lists.libreswan.org) 或 [strongSwan](https://lists.strongswan.org) 用户邮件列表提问，或者搜索比如 [Stack Overflow](https://stackoverflow.com/questions/tagged/vpn) 等网站。\n--->\n\n**问题描述**\n使用清楚简明的语言描述这个 bug。\n\n**重现步骤**\n重现该 bug 的步骤：\n\n1. ...\n2. ...\n\n**期待的正确结果**\n简要地描述你期望的正确结果。\n\n**日志**\n[检查日志及 VPN 状态](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#检查日志及-vpn-状态)，并添加错误日志以帮助解释该问题（如果适用）。\n\n**服务器信息（请填写以下信息）**\n- 操作系统: [比如 Debian 11]\n- 服务提供商（如果适用）: [比如 GCP, AWS]\n\n**客户端信息（请填写以下信息）**\n- 设备: [比如 iPhone 12]\n- 操作系统: [比如 iOS 15]\n- VPN 模式: [IPsec/L2TP, IPsec/XAuth (\"Cisco IPsec\") 或 IKEv2]\n\n**其它信息**\n添加关于该 bug 的其它信息。\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/20-enhancement-request.md",
    "content": "---\nname: Enhancement request\nabout: Suggest an improvement for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Checklist**\n\n- [ ] I searched existing [Issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue), and did not find a similar enhancement request\n- [ ] This enhancement request is about the VPN setup scripts, and not IPsec VPN itself\n- [ ] I read the [README](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md)\n- [ ] I read the [Important notes](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md#important-notes)\n- [ ] I followed instructions to [configure VPN clients](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README.md#next-steps)\n- [ ] I checked [IKEv1 troubleshooting](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#ikev1-troubleshooting), [IKEv2 troubleshooting](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md#ikev2-troubleshooting) and [VPN status](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#check-logs-and-vpn-status)\n\n**Describe the enhancement request**\nA clear and concise description of your enhancement request.\n\n**Is your enhancement request related to a problem? Please describe.**\n(If applicable) A clear and concise description of what the problem is.\n\n**Additional context**\nAdd any other context about the enhancement request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/30-enhancement-request-zh.md",
    "content": "---\nname: 改进建议\nabout: 请使用这个模板来提交改进建议\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**任务列表**\n\n- [ ] 我搜索了已有的 [Issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue)，没有找到类似的改进建议\n- [ ] 这个改进建议是关于 VPN 安装脚本，而不是 IPsec VPN 本身\n- [ ] 我已阅读[自述文件](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md)\n- [ ] 我已阅读[重要提示](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md#重要提示)\n- [ ] 我已按照说明[配置 VPN 客户端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md#下一步)\n- [ ] 我检查了 [IKEv1 故障排除](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#ikev1-故障排除)，[IKEv2 故障排除](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md#ikev2-故障排除)以及 [VPN 状态](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#检查日志及-vpn-状态)\n\n**描述改进建议**\n使用清楚简明的语言描述你的改进建议。\n\n**你的改进建议与遇到的问题有关吗？请描述。**\n（如果适用）清楚，简洁地说明问题所在。\n\n**其它信息**\n添加关于该改进建议的其它信息。\n"
  },
  {
    "path": ".github/workflows/check_urls.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: check_urls\n\non: workflow_call\n\njobs:\n  check_urls:\n    runs-on: ubuntu-24.04\n    if: github.repository_owner == 'hwdsl2'\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Check\n        run: |\n          cd \"$GITHUB_WORKSPACE\"\n          mkdir workdir\n          cd workdir\n          set -ex\n\n          export DEBIAN_FRONTEND=noninteractive\n          sudo apt-get -yqq update\n          sudo apt-get -yqq install wget\n\n          wg=\"wget -t 3 -T 30 -nv -O\"\n          sl=\"sleep 1\"\n          gi=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master\"\n          gh=\"https://github.com/hwdsl2/setup-ipsec-vpn/raw/master\"\n\n          $wg vpnsetup.sh          \"$gi/vpnsetup.sh\"; $sl\n          $wg vpnsetup_centos.sh   \"$gi/vpnsetup_centos.sh\"; $sl\n          $wg vpnsetup_amzn.sh     \"$gi/vpnsetup_amzn.sh\"; $sl\n          $wg vpnsetup_ubuntu.sh   \"$gi/vpnsetup_ubuntu.sh\"; $sl\n          $wg vpnsetup_alpine.sh   \"$gi/vpnsetup_alpine.sh\"; $sl\n          $wg ikev2setup.sh        \"$gi/extras/ikev2setup.sh\"; $sl\n          $wg vpnupgrade.sh        \"$gi/extras/vpnupgrade.sh\"; $sl\n          $wg vpnupgrade_centos.sh \"$gi/extras/vpnupgrade_centos.sh\"; $sl\n          $wg vpnupgrade_amzn.sh   \"$gi/extras/vpnupgrade_amzn.sh\"; $sl\n          $wg vpnupgrade_ubuntu.sh \"$gi/extras/vpnupgrade_ubuntu.sh\"; $sl\n          $wg vpnupgrade_alpine.sh \"$gi/extras/vpnupgrade_alpine.sh\"; $sl\n          $wg vpnuninstall.sh      \"$gi/extras/vpnuninstall.sh\"; $sl\n          $wg add_vpn_user.sh      \"$gi/extras/add_vpn_user.sh\"; $sl\n          $wg del_vpn_user.sh      \"$gi/extras/del_vpn_user.sh\"; $sl\n          $wg update_vpn_users.sh  \"$gi/extras/update_vpn_users.sh\"; $sl\n          $wg ikev2changeaddr.sh   \"$gi/extras/ikev2changeaddr.sh\"; $sl\n          $wg ikev2onlymode.sh     \"$gi/extras/ikev2onlymode.sh\"; $sl\n\n          $wg vpnsetup2.sh          \"$gh/vpnsetup.sh\"; $sl\n          $wg vpnsetup_centos2.sh   \"$gh/vpnsetup_centos.sh\"; $sl\n          $wg vpnsetup_amzn2.sh     \"$gh/vpnsetup_amzn.sh\"; $sl\n          $wg vpnsetup_ubuntu2.sh   \"$gh/vpnsetup_ubuntu.sh\"; $sl\n          $wg vpnsetup_alpine2.sh   \"$gh/vpnsetup_alpine.sh\"; $sl\n          $wg ikev2setup2.sh        \"$gh/extras/ikev2setup.sh\"; $sl\n          $wg vpnupgrade2.sh        \"$gh/extras/vpnupgrade.sh\"; $sl\n          $wg vpnupgrade_centos2.sh \"$gh/extras/vpnupgrade_centos.sh\"; $sl\n          $wg vpnupgrade_amzn2.sh   \"$gh/extras/vpnupgrade_amzn.sh\"; $sl\n          $wg vpnupgrade_ubuntu2.sh \"$gh/extras/vpnupgrade_ubuntu.sh\"; $sl\n          $wg vpnupgrade_alpine2.sh \"$gh/extras/vpnupgrade_alpine.sh\"; $sl\n          $wg vpnuninstall2.sh      \"$gh/extras/vpnuninstall.sh\"; $sl\n          $wg add_vpn_user2.sh      \"$gh/extras/add_vpn_user.sh\"; $sl\n          $wg del_vpn_user2.sh      \"$gh/extras/del_vpn_user.sh\"; $sl\n          $wg update_vpn_users2.sh  \"$gh/extras/update_vpn_users.sh\"; $sl\n          $wg ikev2changeaddr2.sh   \"$gh/extras/ikev2changeaddr.sh\"; $sl\n          $wg ikev2onlymode2.sh     \"$gh/extras/ikev2onlymode.sh\"\n\n          diff vpnsetup.sh          ../vpnsetup.sh\n          diff vpnsetup_centos.sh   ../vpnsetup_centos.sh\n          diff vpnsetup_amzn.sh     ../vpnsetup_amzn.sh\n          diff vpnsetup_ubuntu.sh   ../vpnsetup_ubuntu.sh\n          diff vpnsetup_alpine.sh   ../vpnsetup_alpine.sh\n          diff ikev2setup.sh        ../extras/ikev2setup.sh\n          diff vpnupgrade.sh        ../extras/vpnupgrade.sh\n          diff vpnupgrade_centos.sh ../extras/vpnupgrade_centos.sh\n          diff vpnupgrade_amzn.sh   ../extras/vpnupgrade_amzn.sh\n          diff vpnupgrade_ubuntu.sh ../extras/vpnupgrade_ubuntu.sh\n          diff vpnupgrade_alpine.sh ../extras/vpnupgrade_alpine.sh\n          diff vpnuninstall.sh      ../extras/vpnuninstall.sh\n          diff add_vpn_user.sh      ../extras/add_vpn_user.sh\n          diff del_vpn_user.sh      ../extras/del_vpn_user.sh\n          diff update_vpn_users.sh  ../extras/update_vpn_users.sh\n          diff ikev2changeaddr.sh   ../extras/ikev2changeaddr.sh\n          diff ikev2onlymode.sh     ../extras/ikev2onlymode.sh\n\n          diff vpnsetup2.sh          ../vpnsetup.sh\n          diff vpnsetup_centos2.sh   ../vpnsetup_centos.sh\n          diff vpnsetup_amzn2.sh     ../vpnsetup_amzn.sh\n          diff vpnsetup_ubuntu2.sh   ../vpnsetup_ubuntu.sh\n          diff vpnsetup_alpine2.sh   ../vpnsetup_alpine.sh\n          diff ikev2setup2.sh        ../extras/ikev2setup.sh\n          diff vpnupgrade2.sh        ../extras/vpnupgrade.sh\n          diff vpnupgrade_centos2.sh ../extras/vpnupgrade_centos.sh\n          diff vpnupgrade_amzn2.sh   ../extras/vpnupgrade_amzn.sh\n          diff vpnupgrade_ubuntu2.sh ../extras/vpnupgrade_ubuntu.sh\n          diff vpnupgrade_alpine2.sh ../extras/vpnupgrade_alpine.sh\n          diff vpnuninstall2.sh      ../extras/vpnuninstall.sh\n          diff add_vpn_user2.sh      ../extras/add_vpn_user.sh\n          diff del_vpn_user2.sh      ../extras/del_vpn_user.sh\n          diff update_vpn_users2.sh  ../extras/update_vpn_users.sh\n          diff ikev2changeaddr2.sh   ../extras/ikev2changeaddr.sh\n          diff ikev2onlymode2.sh     ../extras/ikev2onlymode.sh\n"
  },
  {
    "path": ".github/workflows/cron.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: build cron\n\non:\n  schedule:\n    - cron: '25 2 * * 0,4'\n\njobs:\n  check_urls:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/check_urls.yml\n\n  test_set_1:\n    needs: check_urls\n    uses: ./.github/workflows/test_set_1.yml\n\n  test_set_2:\n    needs: check_urls\n    uses: ./.github/workflows/test_set_2.yml\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: build\n\non:\n  push:\n    branches: [master]\n    paths:\n      - '**.sh'\n      - '.github/workflows/main.yml'\n      - '.github/workflows/shellcheck.yml'\n      - '.github/workflows/test_set_1.yml'\n      - '.github/workflows/test_set_2.yml'\n\njobs:\n  shellcheck:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/shellcheck.yml\n\n  test_set_1:\n    needs: shellcheck\n    uses: ./.github/workflows/test_set_1.yml\n\n  test_set_2:\n    needs: shellcheck\n    uses: ./.github/workflows/test_set_2.yml\n"
  },
  {
    "path": ".github/workflows/shellcheck.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: shellcheck\n\non: workflow_call\n\njobs:\n  shellcheck:\n    runs-on: ubuntu-24.04\n    if: github.repository_owner == 'hwdsl2'\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Check\n        run: |\n          if [ ! -x /usr/bin/shellcheck ]; then\n            export DEBIAN_FRONTEND=noninteractive\n            sudo apt-get -yqq update\n            sudo apt-get -yqq install shellcheck\n          fi\n\n          cd \"$GITHUB_WORKSPACE\"\n          pwd\n          ls -ld vpnsetup.sh\n\n          export SHELLCHECK_OPTS=\"-e SC1090,SC1091\"\n          shellcheck --version\n          shopt -s globstar\n          ls -ld -- **/*.sh\n          shellcheck **/*.sh\n"
  },
  {
    "path": ".github/workflows/test_set_1.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: test_set_1\n\non: workflow_call\n\njobs:\n  test_set_1:\n    runs-on: ubuntu-22.04\n    if: github.repository_owner == 'hwdsl2'\n    strategy:\n      matrix:\n        os_version: [\"centos:10s\", \"centos:9s\", \"rockylinux:8\", \"almalinux:10\", \"almalinux:9\", \"almalinux:8\", \"oraclelinux:10\", \"oraclelinux:9\", \"oraclelinux:8\"]\n      fail-fast: false\n    env:\n      OS_VERSION: ${{ matrix.os_version }}\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Build\n        run: |\n          mkdir -p \"$GITHUB_WORKSPACE/testing/${OS_VERSION//:}\"\n          cd \"$GITHUB_WORKSPACE/testing/${OS_VERSION//:}\"\n\n          mkdir -p scripts/extras\n          ls -ld \"$GITHUB_WORKSPACE/vpnsetup.sh\"\n          cp -f \"$GITHUB_WORKSPACE\"/*.sh scripts/\n          cp -f \"$GITHUB_WORKSPACE\"/extras/*.sh scripts/extras/\n\n          cat > run.sh <<'EOF'\n          #!/bin/bash\n          set -eEx\n\n          log1=/var/log/secure\n          log2=/var/log/messages\n\n          trap 'catch $? $LINENO' ERR\n\n          catch() {\n            echo \"Error $1 occurred on line $2.\"\n            cat -n -- \"$0\" | tail -n+\"$(($2 - 3))\" | head -n7\n            exit 1\n          }\n\n          restart_ipsec() {\n            if [ -f /etc/oracle-release ]; then\n              sleep 3\n            fi\n            systemctl restart ipsec\n            if grep -qs -i stream /etc/redhat-release \\\n              && grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n              sleep 5\n              return 0\n            fi\n            echo \"Waiting for IPsec to restart.\"\n            count=0\n            while ! grep -q \"pluto\\[$(cat /var/run/pluto/pluto.pid)\\]: listening for IKE messages\" \"$log1\"; do\n              [ \"$count\" -ge \"30\" ] && { echo \"IPsec failed to start.\"; exit 1; }\n              count=$((count+1))\n              printf '%s' '.'\n              sleep 0.5\n            done\n            echo\n          }\n\n          restart_fail2ban() {\n            rm -f /var/log/fail2ban.log\n            systemctl restart fail2ban\n            echo \"Waiting for Fail2ban to restart.\"\n            count=0\n            while ! grep -qs -E \"Jail '(sshd?|ssh-iptables)' started\" /var/log/fail2ban.log; do\n              [ \"$count\" -ge \"30\" ] && { echo \"Fail2ban failed to start.\"; exit 1; }\n              count=$((count+1))\n              printf '%s' '.'\n              sleep 0.5\n            done\n            echo\n          }\n\n          cd /opt/src\n          if grep -qs -i rocky /etc/redhat-release; then\n            yum -y -q update\n          fi\n          yum -y -q install wget rsyslog\n          if grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            if grep -qs -i rocky /etc/redhat-release \\\n              || grep -qs -i alma /etc/redhat-release; then\n              yum -y -q install diffutils\n            fi\n          fi\n          if ! grep -qs -i stream /etc/redhat-release \\\n            || ! grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            systemctl start rsyslog\n          fi\n\n          cp -f /opt/src/scripts/vpnsetup.sh .\n          cp -f /opt/src/scripts/extras/vpnuninstall.sh ./vpnunst.sh\n          sed -i -e '/curl /a sed -i \"/swan_ver_latest=/s/^/#/\" \"$tmpdir/vpn.sh\"' \\\n            -e '/curl /a sed -i \\x27/status=0/a sed -i \"/swan_ver_latest=/s/^/#/\" /opt/src/ikev2.sh\\x27 \"$tmpdir/vpn.sh\"' \\\n            vpnsetup.sh\n\n          sh vpnsetup.sh\n\n          systemctl restart xl2tpd\n          restart_ipsec\n          if ! grep -qsE 'release (9|1[0-9])' /etc/oracle-release; then\n            if ! grep -qs -i stream /etc/redhat-release \\\n              || ! grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n              restart_fail2ban\n              cat /var/log/fail2ban.log\n            fi\n          fi\n\n          netstat -anpu | grep pluto\n          netstat -anpu | grep xl2tpd\n          if grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            nft list ruleset\n            nft list ruleset | grep -q '192\\.168\\.42\\.0/24'\n            nft list ruleset | grep -q '192\\.168\\.43\\.0/24'\n          else\n            iptables -nvL\n            iptables -nvL | grep -q 'ppp+'\n            iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n            iptables -nvL -t nat\n            iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n            iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          fi\n          if ! grep -qs -i stream /etc/redhat-release \\\n            || ! grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            grep pluto \"$log1\"\n            grep xl2tpd \"$log2\"\n          fi\n          ipsec status\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n\n          ls -l /usr/bin/ikev2.sh\n          ls -l /usr/bin/addvpnuser.sh\n          ls -l /usr/bin/delvpnuser.sh\n          ls -l /opt/src/ikev2.sh\n          ls -l /opt/src/addvpnuser.sh\n          ls -l /opt/src/delvpnuser.sh\n\n          bash vpnunst.sh <<ANSWERS\n          y\n          ANSWERS\n          rm -f /etc/ipsec.d/vpnclient*\n          if grep -qs -i stream /etc/redhat-release \\\n            || grep -qsE 'release (8|9|1[0-9])' /etc/oracle-release; then\n            mkdir /etc/xl2tpd\n          fi\n          if grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            if grep -qs -i rocky /etc/redhat-release \\\n              || grep -qs -i alma /etc/redhat-release; then\n              mkdir /etc/xl2tpd\n            fi\n          fi\n\n          cp -f /opt/src/scripts/vpnsetup_centos.sh ./vpnsetup.sh\n          sed -i -e '/swan_ver_latest=/s/^/#/' \\\n            -e '/status=0/a sed -i \"/swan_ver_latest=/s/^/#/\" /opt/src/ikev2.sh' \\\n            vpnsetup.sh\n\n          bash vpnsetup.sh\n\n          VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \\\n          VPN_USER='your_vpn_username' \\\n          VPN_PASSWORD='your_vpn_password' \\\n          VPN_DNS_SRV1='1.1.1.1' \\\n          VPN_DNS_SRV2='1.0.0.1' \\\n          bash vpnsetup.sh\n\n          systemctl restart xl2tpd\n          restart_ipsec\n\n          netstat -anpu | grep pluto\n          netstat -anpu | grep xl2tpd\n          if grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            nft list ruleset\n            nft list ruleset | grep -q '192\\.168\\.42\\.0/24'\n            nft list ruleset | grep -q '192\\.168\\.43\\.0/24'\n          else\n            iptables -nvL\n            iptables -nvL | grep -q 'ppp+'\n            iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n            iptables -nvL -t nat\n            iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n            iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          fi\n          ipsec status\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          grep -q \"your_ipsec_pre_shared_key\" /etc/ipsec.secrets\n          grep -q \"your_vpn_username\" /etc/ppp/chap-secrets\n          grep -q \"your_vpn_password\" /etc/ppp/chap-secrets\n          grep -q \"your_vpn_username\" /etc/ipsec.d/passwd\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.conf\n          grep -q 'ms-dns 1.1.1.1' /etc/ppp/options.xl2tpd\n          grep -q 'ms-dns 1.0.0.1' /etc/ppp/options.xl2tpd\n\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n\n          ls -l /usr/bin/ikev2.sh\n          ls -l /usr/bin/addvpnuser.sh\n          ls -l /usr/bin/delvpnuser.sh\n          ls -l /opt/src/ikev2.sh\n          ls -l /opt/src/addvpnuser.sh\n          ls -l /opt/src/delvpnuser.sh\n\n          rm -f /usr/bin/ikev2.sh /opt/src/ikev2.sh\n          rm -f /etc/ipsec.d/vpnclient*\n\n          cp -f /opt/src/scripts/extras/ikev2setup.sh ./ikev2.sh # hwdsl2\n          sed -i '/swan_ver_latest=/s/^/#/' ikev2.sh\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n\n          bash ikev2.sh <<ANSWERS\n\n\n\n\n\n\n\n          ANSWERS\n\n          grep -q 'modecfgdns=\"8.8.8.8 8.8.4.4\"' /etc/ipsec.d/ikev2.conf\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient.p12 | grep AES-256 && exit 1\n\n          restart_ipsec\n          if ! grep -qs -i stream /etc/redhat-release \\\n            || ! grep -qsE 'release (9|1[0-9])' /etc/redhat-release; then\n            grep pluto \"$log1\" | tail -n 20\n          fi\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh <<ANSWERS\n          1\n          invalidclient:\n          vpnclient\n          vpnclient2\n\n          ANSWERS\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          rm -f /etc/ipsec.d/vpnclient2*\n          bash ikev2.sh <<ANSWERS\n          2\n          nonexistclient\n          vpnclient2\n          ANSWERS\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh <<ANSWERS\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS | grep -i \"2 clients\"\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          4\n          nonexistclient\n          vpnclient2\n          y\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          4\n          vpnclient2\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          5\n          vpnclient2\n          y\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS | grep -i \"1 client\"\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          2\n          vpnclient2\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          100\n          7\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          6\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          6\n          y\n          ANSWERS\n\n          restart_ipsec\n          ls -ld /etc/ipsec.d/ikev2.conf && exit 1\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp && exit 1\n          certutil -L -d sql:/etc/ipsec.d\n\n          rm -f /etc/ipsec.d/vpnclient*\n\n          VPN_DNS_SRV1=invaliddns \\\n          bash ikev2.sh --auto 2>&1 | grep -i \"invalid\"\n\n          sed -i '/^include /d' /etc/ipsec.conf\n\n          VPN_CLIENT_NAME=vpnclient1 \\\n          VPN_DNS_NAME=vpn.example.com \\\n          VPN_DNS_SRV1=1.1.1.1 \\\n          VPN_DNS_SRV2=1.0.0.1 \\\n          bash ikev2.sh --auto\n\n          grep -q 'leftid=@vpn.example.com' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.d/ikev2.conf\n          ls -ld /etc/ipsec.d/vpnclient1.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient1.sswan\n          ls -ld /etc/ipsec.d/vpnclient1.p12\n          grep -q 'vpn.example.com' /etc/ipsec.d/vpnclient1.mobileconfig\n          grep -q 'vpn.example.com' /etc/ipsec.d/vpnclient1.sswan\n\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --addclient invalidclient: 2>&1 | grep -i \"invalid\"\n          bash ikev2.sh --addclient vpnclient1 2>&1 | grep -i \"already exists\"\n\n          bash ikev2.sh --addclient vpnclient2\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n\n          bash ikev2.sh --exportclient nonexistclient 2>&1 | grep -i \"does not exist\"\n\n          rm -f /etc/ipsec.d/vpnclient2*\n          bash ikev2.sh --exportclient vpnclient2\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n\n          bash ikev2.sh --addclient vpnclient2 --exportclient vpnclient2 2>&1 | grep -i \"invalid\"\n\n          bash ikev2.sh --listclients | grep \"vpnclient1 \\+valid\"\n          bash ikev2.sh --listclients | grep \"vpnclient2 \\+valid\"\n          bash ikev2.sh --listclients | grep \"2 clients\"\n\n          bash ikev2.sh --revokeclient nonexistclient 2>&1 | grep -i \"does not exist\"\n          bash ikev2.sh --revokeclient vpnclient2 <<ANSWERS\n          y\n          ANSWERS\n\n          bash ikev2.sh --listclients | grep \"vpnclient2 \\+revoked\"\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig && exit 1\n          ls -ld /etc/ipsec.d/vpnclient2.sswan && exit 1\n          ls -ld /etc/ipsec.d/vpnclient2.p12 && exit 1\n\n          bash ikev2.sh --revokeclient vpnclient2 2>&1 | grep -i \"already been revoked\"\n          bash ikev2.sh --exportclient vpnclient2 2>&1 | grep -i \"revoked\"\n\n          bash ikev2.sh --deleteclient nonexistclient 2>&1 | grep -i \"does not exist\"\n          bash ikev2.sh --deleteclient vpnclient1 <<ANSWERS\n          y\n          ANSWERS\n\n          bash ikev2.sh --listclients | grep \"1 client\"\n          ls -ld /etc/ipsec.d/vpnclient1.mobileconfig && exit 1\n          ls -ld /etc/ipsec.d/vpnclient1.sswan && exit 1\n          ls -ld /etc/ipsec.d/vpnclient1.p12 && exit 1\n\n          bash ikev2.sh -h 2>&1 | grep -i \"usage:\"\n          bash ikev2.sh --invalidoption 2>&1 | grep -i \"usage:\"\n\n          bash ikev2.sh --removeikev2 --exportclient vpnclient1 2>&1 | grep -i \"invalid\"\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          rm -f /etc/ipsec.d/vpnclient*\n\n          bash ikev2.sh <<ANSWERS\n          y\n          invalidfqdn\n          vpn.example.com\n\n\n          y\n          invaliddns\n          1.1.1.1\n          invaliddns\n          1.0.0.1\n          y\n\n          ANSWERS\n\n          grep -q 'leftid=@vpn.example.com' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          config_file=\"/etc/ipsec.d/.vpnconfig\"\n          p12_pw=$(grep -s '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" | tail -n 1 | cut -f2- -d= | sed -e \"s/^'//\" -e \"s/'$//\")\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --addclient vpnclient2\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --exportclient vpnclient2\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" && exit 1\n          restart_ipsec\n          bash ikev2.sh <<ANSWERS\n\n          invalidip\n          1.2.3.4\n          invalidclient:\n          vpnclient1\n          1000\n          12\n          y\n          1.1.1.1\n\n\n\n          ANSWERS\n\n          grep -q 'leftid=1.2.3.4' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=1.1.1.1' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          VPN_DNS_SRV1=1.1.1.1 \\\n          bash ikev2.sh --auto\n\n          grep -q 'modecfgdns=1.1.1.1' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          bash ikev2.sh --auto\n\n          grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" && exit 1\n          grep -q 'modecfgdns=\"8.8.8.8 8.8.4.4\"' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          cp -f /opt/src/scripts/extras/vpnupgrade.sh ./vpnup.sh\n          sed -i '/curl /a sed -i \"/swan_ver_latest=/s/^/#/\" \"$tmpdir/vpnup.sh\"' vpnup.sh\n\n          ver=5.2\n          sed -i \"s/^SWAN_VER=.*/SWAN_VER=$ver/\" vpnup.sh\n          bash vpnup.sh <<ANSWERS\n\n          ANSWERS\n          restart_ipsec\n          ipsec --version | grep \"$ver\"\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          cp -f /opt/src/scripts/extras/vpnupgrade_centos.sh ./vpnup.sh\n          sed -i '/swan_ver_latest=/s/^/#/' vpnup.sh\n\n          ver=5.3\n          bash vpnup.sh <<ANSWERS\n\n          ANSWERS\n          restart_ipsec\n          ipsec --version | grep \"$ver\"\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          ls -ld /etc/ipsec.d/ikev2.conf && exit 1\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp && exit 1\n          certutil -L -d sql:/etc/ipsec.d\n\n          exit 0\n          EOF\n\n          if [ \"$OS_VERSION\" = \"centos:9s\" ]; then\n            echo \"FROM quay.io/centos/centos:stream9\" > Dockerfile\n          elif [ \"$OS_VERSION\" = \"centos:10s\" ]; then\n            echo \"FROM quay.io/centos/centos:stream10\" > Dockerfile\n          else\n            echo \"FROM $OS_VERSION\" > Dockerfile\n          fi\n\n          cat >> Dockerfile <<'EOF'\n\n          ENV container=docker\n          WORKDIR /opt/src\n          EOF\n\n          if [ \"$OS_VERSION\" = \"centos:9s\" ] || [ \"$OS_VERSION\" = \"centos:10s\" ]; then\n            echo \"RUN yum -y -q install systemd\" >> Dockerfile\n          fi\n\n          cat >> Dockerfile <<'EOF'\n          RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ \"$i\" = \\\n          systemd-tmpfiles-setup.service ] || rm -f \"$i\"; done); \\\n          rm -f /lib/systemd/system/multi-user.target.wants/*; \\\n          rm -f /etc/systemd/system/*.wants/*; \\\n          rm -f /lib/systemd/system/local-fs.target.wants/*; \\\n          rm -f /lib/systemd/system/sockets.target.wants/*udev*; \\\n          rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \\\n          rm -f /lib/systemd/system/basic.target.wants/*; \\\n          rm -f /lib/systemd/system/anaconda.target.wants/*;\n\n          COPY scripts/ /opt/src/scripts/\n          COPY ./run.sh /opt/src/run.sh\n          RUN chmod 755 /opt/src/run.sh\n\n          VOLUME [ \"/sys/fs/cgroup\" ]\n\n          CMD [\"/sbin/init\"]\n          EOF\n          cat Dockerfile\n          cat run.sh\n          docker build -t \"${OS_VERSION//:}-test\" .\n\n      - name: Test\n        run: |\n          docker run -d --name \"${OS_VERSION//:}-test-1\" -v /sys/fs/cgroup:/sys/fs/cgroup:rw \\\n            --cgroupns=host --privileged \"${OS_VERSION//:}-test\"\n          sleep 5\n          docker exec \"${OS_VERSION//:}-test-1\" /opt/src/run.sh \"${OS_VERSION::6}\"\n\n      - name: Clear\n        if: always()\n        run: |\n          rm -rf \"$GITHUB_WORKSPACE/testing/${OS_VERSION//:}\"\n          docker rm -f \"${OS_VERSION//:}-test-1\" || true\n          docker rmi \"${OS_VERSION//:}-test\" || true\n"
  },
  {
    "path": ".github/workflows/test_set_2.yml",
    "content": "#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nname: test_set_2\n\non: workflow_call\n\njobs:\n  test_set_2:\n    runs-on: ubuntu-24.04\n    if: github.repository_owner == 'hwdsl2'\n    strategy:\n      matrix:\n        os_version: [\"ubuntu:24.04\", \"ubuntu:22.04\", \"debian:13\", \"debian:12\", \"debian:11\", \"alpine:3.23\", \"alpine:3.22\"]\n      fail-fast: false\n    container:\n      image: ${{ matrix.os_version }}\n      options: --cap-add=NET_ADMIN --device=/dev/ppp\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Test\n        run: |\n          set -ex\n\n          os_type=\"\"\n          [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n          [ -z \"$os_type\" ] && exit 1\n          if [ \"$os_type\" != \"alpine\" ]; then\n            os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n          fi\n\n          log1=/var/log/auth.log\n          if [ \"$os_type\" = \"alpine\" ]; then\n            log2=/var/log/messages\n          else\n            log2=/var/log/syslog\n          fi\n\n          restart_ipsec() {\n            if [ \"$os_type\" = \"alpine\" ] || [ \"$os_ver\" = \"trixiesid\" ] || [ \"$os_ver\" = 13 ]; then\n              ipsec whack --shutdown || true\n              ipsec pluto --config /etc/ipsec.conf\n            fi\n            echo \"Waiting for IPsec to restart.\"\n            count=0\n            while ! grep -q \"pluto\\[$(cat /var/run/pluto/pluto.pid)\\]: listening for IKE messages\" \"$log1\"; do\n              [ \"$count\" -ge \"30\" ] && { echo \"IPsec failed to start.\"; exit 1; }\n              count=$((count+1))\n              printf '%s' '.'\n              sleep 0.5\n            done\n            echo\n          }\n\n          restart_fail2ban() {\n            rm -f /var/log/fail2ban.log\n            service fail2ban restart\n            echo \"Waiting for Fail2ban to restart.\"\n            count=0\n            while ! grep -qs -E \"Jail '(sshd?|ssh-iptables)' started\" /var/log/fail2ban.log; do\n              [ \"$count\" -ge \"30\" ] && { echo \"Fail2ban failed to start.\"; exit 1; }\n              count=$((count+1))\n              printf '%s' '.'\n              sleep 0.5\n            done\n            echo\n          }\n\n          mkdir -p /opt/src\n          cd /opt/src\n          ls -ld \"$GITHUB_WORKSPACE/vpnsetup.sh\"\n          echo \"# hwdsl2\" > run.sh\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            apk add -U wget rsyslog sed bash\n            rsyslogd\n          else\n            export DEBIAN_FRONTEND=noninteractive\n            apt-get -yqq update\n            apt-get -yqq install wget rsyslog\n            if [ \"$os_ver\" = \"bookwormsid\" ] || [ \"$os_ver\" = \"trixiesid\" ] \\\n              || [ \"$os_ver\" = 13 ] || [ \"$os_ver\" = 12 ]; then\n              rsyslogd\n            else\n              service rsyslog start\n            fi\n          fi\n\n          cp -f \"$GITHUB_WORKSPACE\"/vpnsetup.sh .\n          cp -f \"$GITHUB_WORKSPACE\"/extras/vpnuninstall.sh ./vpnunst.sh\n          sed -i -e '/curl /a sed -i \"/swan_ver_latest=/s/^/#/\" \"$tmpdir/vpn.sh\"' \\\n            -e '/curl /a sed -i \\x27/status=0/a sed -i \"/swan_ver_latest=/s/^/#/\" /opt/src/ikev2.sh\\x27 \"$tmpdir/vpn.sh\"' \\\n            vpnsetup.sh\n\n          sh vpnsetup.sh\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            xl2tpd -c /etc/xl2tpd/xl2tpd.conf\n            restart_ipsec\n          else\n            restart_ipsec\n            restart_fail2ban\n            cat /var/log/fail2ban.log\n          fi\n\n          netstat -anpu | grep pluto\n          netstat -anpu | grep xl2tpd\n          iptables -nvL\n          iptables -nvL | grep -q 'ppp+'\n          iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n          iptables -nvL -t nat\n          iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n          iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          grep pluto \"$log1\"\n          grep xl2tpd \"$log2\"\n          ipsec status\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n\n          ls -l /usr/bin/ikev2.sh\n          ls -l /usr/bin/addvpnuser.sh\n          ls -l /usr/bin/delvpnuser.sh\n          ls -l /opt/src/ikev2.sh\n          ls -l /opt/src/addvpnuser.sh\n          ls -l /opt/src/delvpnuser.sh\n\n          bash vpnunst.sh <<ANSWERS\n          y\n          ANSWERS\n          rm -f /etc/ipsec.d/vpnclient*\n          if [ \"$os_type\" = \"alpine\" ]; then\n            killall pluto || true\n            killall xl2tpd || true\n          fi\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            cp -f \"$GITHUB_WORKSPACE\"/vpnsetup_alpine.sh ./vpnsetup.sh\n          else\n            cp -f \"$GITHUB_WORKSPACE\"/vpnsetup_ubuntu.sh ./vpnsetup.sh\n          fi\n          sed -i -e '/swan_ver_latest=/s/^/#/' \\\n            -e '/status=0/a sed -i \"/swan_ver_latest=/s/^/#/\" /opt/src/ikev2.sh' \\\n            vpnsetup.sh\n\n          bash vpnsetup.sh\n\n          VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \\\n          VPN_USER='your_vpn_username' \\\n          VPN_PASSWORD='your_vpn_password' \\\n          VPN_DNS_SRV1='1.1.1.1' \\\n          VPN_DNS_SRV2='1.0.0.1' \\\n          bash vpnsetup.sh\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            xl2tpd -c /etc/xl2tpd/xl2tpd.conf\n          fi\n          restart_ipsec\n\n          netstat -anpu | grep pluto\n          netstat -anpu | grep xl2tpd\n          iptables -nvL\n          iptables -nvL | grep -q 'ppp+'\n          iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n          iptables -nvL -t nat\n          iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n          iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          ipsec status\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          grep -q \"your_ipsec_pre_shared_key\" /etc/ipsec.secrets\n          grep -q \"your_vpn_username\" /etc/ppp/chap-secrets\n          grep -q \"your_vpn_password\" /etc/ppp/chap-secrets\n          grep -q \"your_vpn_username\" /etc/ipsec.d/passwd\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.conf\n          grep -q 'ms-dns 1.1.1.1' /etc/ppp/options.xl2tpd\n          grep -q 'ms-dns 1.0.0.1' /etc/ppp/options.xl2tpd\n\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n\n          ls -l /usr/bin/ikev2.sh\n          ls -l /usr/bin/addvpnuser.sh\n          ls -l /usr/bin/delvpnuser.sh\n          ls -l /opt/src/ikev2.sh\n          ls -l /opt/src/addvpnuser.sh\n          ls -l /opt/src/delvpnuser.sh\n\n          rm -f /usr/bin/ikev2.sh /opt/src/ikev2.sh\n          rm -f /etc/ipsec.d/vpnclient*\n\n          cp -f \"$GITHUB_WORKSPACE\"/extras/ikev2setup.sh ./ikev2.sh\n          sed -i '/swan_ver_latest=/s/^/#/' ikev2.sh\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n\n          bash ikev2.sh <<ANSWERS\n\n\n\n\n\n\n\n          ANSWERS\n\n          grep -q 'modecfgdns=\"8.8.8.8 8.8.4.4\"' /etc/ipsec.d/ikev2.conf\n          ls -ld /etc/ipsec.d/vpnclient.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient.sswan\n          ls -ld /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient.p12 | grep AES-256 && exit 1\n\n          restart_ipsec\n          grep pluto \"$log1\" | tail -n 20\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh <<ANSWERS\n          1\n          invalidclient:\n          vpnclient\n          vpnclient2\n\n          ANSWERS\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          rm -f /etc/ipsec.d/vpnclient2*\n          bash ikev2.sh <<ANSWERS\n          2\n          nonexistclient\n          vpnclient2\n          ANSWERS\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh <<ANSWERS\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS | grep -i \"2 clients\"\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          4\n          nonexistclient\n          vpnclient2\n          y\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          4\n          vpnclient2\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          5\n          vpnclient2\n          y\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS | grep -i \"1 client\"\n          3\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          2\n          vpnclient2\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          100\n          7\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS 2>&1 | grep -i \"abort\"\n          6\n\n          ANSWERS\n\n          bash ikev2.sh <<ANSWERS\n          6\n          y\n          ANSWERS\n\n          restart_ipsec\n          ls -ld /etc/ipsec.d/ikev2.conf && exit 1\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp && exit 1\n          certutil -L -d sql:/etc/ipsec.d\n\n          rm -f /etc/ipsec.d/vpnclient*\n\n          VPN_DNS_SRV1=invaliddns \\\n          bash ikev2.sh --auto 2>&1 | grep -i \"invalid\"\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            apk del uuidgen\n          else\n            apt-get -yqq remove uuid-runtime\n          fi\n          sed -i '/^include /d' /etc/ipsec.conf\n\n          VPN_CLIENT_NAME=vpnclient1 \\\n          VPN_DNS_NAME=vpn.example.com \\\n          VPN_DNS_SRV1=1.1.1.1 \\\n          VPN_DNS_SRV2=1.0.0.1 \\\n          bash ikev2.sh --auto\n\n          grep -q 'leftid=@vpn.example.com' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.d/ikev2.conf\n          ls -ld /etc/ipsec.d/vpnclient1.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient1.sswan\n          ls -ld /etc/ipsec.d/vpnclient1.p12\n          grep -q 'vpn.example.com' /etc/ipsec.d/vpnclient1.mobileconfig\n          grep -q 'vpn.example.com' /etc/ipsec.d/vpnclient1.sswan\n\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --addclient invalidclient: 2>&1 | grep -i \"invalid\"\n          bash ikev2.sh --addclient vpnclient1 2>&1 | grep -i \"already exists\"\n\n          bash ikev2.sh --addclient vpnclient2\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n\n          bash ikev2.sh --exportclient nonexistclient 2>&1 | grep -i \"does not exist\"\n\n          rm -f /etc/ipsec.d/vpnclient2*\n          bash ikev2.sh --exportclient vpnclient2\n\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n          ls -ld /etc/ipsec.d/vpnclient2.sswan\n          ls -ld /etc/ipsec.d/vpnclient2.p12\n\n          bash ikev2.sh --addclient vpnclient2 --exportclient vpnclient2 2>&1 | grep -i \"invalid\"\n\n          bash ikev2.sh --listclients | grep \"vpnclient1 \\+valid\"\n          bash ikev2.sh --listclients | grep \"vpnclient2 \\+valid\"\n          bash ikev2.sh --listclients | grep \"2 clients\"\n\n          bash ikev2.sh --revokeclient nonexistclient 2>&1 | grep -i \"does not exist\"\n          bash ikev2.sh --revokeclient vpnclient2 <<ANSWERS\n          y\n          ANSWERS\n\n          bash ikev2.sh --listclients | grep \"vpnclient2 \\+revoked\"\n          ls -ld /etc/ipsec.d/vpnclient2.mobileconfig && exit 1\n          ls -ld /etc/ipsec.d/vpnclient2.sswan && exit 1\n          ls -ld /etc/ipsec.d/vpnclient2.p12 && exit 1\n\n          bash ikev2.sh --revokeclient vpnclient2 2>&1 | grep -i \"already been revoked\"\n          bash ikev2.sh --exportclient vpnclient2 2>&1 | grep -i \"revoked\"\n\n          bash ikev2.sh --deleteclient nonexistclient 2>&1 | grep -i \"does not exist\"\n          bash ikev2.sh --deleteclient vpnclient1 <<ANSWERS\n          y\n          ANSWERS\n\n          bash ikev2.sh --listclients | grep \"1 client\"\n          ls -ld /etc/ipsec.d/vpnclient1.mobileconfig && exit 1\n          ls -ld /etc/ipsec.d/vpnclient1.sswan && exit 1\n          ls -ld /etc/ipsec.d/vpnclient1.p12 && exit 1\n\n          bash ikev2.sh -h 2>&1 | grep -i \"usage:\"\n          bash ikev2.sh --invalidoption 2>&1 | grep -i \"usage:\"\n\n          bash ikev2.sh --removeikev2 --exportclient vpnclient1 2>&1 | grep -i \"invalid\"\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          rm -f /etc/ipsec.d/vpnclient*\n\n          bash ikev2.sh <<ANSWERS\n          y\n          invalidfqdn\n          vpn.example.com\n\n\n          y\n          invaliddns\n          1.1.1.1\n          invaliddns\n          1.0.0.1\n          y\n\n          ANSWERS\n\n          grep -q 'leftid=@vpn.example.com' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          config_file=\"/etc/ipsec.d/.vpnconfig\"\n          p12_pw=$(grep -s '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" | tail -n 1 | cut -f2- -d= | sed -e \"s/^'//\" -e \"s/'$//\")\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --addclient vpnclient2\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --exportclient vpnclient2\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12\n          pk12util -W \"$p12_pw\" -l /etc/ipsec.d/vpnclient2.p12 | grep AES-256 && exit 1\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" && exit 1\n          restart_ipsec\n          bash ikev2.sh <<ANSWERS\n\n          invalidip\n          1.2.3.4\n          invalidclient:\n          vpnclient1\n          1000\n          12\n          y\n          1.1.1.1\n\n\n\n          ANSWERS\n\n          grep -q 'leftid=1.2.3.4' /etc/ipsec.d/ikev2.conf\n          grep -q 'modecfgdns=1.1.1.1' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          VPN_DNS_SRV1=1.1.1.1 \\\n          bash ikev2.sh --auto\n\n          grep -q 'modecfgdns=1.1.1.1' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          bash ikev2.sh --auto\n\n          grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$config_file\" && exit 1\n          grep -q 'modecfgdns=\"8.8.8.8 8.8.4.4\"' /etc/ipsec.d/ikev2.conf\n          restart_ipsec\n          ipsec status | grep -q ikev2-cp\n\n          cp -f \"$GITHUB_WORKSPACE\"/extras/vpnupgrade.sh ./vpnup.sh\n          sed -i '/curl /a sed -i \"/swan_ver_latest=/s/^/#/\" \"$tmpdir/vpnup.sh\"' vpnup.sh\n\n          ver=5.2\n          if [ \"$os_type\" = \"alpine\" ] || [ \"$os_ver\" = \"trixiesid\" ] || [ \"$os_ver\" = 13 ]; then\n            ipsec whack --shutdown || true\n          fi\n          sed -i \"s/^SWAN_VER=.*/SWAN_VER=$ver/\" vpnup.sh\n          bash vpnup.sh <<ANSWERS\n\n          ANSWERS\n          restart_ipsec\n          ipsec --version | grep \"$ver\"\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          if [ \"$os_type\" = \"alpine\" ]; then\n            cp -f \"$GITHUB_WORKSPACE\"/extras/vpnupgrade_alpine.sh ./vpnup.sh\n          else\n            cp -f \"$GITHUB_WORKSPACE\"/extras/vpnupgrade_ubuntu.sh ./vpnup.sh\n          fi\n          sed -i '/swan_ver_latest=/s/^/#/' vpnup.sh\n\n          ver=5.3\n          if [ \"$os_type\" = \"alpine\" ] || [ \"$os_ver\" = \"trixiesid\" ] || [ \"$os_ver\" = 13 ]; then\n            ipsec whack --shutdown || true\n          fi\n          bash vpnup.sh <<ANSWERS\n\n          ANSWERS\n          restart_ipsec\n          ipsec --version | grep \"$ver\"\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp\n\n          bash ikev2.sh --removeikev2 <<ANSWERS\n          y\n          ANSWERS\n\n          restart_ipsec\n          ls -ld /etc/ipsec.d/ikev2.conf && exit 1\n          ipsec status | grep -q l2tp-psk\n          ipsec status | grep -q xauth-psk\n          ipsec status | grep -q ikev2-cp && exit 1\n          certutil -L -d sql:/etc/ipsec.d\n"
  },
  {
    "path": "LICENSE.md",
    "content": "### Creative Commons Attribution-ShareAlike 3.0 Unported License\nLink to license summary: https://creativecommons.org/licenses/by-sa/3.0/\n\nCopyright (C) 2014-2026 [Lin Song](https://github.com/hwdsl2)   \nBased on [the work of Thomas Sarlandie](https://github.com/sarfata/voodooprivacy) (Copyright 2012)\n\nSee the [aws/](aws/) and [azure/](azure/) subfolders for their respective authors.\n\nThe following four files (only) are licensed under the GPL:   \n[clients.md](docs/clients.md), [clients-zh.md](docs/clients-zh.md), [clients-xauth.md](docs/clients-xauth.md) and [clients-xauth-zh.md](docs/clients-xauth-zh.md)\n\n<p>THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS\nOF THIS CREATIVE COMMONS PUBLIC LICENSE (\"CCPL\" OR\n\"LICENSE\"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER\nAPPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS\nAUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS\nPROHIBITED.</p>\n<p>BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU\nACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.\nTO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A\nCONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE\nIN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND\nCONDITIONS.</p>\n<p><strong>1. Definitions</strong></p>\n<ol type=\"a\">\n<li><strong>\"Adaptation\"</strong> means a work based upon\nthe Work, or upon the Work and other pre-existing works,\nsuch as a translation, adaptation, derivative work,\narrangement of music or other alterations of a literary\nor artistic work, or phonogram or performance and\nincludes cinematographic adaptations or any other form in\nwhich the Work may be recast, transformed, or adapted\nincluding in any form recognizably derived from the\noriginal, except that a work that constitutes a\nCollection will not be considered an Adaptation for the\npurpose of this License. For the avoidance of doubt,\nwhere the Work is a musical work, performance or\nphonogram, the synchronization of the Work in\ntimed-relation with a moving image (\"synching\") will be\nconsidered an Adaptation for the purpose of this\nLicense.</li>\n<li><strong>\"Collection\"</strong> means a collection of\nliterary or artistic works, such as encyclopedias and\nanthologies, or performances, phonograms or broadcasts,\nor other works or subject matter other than works listed\nin Section 1(f) below, which, by reason of the selection\nand arrangement of their contents, constitute\nintellectual creations, in which the Work is included in\nits entirety in unmodified form along with one or more\nother contributions, each constituting separate and\nindependent works in themselves, which together are\nassembled into a collective whole. A work that\nconstitutes a Collection will not be considered an\nAdaptation (as defined below) for the purposes of this\nLicense.</li>\n<li><strong>\"Creative Commons Compatible\nLicense\"</strong> means a license that is listed at\nhttps://creativecommons.org/compatiblelicenses that has\nbeen approved by Creative Commons as being essentially\nequivalent to this License, including, at a minimum,\nbecause that license: (i) contains terms that have the\nsame purpose, meaning and effect as the License Elements\nof this License; and, (ii) explicitly permits the\nrelicensing of adaptations of works made available under\nthat license under this License or a Creative Commons\njurisdiction license with the same License Elements as\nthis License.</li>\n<li><strong>\"Distribute\"</strong> means to make available\nto the public the original and copies of the Work or\nAdaptation, as appropriate, through sale or other\ntransfer of ownership.</li>\n<li><strong>\"License Elements\"</strong> means the\nfollowing high-level license attributes as selected by\nLicensor and indicated in the title of this License:\nAttribution, ShareAlike.</li>\n<li><strong>\"Licensor\"</strong> means the individual,\nindividuals, entity or entities that offer(s) the Work\nunder the terms of this License.</li>\n<li><strong>\"Original Author\"</strong> means, in the case\nof a literary or artistic work, the individual,\nindividuals, entity or entities who created the Work or\nif no individual or entity can be identified, the\npublisher; and in addition (i) in the case of a\nperformance the actors, singers, musicians, dancers, and\nother persons who act, sing, deliver, declaim, play in,\ninterpret or otherwise perform literary or artistic works\nor expressions of folklore; (ii) in the case of a\nphonogram the producer being the person or legal entity\nwho first fixes the sounds of a performance or other\nsounds; and, (iii) in the case of broadcasts, the\norganization that transmits the broadcast.</li>\n<li><strong>\"Work\"</strong> means the literary and/or\nartistic work offered under the terms of this License\nincluding without limitation any production in the\nliterary, scientific and artistic domain, whatever may be\nthe mode or form of its expression including digital\nform, such as a book, pamphlet and other writing; a\nlecture, address, sermon or other work of the same\nnature; a dramatic or dramatico-musical work; a\nchoreographic work or entertainment in dumb show; a\nmusical composition with or without words; a\ncinematographic work to which are assimilated works\nexpressed by a process analogous to cinematography; a\nwork of drawing, painting, architecture, sculpture,\nengraving or lithography; a photographic work to which\nare assimilated works expressed by a process analogous to\nphotography; a work of applied art; an illustration, map,\nplan, sketch or three-dimensional work relative to\ngeography, topography, architecture or science; a\nperformance; a broadcast; a phonogram; a compilation of\ndata to the extent it is protected as a copyrightable\nwork; or a work performed by a variety or circus\nperformer to the extent it is not otherwise considered a\nliterary or artistic work.</li>\n<li><strong>\"You\"</strong> means an individual or entity\nexercising rights under this License who has not\npreviously violated the terms of this License with\nrespect to the Work, or who has received express\npermission from the Licensor to exercise rights under\nthis License despite a previous violation.</li>\n<li><strong>\"Publicly Perform\"</strong> means to perform\npublic recitations of the Work and to communicate to the\npublic those public recitations, by any means or process,\nincluding by wire or wireless means or public digital\nperformances; to make available to the public Works in\nsuch a way that members of the public may access these\nWorks from a place and at a place individually chosen by\nthem; to perform the Work to the public by any means or\nprocess and the communication to the public of the\nperformances of the Work, including by public digital\nperformance; to broadcast and rebroadcast the Work by any\nmeans including signs, sounds or images.</li>\n<li><strong>\"Reproduce\"</strong> means to make copies of\nthe Work by any means including without limitation by\nsound or visual recordings and the right of fixation and\nreproducing fixations of the Work, including storage of a\nprotected performance or phonogram in digital form or\nother electronic medium.</li>\n</ol>\n<p><strong>2. Fair Dealing Rights.</strong> Nothing in this\nLicense is intended to reduce, limit, or restrict any uses\nfree from copyright or rights arising from limitations or\nexceptions that are provided for in connection with the\ncopyright protection under copyright law or other\napplicable laws.</p>\n<p><strong>3. License Grant.</strong> Subject to the terms\nand conditions of this License, Licensor hereby grants You\na worldwide, royalty-free, non-exclusive, perpetual (for\nthe duration of the applicable copyright) license to\nexercise the rights in the Work as stated below:</p>\n<ol type=\"a\">\n<li>to Reproduce the Work, to incorporate the Work into\none or more Collections, and to Reproduce the Work as\nincorporated in the Collections;</li>\n<li>to create and Reproduce Adaptations provided that any\nsuch Adaptation, including any translation in any medium,\ntakes reasonable steps to clearly label, demarcate or\notherwise identify that changes were made to the original\nWork. For example, a translation could be marked \"The\noriginal work was translated from English to Spanish,\" or\na modification could indicate \"The original work has been\nmodified.\";</li>\n<li>to Distribute and Publicly Perform the Work including\nas incorporated in Collections; and,</li>\n<li>to Distribute and Publicly Perform Adaptations.</li>\n<li>\n<p>For the avoidance of doubt:</p>\n<ol type=\"i\">\n<li><strong>Non-waivable Compulsory License\nSchemes</strong>. In those jurisdictions in which the\nright to collect royalties through any statutory or\ncompulsory licensing scheme cannot be waived, the\nLicensor reserves the exclusive right to collect such\nroyalties for any exercise by You of the rights\ngranted under this License;</li>\n<li><strong>Waivable Compulsory License\nSchemes</strong>. In those jurisdictions in which the\nright to collect royalties through any statutory or\ncompulsory licensing scheme can be waived, the\nLicensor waives the exclusive right to collect such\nroyalties for any exercise by You of the rights\ngranted under this License; and,</li>\n<li><strong>Voluntary License Schemes</strong>. The\nLicensor waives the right to collect royalties,\nwhether individually or, in the event that the\nLicensor is a member of a collecting society that\nadministers voluntary licensing schemes, via that\nsociety, from any exercise by You of the rights\ngranted under this License.</li>\n</ol>\n</li>\n</ol>\n<p>The above rights may be exercised in all media and\nformats whether now known or hereafter devised. The above\nrights include the right to make such modifications as are\ntechnically necessary to exercise the rights in other media\nand formats. Subject to Section 8(f), all rights not\nexpressly granted by Licensor are hereby reserved.</p>\n<p><strong>4. Restrictions.</strong> The license granted in\nSection 3 above is expressly made subject to and limited by\nthe following restrictions:</p>\n<ol type=\"a\">\n<li>You may Distribute or Publicly Perform the Work only\nunder the terms of this License. You must include a copy\nof, or the Uniform Resource Identifier (URI) for, this\nLicense with every copy of the Work You Distribute or\nPublicly Perform. You may not offer or impose any terms\non the Work that restrict the terms of this License or\nthe ability of the recipient of the Work to exercise the\nrights granted to that recipient under the terms of the\nLicense. You may not sublicense the Work. You must keep\nintact all notices that refer to this License and to the\ndisclaimer of warranties with every copy of the Work You\nDistribute or Publicly Perform. When You Distribute or\nPublicly Perform the Work, You may not impose any\neffective technological measures on the Work that\nrestrict the ability of a recipient of the Work from You\nto exercise the rights granted to that recipient under\nthe terms of the License. This Section 4(a) applies to\nthe Work as incorporated in a Collection, but this does\nnot require the Collection apart from the Work itself to\nbe made subject to the terms of this License. If You\ncreate a Collection, upon notice from any Licensor You\nmust, to the extent practicable, remove from the\nCollection any credit as required by Section 4(c), as\nrequested. If You create an Adaptation, upon notice from\nany Licensor You must, to the extent practicable, remove\nfrom the Adaptation any credit as required by Section\n4(c), as requested.</li>\n<li>You may Distribute or Publicly Perform an Adaptation\nonly under the terms of: (i) this License; (ii) a later\nversion of this License with the same License Elements as\nthis License; (iii) a Creative Commons jurisdiction\nlicense (either this or a later license version) that\ncontains the same License Elements as this License (e.g.,\nAttribution-ShareAlike 3.0 US)); (iv) a Creative Commons\nCompatible License. If you license the Adaptation under\none of the licenses mentioned in (iv), you must comply\nwith the terms of that license. If you license the\nAdaptation under the terms of any of the licenses\nmentioned in (i), (ii) or (iii) (the \"Applicable\nLicense\"), you must comply with the terms of the\nApplicable License generally and the following\nprovisions: (I) You must include a copy of, or the URI\nfor, the Applicable License with every copy of each\nAdaptation You Distribute or Publicly Perform; (II) You\nmay not offer or impose any terms on the Adaptation that\nrestrict the terms of the Applicable License or the\nability of the recipient of the Adaptation to exercise\nthe rights granted to that recipient under the terms of\nthe Applicable License; (III) You must keep intact all\nnotices that refer to the Applicable License and to the\ndisclaimer of warranties with every copy of the Work as\nincluded in the Adaptation You Distribute or Publicly\nPerform; (IV) when You Distribute or Publicly Perform the\nAdaptation, You may not impose any effective\ntechnological measures on the Adaptation that restrict\nthe ability of a recipient of the Adaptation from You to\nexercise the rights granted to that recipient under the\nterms of the Applicable License. This Section 4(b)\napplies to the Adaptation as incorporated in a\nCollection, but this does not require the Collection\napart from the Adaptation itself to be made subject to\nthe terms of the Applicable License.</li>\n<li>If You Distribute, or Publicly Perform the Work or\nany Adaptations or Collections, You must, unless a\nrequest has been made pursuant to Section 4(a), keep\nintact all copyright notices for the Work and provide,\nreasonable to the medium or means You are utilizing: (i)\nthe name of the Original Author (or pseudonym, if\napplicable) if supplied, and/or if the Original Author\nand/or Licensor designate another party or parties (e.g.,\na sponsor institute, publishing entity, journal) for\nattribution (\"Attribution Parties\") in Licensor's\ncopyright notice, terms of service or by other reasonable\nmeans, the name of such party or parties; (ii) the title\nof the Work if supplied; (iii) to the extent reasonably\npracticable, the URI, if any, that Licensor specifies to\nbe associated with the Work, unless such URI does not\nrefer to the copyright notice or licensing information\nfor the Work; and (iv) , consistent with Ssection 3(b),\nin the case of an Adaptation, a credit identifying the\nuse of the Work in the Adaptation (e.g., \"French\ntranslation of the Work by Original Author,\" or\n\"Screenplay based on original Work by Original Author\").\nThe credit required by this Section 4(c) may be\nimplemented in any reasonable manner; provided, however,\nthat in the case of a Adaptation or Collection, at a\nminimum such credit will appear, if a credit for all\ncontributing authors of the Adaptation or Collection\nappears, then as part of these credits and in a manner at\nleast as prominent as the credits for the other\ncontributing authors. For the avoidance of doubt, You may\nonly use the credit required by this Section for the\npurpose of attribution in the manner set out above and,\nby exercising Your rights under this License, You may not\nimplicitly or explicitly assert or imply any connection\nwith, sponsorship or endorsement by the Original Author,\nLicensor and/or Attribution Parties, as appropriate, of\nYou or Your use of the Work, without the separate,\nexpress prior written permission of the Original Author,\nLicensor and/or Attribution Parties.</li>\n<li>Except as otherwise agreed in writing by the Licensor\nor as may be otherwise permitted by applicable law, if\nYou Reproduce, Distribute or Publicly Perform the Work\neither by itself or as part of any Adaptations or\nCollections, You must not distort, mutilate, modify or\ntake other derogatory action in relation to the Work\nwhich would be prejudicial to the Original Author's honor\nor reputation. Licensor agrees that in those\njurisdictions (e.g. Japan), in which any exercise of the\nright granted in Section 3(b) of this License (the right\nto make Adaptations) would be deemed to be a distortion,\nmutilation, modification or other derogatory action\nprejudicial to the Original Author's honor and\nreputation, the Licensor will waive or not assert, as\nappropriate, this Section, to the fullest extent\npermitted by the applicable national law, to enable You\nto reasonably exercise Your right under Section 3(b) of\nthis License (right to make Adaptations) but not\notherwise.</li>\n</ol>\n<p><strong>5. Representations, Warranties and\nDisclaimer</strong></p>\n<p>UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN\nWRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO\nREPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE\nWORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING,\nWITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,\nFITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE\nABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE\nPRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE.\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED\nWARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.</p>\n<p><strong>6. Limitation on Liability.</strong> EXCEPT TO\nTHE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL\nLICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY\nSPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY\nDAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,\nEVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.</p>\n<p><strong>7. Termination</strong></p>\n<ol type=\"a\">\n<li>This License and the rights granted hereunder will\nterminate automatically upon any breach by You of the\nterms of this License. Individuals or entities who have\nreceived Adaptations or Collections from You under this\nLicense, however, will not have their licenses terminated\nprovided such individuals or entities remain in full\ncompliance with those licenses. Sections 1, 2, 5, 6, 7,\nand 8 will survive any termination of this License.</li>\n<li>Subject to the above terms and conditions, the\nlicense granted here is perpetual (for the duration of\nthe applicable copyright in the Work). Notwithstanding\nthe above, Licensor reserves the right to release the\nWork under different license terms or to stop\ndistributing the Work at any time; provided, however that\nany such election will not serve to withdraw this License\n(or any other license that has been, or is required to\nbe, granted under the terms of this License), and this\nLicense will continue in full force and effect unless\nterminated as stated above.</li>\n</ol>\n<p><strong>8. Miscellaneous</strong></p>\n<ol type=\"a\">\n<li>Each time You Distribute or Publicly Perform the Work\nor a Collection, the Licensor offers to the recipient a\nlicense to the Work on the same terms and conditions as\nthe license granted to You under this License.</li>\n<li>Each time You Distribute or Publicly Perform an\nAdaptation, Licensor offers to the recipient a license to\nthe original Work on the same terms and conditions as the\nlicense granted to You under this License.</li>\n<li>If any provision of this License is invalid or\nunenforceable under applicable law, it shall not affect\nthe validity or enforceability of the remainder of the\nterms of this License, and without further action by the\nparties to this agreement, such provision shall be\nreformed to the minimum extent necessary to make such\nprovision valid and enforceable.</li>\n<li>No term or provision of this License shall be deemed\nwaived and no breach consented to unless such waiver or\nconsent shall be in writing and signed by the party to be\ncharged with such waiver or consent.</li>\n<li>This License constitutes the entire agreement between\nthe parties with respect to the Work licensed here. There\nare no understandings, agreements or representations with\nrespect to the Work not specified here. Licensor shall\nnot be bound by any additional provisions that may appear\nin any communication from You. This License may not be\nmodified without the mutual written agreement of the\nLicensor and You.</li>\n<li>The rights granted under, and the subject matter\nreferenced, in this License were drafted utilizing the\nterminology of the Berne Convention for the Protection of\nLiterary and Artistic Works (as amended on September 28,\n1979), the Rome Convention of 1961, the WIPO Copyright\nTreaty of 1996, the WIPO Performances and Phonograms\nTreaty of 1996 and the Universal Copyright Convention (as\nrevised on July 24, 1971). These rights and subject\nmatter take effect in the relevant jurisdiction in which\nthe License terms are sought to be enforced according to\nthe corresponding provisions of the implementation of\nthose treaty provisions in the applicable national law.\nIf the standard suite of rights granted under applicable\ncopyright law includes additional rights not granted\nunder this License, such additional rights are deemed to\nbe included in the License; this License is not intended\nto restrict the license of any rights under applicable\nlaw.</li>\n</ol>\n"
  },
  {
    "path": "README-ja.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [日本語](README-ja.md) | [Русский](README-ru.md)\n\n# IPsec VPN サーバー自動セットアップスクリプト\n\n[![Build Status](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server)\n\n数分で自分のIPsec VPNサーバーをセットアップし、IPsec/L2TP、Cisco IPsec、IKEv2をサポートします。\n\nIPsec VPNはネットワークトラフィックを暗号化し、インターネット経由でデータが送信される際に、VPNサーバーとあなたの間の誰もがデータを盗聴できないようにします。これは、コーヒーショップ、空港、ホテルの部屋などの安全でないネットワークを使用する際に特に有用です。\n\nIPsecサーバーとして[Libreswan](https://libreswan.org/)を使用し、L2TPプロバイダーとして[xl2tpd](https://github.com/xelerance/xl2tpd)を使用します。\n\n**[&raquo; :book: 本：Privacy Tools in the Age of AI](docs/vpn-book-ja.md) &nbsp;[VPNサーバーの構築方法](docs/vpn-book-ja.md)**\n\n## クイックスタート\n\nまず、Ubuntu、Debian、またはCentOSをインストールしたLinuxサーバー\\*を準備します。\n\nこのワンライナーを使用してIPsec VPNサーバーをセットアップします：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\nVPNログイン情報はランダムに生成され、完了時に表示されます。\n\n**オプション:** 同じサーバーに[WireGuard](https://github.com/hwdsl2/wireguard-install)および/または[OpenVPN](https://github.com/hwdsl2/openvpn-install)をインストールします。\n\n<details>\n<summary>\nスクリプトの動作を確認する（ターミナル記録）。\n</summary>\n\n**注:** この記録はデモ目的のみです。この記録のVPN資格情報は**無効**です。\n\n<p align=\"center\"><img src=\"docs/images/script-demo.svg\"></p>\n</details>\n<details>\n<summary>\nダウンロードできない場合はこちらをクリックしてください。\n</summary>\n\n`curl`を使用してダウンロードすることもできます：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net -o vpn.sh && sudo sh vpn.sh\n```\n\n代替セットアップURL：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nダウンロードできない場合は、[vpnsetup.sh](vpnsetup.sh)を開き、右側の`Raw`ボタンをクリックします。`Ctrl/Cmd+A`を押してすべて選択し、`Ctrl/Cmd+C`を押してコピーし、お気に入りのエディタに貼り付けます。\n</details>\n\n事前構築された[Dockerイメージ](https://github.com/hwdsl2/docker-ipsec-vpn-server)も利用可能です。他のオプションやクライアントのセットアップについては、以下のセクションを参照してください。\n\n\\* クラウドサーバー、仮想プライベートサーバー（VPS）、または専用サーバー。\n\n## 機能\n\n- 完全自動化されたIPsec VPNサーバーのセットアップ、ユーザー入力不要\n- 強力で高速な暗号（例：AES-GCM）をサポートするIKEv2をサポート\n- iOS、macOS、Androidデバイスを自動設定するVPNプロファイルを生成\n- Windows、macOS、iOS、Android、Chrome OS、LinuxをVPNクライアントとしてサポート\n- VPNユーザーと証明書を管理するためのヘルパースクリプトを含む\n\n## 要件\n\n以下のいずれかのインストールを備えたクラウドサーバー、仮想プライベートサーバー（VPS）、または専用サーバー：\n\n- Ubuntu 24.04または22.04\n- Debian 13、12、または11\n- CentOS Stream 10または9\n- Rocky LinuxまたはAlmaLinux\n- Oracle Linux\n- Amazon Linux 2\n\n<details>\n<summary>\n他のサポートされているLinuxディストリビューション。\n</summary>\n\n- Raspberry Pi OS（Raspbian）\n- Kali Linux\n- Alpine Linux\n- Red Hat Enterprise Linux（RHEL）\n</details>\n\nこれは、[DigitalOcean](https://blog.ls20.com/digitalocean)、[Vultr](https://blog.ls20.com/vultr)、[Linode](https://blog.ls20.com/linode)、[OVH](https://www.ovhcloud.com/en/vps/)、および[Microsoft Azure](https://azure.microsoft.com)などのパブリッククラウドのLinux VMも含まれます。パブリッククラウドユーザーは、[ユーザーデータ](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#vpnsetup)を使用してデプロイすることもできます。\n\nクイックデプロイ：\n\n[![Deploy to Linode](docs/images/linode-deploy-button.png)](https://cloud.linode.com/stackscripts/37239) &nbsp;[![Deploy to AWS](docs/images/aws-deploy-button.png)](aws/README.md) &nbsp;[![Deploy to Azure](docs/images/azure-deploy-button.png)](azure/README.md)\n\n[**&raquo; 自分のVPNを運用したいが、そのためのサーバーがない**](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#gettingavps)\n\n外部ファイアウォールを持つサーバー（例：[EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)）の場合、VPNのUDPポート500および4500を開きます。\n\n事前構築された[Dockerイメージ](https://github.com/hwdsl2/docker-ipsec-vpn-server)も利用可能です。上級ユーザーは[Raspberry Pi](https://www.raspberrypi.com)にインストールできます。[[1]](https://elasticbyte.net/posts/setting-up-a-native-cisco-ipsec-vpn-server-using-a-raspberry-pi/) [[2]](https://www.stewright.me/2018/07/create-a-raspberry-pi-vpn-server-using-l2tpipsec/)\n\n:warning: これらのスクリプトをPCやMacで実行しないでください！これらはサーバーでのみ使用する必要があります！\n\n## インストール\n\nまず、サーバーを更新します：`sudo apt-get update && sudo apt-get dist-upgrade`（Ubuntu/Debian）または`sudo yum update`を実行し、再起動します。これはオプションですが、推奨されます。\n\nVPNをインストールするには、次のオプションのいずれかを選択してください：\n\n**オプション1:** スクリプトにランダムなVPN資格情報を生成させる（完了時に表示されます）。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n**オプション2:** スクリプトを編集し、自分のVPN資格情報を提供する。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nnano -w vpn.sh\n[自分の値に置き換える：YOUR_IPSEC_PSK、YOUR_USERNAME、およびYOUR_PASSWORD]\nsudo sh vpn.sh\n```\n\n**注:** 安全なIPsec PSKは少なくとも20のランダムな文字で構成されるべきです。\n\n**オプション3:** 環境変数として自分のVPN資格情報を定義する。\n\n```bash\n# すべての値は 'シングルクォート' で囲む必要があります\n# これらの特殊文字を値に使用しないでください： \\ \" '\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \\\nVPN_USER='your_vpn_username' \\\nVPN_PASSWORD='your_vpn_password' \\\nsh vpn.sh\n```\n\n同じサーバーに[WireGuard](https://github.com/hwdsl2/wireguard-install)および/または[OpenVPN](https://github.com/hwdsl2/openvpn-install)をインストールすることもできます。サーバーがCentOS Stream、Rocky Linux、またはAlmaLinuxを実行している場合、最初にOpenVPN/WireGuardをインストールし、その後IPsec VPNをインストールします。\n\n<details>\n<summary>\nダウンロードできない場合はこちらをクリックしてください。\n</summary>\n\n`curl`を使用してダウンロードすることもできます。例えば：\n\n```bash\ncurl -fL https://get.vpnsetup.net -o vpn.sh\nsudo sh vpn.sh\n```\n\n代替セットアップURL：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nダウンロードできない場合は、[vpnsetup.sh](vpnsetup.sh)を開き、右側の`Raw`ボタンをクリックします。`Ctrl/Cmd+A`を押してすべて選択し、`Ctrl/Cmd+C`を押してコピーし、お気に入りのエディタに貼り付けます。\n</details>\n<details>\n<summary>\n古いLibreswanバージョン4をインストールしたい。\n</summary>\n\n一般的には、最新の[Libreswan](https://libreswan.org/)バージョン5を使用することをお勧めします。これはこのプロジェクトのデフォルトバージョンです。ただし、古いLibreswanバージョン4をインストールしたい場合：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_SWAN_VER=4.15 sh vpn.sh\n```\n\n**注:** Libreswanバージョン5がすでにインストールされている場合、最初に[VPNをアンインストール](docs/uninstall.md)してからLibreswanバージョン4をインストールする必要があるかもしれません。あるいは、[アップデートスクリプト](#libreswanのアップグレード)をダウンロードし、`SWAN_VER=4.15`を指定して編集し、スクリプトを実行します。\n</details>\n\n## VPNオプションのカスタマイズ\n\n### 代替DNSサーバーの使用\n\nデフォルトでは、VPNがアクティブなときにクライアントは[Google Public DNS](https://developers.google.com/speed/public-dns/)を使用するように設定されています。VPNをインストールする際に、すべてのVPNモードに対してカスタムDNSサーバーを指定することができます。例：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\n`VPN_DNS_SRV1`を使用してプライマリDNSサーバーを指定し、`VPN_DNS_SRV2`を使用してセカンダリDNSサーバーを指定します（オプション）。\n\n以下は、参考のためのいくつかの人気のあるパブリックDNSプロバイダーのリストです。\n\n| プロバイダー | プライマリDNS | セカンダリDNS | 注記 |\n| -------- | ----------- | ------------- | ----- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | このプロジェクトのデフォルト |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | 参照：[Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | 悪意のあるドメインをブロック |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | フィッシングドメインをブロック、設定可能。 |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | [ドメインフィルター](https://cleanbrowsing.org/filters/)利用可能 |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | さまざま | さまざま | 広告ブロック、無料プラン利用可能。[詳細はこちら](https://nextdns.io/?from=bg25bwmp)。 |\n| [Control D](https://controld.com/free-dns) | さまざま | さまざま | 広告ブロック、設定可能。[詳細はこちら](https://controld.com/free-dns)。 |\n\nVPNセットアップ後にDNSサーバーを変更する必要がある場合は、[高度な使用法](docs/advanced-usage.md)を参照してください。\n\n**注:** サーバーにIKEv2がすでに設定されている場合、上記の変数はIKEv2モードには影響しません。その場合、DNSサーバーなどのIKEv2オプションをカスタマイズするには、まず[IKEv2を削除](docs/ikev2-howto.md#remove-ikev2)し、`sudo ikev2.sh`を使用して再設定します。\n\n### IKEv2オプションのカスタマイズ\n\nVPNをインストールする際に、上級ユーザーはオプションでIKEv2オプションをカスタマイズできます。\n\n<details open>\n<summary>\nオプション1: VPNセットアップ時にIKEv2をスキップし、カスタムオプションを使用してIKEv2を設定します。\n</summary>\n\nVPNをインストールする際に、IKEv2をスキップし、IPsec/L2TPおよびIPsec/XAuth（\"Cisco IPsec\"）モードのみをインストールできます：\n\n```bash\nsudo VPN_SKIP_IKEV2=yes sh vpn.sh\n```\n\n（オプション）VPNクライアントにカスタムDNSサーバーを指定する場合は、`VPN_DNS_SRV1`およびオプションで`VPN_DNS_SRV2`を定義します。詳細については、[代替DNSサーバーの使用](#代替dnsサーバーの使用)を参照してください。\n\nその後、IKEv2ヘルパースクリプトを実行して、カスタムオプションを使用して対話的にIKEv2を設定します：\n\n```bash\nsudo ikev2.sh\n```\n\n次のオプションをカスタマイズできます：VPNサーバーのDNS名、最初のクライアントの名前と有効期間、VPNクライアントのDNSサーバー、およびクライアント構成ファイルをパスワードで保護するかどうか。\n\n**注:** サーバーにIKEv2がすでに設定されている場合、`VPN_SKIP_IKEV2`変数は影響しません。その場合、IKEv2オプションをカスタマイズするには、まず[IKEv2を削除](docs/ikev2-howto.md#remove-ikev2)し、`sudo ikev2.sh`を使用して再設定します。\n</details>\n<details>\n<summary>\nオプション2: 環境変数を使用してIKEv2オプションをカスタマイズします。\n</summary>\n\nVPNをインストールする際に、オプションでIKEv2サーバーアドレスのDNS名を指定できます。DNS名は完全修飾ドメイン名（FQDN）である必要があります。例：\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' sh vpn.sh\n```\n\n同様に、最初のIKEv2クライアントの名前を指定できます。指定しない場合、デフォルトは`vpnclient`です。\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' sh vpn.sh\n```\n\nデフォルトでは、VPNがアクティブなときにクライアントは[Google Public DNS](https://developers.google.com/speed/public-dns/)を使用するように設定されています。すべてのVPNモードに対してカスタムDNSサーバーを指定できます。例：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\nデフォルトでは、IKEv2クライアント構成のインポート時にパスワードは必要ありません。ランダムなパスワードを使用してクライアント構成ファイルを保護することを選択できます。\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes sh vpn.sh\n```\n</details>\n<details>\n<summary>\n参考のために：IKEv1およびIKEv2パラメータのリスト。\n</summary>\n\n| IKEv1パラメータ\\* | デフォルト値 | カスタマイズ（環境変数）\\*\\* |\n| ------------ | ---- | ----------------- |\n| サーバーアドレス（DNS名）| - | いいえ、ただしDNS名を使用して接続できます |\n| サーバーアドレス（パブリックIP）| 自動検出 | VPN_PUBLIC_IP |\n| IPsec事前共有キー | 自動生成 | VPN_IPSEC_PSK |\n| VPNユーザー名 | vpnuser | VPN_USER |\n| VPNパスワード | 自動生成 | VPN_PASSWORD |\n| クライアントのDNSサーバー | Google Public DNS | VPN_DNS_SRV1、VPN_DNS_SRV2 |\n| IKEv2セットアップをスキップ | いいえ | VPN_SKIP_IKEV2=yes |\n\n\\* これらのIKEv1パラメータは、IPsec/L2TPおよびIPsec/XAuth（\"Cisco IPsec\"）モード用です。   \n\\*\\* vpn（setup）.shを実行する際に、これらを環境変数として定義します。\n\n| IKEv2パラメータ\\* | デフォルト値 | カスタマイズ（環境変数）\\*\\* | カスタマイズ（対話型）\\*\\*\\* |\n| ----------- | ---- | ------------------ | ----------------- |\n| サーバーアドレス（DNS名）| - | VPN_DNS_NAME | ✅ |\n| サーバーアドレス（パブリックIP）| 自動検出 | VPN_PUBLIC_IP | ✅ |\n| 最初のクライアントの名前 | vpnclient | VPN_CLIENT_NAME | ✅ |\n| クライアントのDNSサーバー | Google Public DNS | VPN_DNS_SRV1、VPN_DNS_SRV2 | ✅ |\n| クライアント構成ファイルを保護する | いいえ | VPN_PROTECT_CONFIG=yes | ✅ |\n| MOBIKEの有効/無効 | サポートされている場合は有効 | ❌ | ✅ |\n| クライアント証明書の有効期間 | 10年（120ヶ月）| VPN_CLIENT_VALIDITY\\*\\*\\*\\* | ✅ |\n| CAおよびサーバー証明書の有効期間 | 10年（120ヶ月）| ❌ | ❌ |\n| CA証明書名 | IKEv2 VPN CA | ❌ | ❌ |\n| 証明書キーサイズ | 3072ビット | ❌ | ❌ |\n\n\\* これらのIKEv2パラメータは、IKEv2モード用です。   \n\\*\\* vpn（setup）.shを実行する際、または自動モードでIKEv2を設定する際に、これらを環境変数として定義します（`sudo ikev2.sh --auto`）。   \n\\*\\*\\* 対話型IKEv2セットアップ中にカスタマイズできます（`sudo ikev2.sh`）。上記のオプション1を参照してください。   \n\\*\\*\\*\\* `VPN_CLIENT_VALIDITY`を使用して、クライアント証明書の有効期間を月単位で指定します。1から120の間の整数である必要があります。\n\nこれらのパラメータに加えて、上級ユーザーはVPNセットアップ中に[VPNサブネットをカスタマイズ](docs/advanced-usage.md#customize-vpn-subnets)することもできます。\n</details>\n\n## 次のステップ\n\n*他の言語で読む：[English](README.md#next-steps)、[简体中文](README-zh.md#下一步)、[繁體中文](README-zh-Hant.md#下一步)、[日本語](README-ja.md#次のステップ)、[Русский](README-ru.md#следующие-шаги)。*\n\nコンピュータやデバイスをVPNに接続します。詳細は以下のリンク（英語）をご覧ください。\n\n**[IKEv2 VPNクライアントの設定（推奨）](docs/ikev2-howto.md)**\n\n**[IPsec/L2TP VPNクライアントの設定](docs/clients.md)**\n\n**[IPsec/XAuth（\"Cisco IPsec\"）VPNクライアントの設定](docs/clients-xauth.md)**\n\n**:book: [VPN本](docs/vpn-book.md)を読んで[追加コンテンツ](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)にアクセスしてください。**\n\n自分のVPNを楽しんでください！ :sparkles::tada::rocket::sparkles:\n\n## 重要な注意事項\n\n**Windowsユーザー**：IPsec/L2TPモードの場合、VPNサーバーまたはクライアントがNAT（例：家庭用ルーター）の背後にある場合、[一度だけレジストリを変更](docs/clients.md#windows-error-809)する必要があります。\n\n同じVPNアカウントを複数のデバイスで使用できます。ただし、IPsec/L2TPの制限により、同じNAT（例：家庭用ルーター）の背後から複数のデバイスを接続する場合は、[IKEv2](docs/ikev2-howto.md)または[IPsec/XAuth](docs/clients-xauth.md)モードを使用する必要があります。VPNユーザーアカウントを表示または更新するには、[VPNユーザーの管理](docs/manage-users.md)を参照してください。\n\n外部ファイアウォールを持つサーバー（例：[EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)）の場合、VPNのUDPポート500および4500を開きます。Aliyunユーザーは、[＃433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433)を参照してください。\n\nクライアントは、VPNがアクティブなときに[Google Public DNS](https://developers.google.com/speed/public-dns/)を使用するように設定されています。別のDNSプロバイダーを好む場合は、[高度な使用法](docs/advanced-usage.md)を参照してください。\n\nカーネルサポートを使用すると、IPsec/L2TPのパフォーマンスが向上する可能性があります。これは[すべてのサポートされているOS](#要件)で利用可能です。Ubuntuユーザーは`linux-modules-extra-$(uname -r)`パッケージをインストールし、`service xl2tpd restart`を実行する必要があります。\n\nスクリプトは、変更を加える前に既存の構成ファイルをバックアップし、`.old-date-time`サフィックスを付けます。\n\n## Libreswanのアップグレード\n\nこのワンライナーを使用して、VPNサーバー上の[Libreswan](https://libreswan.org)（[変更ログ](https://github.com/libreswan/libreswan/blob/main/CHANGES) | [アナウンス](https://lists.libreswan.org)）を更新します。\n\n```bash\nwget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n```\n\n<details>\n<summary>\nダウンロードできない場合はこちらをクリックしてください。\n</summary>\n\n`curl`を使用してダウンロードすることもできます：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/upg -o vpnup.sh && sudo sh vpnup.sh\n```\n\n代替アップデートURL：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnupgrade.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnupgrade.sh\n```\n\nダウンロードできない場合は、[vpnupgrade.sh](extras/vpnupgrade.sh)を開き、右側の`Raw`ボタンをクリックします。`Ctrl/Cmd+A`を押してすべて選択し、`Ctrl/Cmd+C`を押してコピーし、お気に入りのエディタに貼り付けます。\n</details>\n\n最新のサポートされているLibreswanバージョンは`5.2`です。インストールされているバージョンを確認します：`ipsec --version`。\n\n**注:** `xl2tpd`は、Ubuntu/Debianの`apt-get`などのシステムのパッケージマネージャーを使用して更新できます。\n\n## VPNユーザーの管理\n\n[VPNユーザーの管理](docs/manage-users.md)（英語）を参照してください。\n\n- [ヘルパースクリプトを使用してVPNユーザーを管理する](docs/manage-users.md#manage-vpn-users-using-helper-scripts)\n- [VPNユーザーを表示する](docs/manage-users.md#view-vpn-users)\n- [IPsec PSKを表示または更新する](docs/manage-users.md#view-or-update-the-ipsec-psk)\n- [VPNユーザーを手動で管理する](docs/manage-users.md#manually-manage-vpn-users)\n\n## 高度な使用法\n\n[高度な使用法](docs/advanced-usage.md)（英語）を参照してください。\n\n- [代替DNSサーバーの使用](docs/advanced-usage.md#use-alternative-dns-servers)\n- [DNS名とサーバーIPの変更](docs/advanced-usage.md#dns-name-and-server-ip-changes)\n- [IKEv2専用VPN](docs/advanced-usage.md#ikev2-only-vpn)\n- [内部VPN IPとトラフィック](docs/advanced-usage.md#internal-vpn-ips-and-traffic)\n- [VPNサーバーのパブリックIPを指定する](docs/advanced-usage.md#specify-vpn-servers-public-ip)\n- [VPNサブネットのカスタマイズ](docs/advanced-usage.md#customize-vpn-subnets)\n- [IPv6サポート](docs/advanced-usage.md#ipv6-support)\n- [VPNクライアントへのポートフォワーディング](docs/advanced-usage.md#port-forwarding-to-vpn-clients)\n- [スプリットトンネリング](docs/advanced-usage.md#split-tunneling)\n- [VPNサーバーのサブネットにアクセスする](docs/advanced-usage.md#access-vpn-servers-subnet)\n- [サーバーのサブネットからVPNクライアントにアクセスする](docs/advanced-usage.md#access-vpn-clients-from-servers-subnet)\n- [IPTablesルールの変更](docs/advanced-usage.md#modify-iptables-rules)\n- [Google BBR輻輳制御の展開](docs/advanced-usage.md#deploy-google-bbr-congestion-control)\n\n## VPNのアンインストール\n\nIPsec VPNをアンインストールするには、[ヘルパースクリプト](extras/vpnuninstall.sh)を実行します：\n\n**警告:** このヘルパースクリプトは、サーバーからIPsec VPNを削除します。すべてのVPN構成は**永久に削除**され、Libreswanおよびxl2tpdは削除されます。これは**元に戻すことはできません**！\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\nダウンロードできない場合はこちらをクリックしてください。\n</summary>\n\n`curl`を使用してダウンロードすることもできます：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\n代替スクリプトURL：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\n詳細については、[VPNのアンインストール](docs/uninstall.md)を参照してください。\n\n## フィードバックと質問\n\n- このプロジェクトに提案がありますか？[改善リクエスト](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)を開いてください。[プルリクエスト](https://github.com/hwdsl2/setup-ipsec-vpn/pulls)も歓迎します。\n- 再現可能なバグを見つけた場合、[IPsec VPN](https://github.com/libreswan/libreswan/issues?q=is%3Aissue)または[VPNスクリプト](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)のバグレポートを開いてください。\n- 質問がありますか？まず、[既存の問題](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue)と、この[Gist](https://gist.github.com/hwdsl2/9030462#comments)および[私のブログ](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#disqus_thread)のコメントを検索してください。\n- VPNに関連する質問は、[Libreswan](https://lists.libreswan.org)または[strongSwan](https://lists.strongswan.org)のメーリングリストで質問するか、次のウィキを参照してください：[[1]](https://libreswan.org/wiki/Main_Page) [[2]](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_virtual_private_networks) [[3]](https://wiki.strongswan.org/projects/strongswan/wiki/UserDocumentation) [[4]](https://wiki.gentoo.org/wiki/IPsec_L2TP_VPN_server) [[5]](https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup)。\n\n## ライセンス\n\n著作権 (C) 2014-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n[Thomas Sarlandieの作品](https://github.com/sarfata/voodooprivacy)に基づく（著作権2012）\n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nこの作品は[クリエイティブ・コモンズ表示-継承3.0非移植ライセンス](http://creativecommons.org/licenses/by-sa/3.0/)の下でライセンスされています。  \n帰属が必要です：私の名前を派生物に含め、改善方法を教えてください！\n"
  },
  {
    "path": "README-ru.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [日本語](README-ja.md) | [Русский](README-ru.md)\n\n# Скрипты автоматической настройки сервера IPsec VPN\n\n[![Статус сборки](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml) [![Звезды GitHub](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/stargazers) [![Звезды Docker](docs/images/badges/docker-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-ru.md) [![Загрузки Docker](docs/images/badges/docker-pulls.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-ru.md)\n\nРазверните собственный сервер IPsec VPN всего за несколько минут с поддержкой IPsec/L2TP, Cisco IPsec и IKEv2.\n\nIPsec VPN шифрует сетевой трафик, поэтому никто между вами и VPN-сервером не сможет перехватывать ваши данные во время их передачи через Интернет. Это особенно полезно при использовании незащищённых сетей, например в кофейнях, аэропортах или гостиничных номерах.\n\nМы будем использовать [Libreswan](https://libreswan.org/) в качестве сервера IPsec и [xl2tpd](https://github.com/xelerance/xl2tpd) в качестве поставщика L2TP.\n\n**[&raquo; :book: Книга: Privacy Tools in the Age of AI](docs/vpn-book.md) &nbsp;[Build Your Own VPN Server](docs/vpn-book.md)**\n\n## Быстрый старт\n\nСначала подготовьте ваш Linux-сервер\\* с установленной системой Ubuntu, Debian или CentOS.\n\nИспользуйте эту однострочную команду для настройки сервера IPsec VPN:\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\nДанные для входа в VPN будут сгенерированы случайным образом и показаны после завершения установки.\n\n**Дополнительно:** Установите [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-ru.md) и/или [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-ru.md) на тот же сервер.\n\n<details>\n<summary>\nПосмотреть работу скрипта (запись терминала).\n</summary>\n\n**Примечание:** Эта запись предназначена только для демонстрационных целей. Учетные данные VPN в этой записи **НЕ** являются действительными.\n\n<p align=\"center\"><img src=\"docs/images/script-demo.svg\"></p>\n</details>\n<details>\n<summary>\nНажмите здесь, если не удаётся скачать.\n</summary>\n\nВы также можете использовать `curl` для загрузки:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net -o vpn.sh && sudo sh vpn.sh\n```\n\nАльтернативные URL для установки:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nЕсли вы не можете скачать файл, откройте [vpnsetup.sh](vpnsetup.sh), затем нажмите кнопку `Raw` справа. Нажмите `Ctrl/Cmd+A`, чтобы выделить всё, `Ctrl/Cmd+C`, чтобы скопировать, затем вставьте в ваш любимый редактор.\n</details>\n\nТакже доступен готовый [образ Docker](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-ru.md). Для других вариантов и настройки клиентов прочитайте разделы ниже.\n\n\\* Облачный сервер, виртуальный частный сервер (VPS) или выделенный сервер.\n\n## Возможности\n\n- Полностью автоматическая настройка сервера IPsec VPN, ввод пользователя не требуется\n- Поддержка IKEv2 с мощными и быстрыми шифрами (например, AES-GCM)\n- Генерация профилей VPN для автоматической настройки устройств iOS, macOS и Android\n- Поддержка Windows, macOS, iOS, Android, Chrome OS и Linux в качестве VPN-клиентов\n- Включает вспомогательные скрипты для управления пользователями VPN и сертификатами\n\n## Требования\n\nОблачный сервер, виртуальный частный сервер (VPS) или выделенный сервер с установленной системой:\n\n- Ubuntu 24.04 или 22.04\n- Debian 13, 12 или 11\n- CentOS Stream 10 или 9\n- Rocky Linux или AlmaLinux\n- Oracle Linux\n- Amazon Linux 2\n\n<details>\n<summary>\nДругие поддерживаемые дистрибутивы Linux.\n</summary>\n\n- Raspberry Pi OS (Raspbian)\n- Kali Linux\n- Alpine Linux\n- Red Hat Enterprise Linux (RHEL)\n</details>\n\nЭто также включает виртуальные машины Linux в публичных облаках, таких как [DigitalOcean](https://blog.ls20.com/digitalocean), [Vultr](https://blog.ls20.com/vultr), [Linode](https://blog.ls20.com/linode), [OVH](https://www.ovhcloud.com/en/vps/) и [Microsoft Azure](https://azure.microsoft.com). Пользователи публичных облаков также могут выполнить развёртывание с помощью [пользовательскими данными](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#vpnsetup).\n\nБыстрое развёртывание в:\n\n[![Deploy to Linode](docs/images/linode-deploy-button.png)](https://cloud.linode.com/stackscripts/37239) &nbsp;[![Deploy to AWS](docs/images/aws-deploy-button.png)](aws/README.md) &nbsp;[![Deploy to Azure](docs/images/azure-deploy-button.png)](azure/README.md)\n\n[**&raquo; Я хочу запустить собственный VPN, но у меня нет сервера для этого**](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#gettingavps)\n\nДля серверов с внешним файрволом (например, [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)) откройте UDP-порты 500 и 4500 для VPN.\n\nТакже доступен готовый [образ Docker](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-ru.md). Продвинутые пользователи могут установить его на [Raspberry Pi](https://www.raspberrypi.com). [[1]](https://elasticbyte.net/posts/setting-up-a-native-cisco-ipsec-vpn-server-using-a-raspberry-pi/) [[2]](https://www.stewright.me/2018/07/create-a-raspberry-pi-vpn-server-using-l2tpipsec/)\n\n:warning: **НЕ** запускайте эти скрипты на вашем ПК или Mac! Их следует использовать только на сервере!\n\n## Установка\n\nСначала обновите ваш сервер с помощью `sudo apt-get update && sudo apt-get dist-upgrade` (Ubuntu/Debian) или `sudo yum update`, затем перезагрузите систему. Это необязательно, но рекомендуется.\n\nЧтобы установить VPN, выберите один из следующих вариантов:\n\n**Вариант 1:** Позвольте скрипту сгенерировать случайные учетные данные VPN (они будут показаны после завершения).\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n**Вариант 2:** Отредактируйте скрипт и укажите собственные учетные данные VPN.\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nnano -w vpn.sh\n[Замените на собственные значения: YOUR_IPSEC_PSK, YOUR_USERNAME и YOUR_PASSWORD]\nsudo sh vpn.sh\n```\n\n**Примечание:** Безопасный IPsec PSK должен состоять как минимум из 20 случайных символов.\n\n**Вариант 3:** Определите учетные данные VPN как переменные окружения.\n\n```bash\n# Все значения ДОЛЖНЫ быть заключены в 'одинарные кавычки'\n# НЕ используйте внутри значений следующие специальные символы: \\ \" '\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \\\nVPN_USER='your_vpn_username' \\\nVPN_PASSWORD='your_vpn_password' \\\nsh vpn.sh\n```\n\nПри желании вы можете установить [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-ru.md) и/или [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-ru.md) на том же сервере. Если ваш сервер работает на CentOS Stream, Rocky Linux или AlmaLinux, сначала установите OpenVPN/WireGuard, а затем установите IPsec VPN.\n\n<details>\n<summary>\nНажмите здесь, если не удаётся скачать.\n</summary>\n\nВы также можете использовать `curl` для загрузки. Например:\n\n```bash\ncurl -fL https://get.vpnsetup.net -o vpn.sh\nsudo sh vpn.sh\n```\n\nАльтернативные URL для установки:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nЕсли вы не можете скачать файл, откройте [vpnsetup.sh](vpnsetup.sh), затем нажмите кнопку `Raw` справа. Нажмите `Ctrl/Cmd+A`, чтобы выделить всё, `Ctrl/Cmd+C`, чтобы скопировать, затем вставьте в ваш любимый редактор.\n</details>\n<details>\n<summary>\nЯ хочу установить более старую версию Libreswan 4.\n</summary>\n\nОбычно рекомендуется использовать последнюю версию [Libreswan](https://libreswan.org/) 5, которая является версией по умолчанию в этом проекте. Однако если вы хотите установить более старую версию Libreswan 4:\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_SWAN_VER=4.15 sh vpn.sh\n```\n\n**Примечание:** Если версия Libreswan 5 уже установлена, возможно, вам сначала потребуется [удалить VPN](docs/uninstall.md), прежде чем устанавливать Libreswan версии 4. В качестве альтернативы можно скачать [скрипт обновления](#обновление-libreswan), отредактировать его, указав `SWAN_VER=4.15`, затем запустить скрипт.\n</details>\n\n## Настройка параметров VPN\n\n### Использование альтернативных DNS-серверов\n\nПо умолчанию клиенты настроены использовать [Google Public DNS](https://developers.google.com/speed/public-dns/) при активном VPN. При установке VPN вы можете при желании указать собственные DNS-серверы для всех режимов VPN. Пример:\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\nИспользуйте `VPN_DNS_SRV1` для указания основного DNS-сервера и `VPN_DNS_SRV2` для указания резервного DNS-сервера (необязательно).\n\nНиже приведён список некоторых популярных публичных DNS-провайдеров для справки.\n\n| Провайдер | Основной DNS | Резервный DNS | Примечания |\n| -------- | ----------- | ------------- | ----- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | Используется по умолчанию в этом проекте |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | См. также: [Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | Блокирует вредоносные домены |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | Блокирует фишинговые домены, настраиваемый |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | Доступны [фильтры доменов](https://cleanbrowsing.org/filters/) |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | Различается | Различается | Блокировка рекламы, доступен бесплатный тариф. [Подробнее](https://nextdns.io/?from=bg25bwmp). |\n| [Control D](https://controld.com/free-dns) | Различается | Различается | Блокировка рекламы, настраиваемый. [Подробнее](https://controld.com/free-dns). |\n\nЕсли вам нужно изменить DNS-серверы после настройки VPN, см. раздел [Расширенное использование](docs/advanced-usage.md).\n\n**Примечание:** Если IKEv2 уже настроен на сервере, переменные выше не влияют на режим IKEv2. В этом случае для настройки параметров IKEv2, таких как DNS-серверы, вы можете сначала [удалить IKEv2](docs/ikev2-howto.md#remove-ikev2), а затем снова настроить его с помощью `sudo ikev2.sh`.\n\n### Настройка параметров IKEv2\n\nПри установке VPN продвинутые пользователи могут при желании настроить параметры IKEv2.\n\n<details open>\n<summary>\nВариант 1: Пропустить IKEv2 во время настройки VPN, затем настроить IKEv2 с пользовательскими параметрами.\n</summary>\n\nПри установке VPN вы можете пропустить IKEv2 и установить только режимы IPsec/L2TP и IPsec/XAuth («Cisco IPsec»):\n\n```bash\nsudo VPN_SKIP_IKEV2=yes sh vpn.sh\n```\n\n(Необязательно) Если вы хотите указать пользовательские DNS-серверы для клиентов VPN, определите `VPN_DNS_SRV1` и при необходимости `VPN_DNS_SRV2`. Подробности смотрите в разделе [Использование альтернативных DNS-серверов](#использование-альтернативных-dns-серверов).\n\nПосле этого запустите вспомогательный скрипт IKEv2, чтобы настроить IKEv2 в интерактивном режиме с пользовательскими параметрами:\n\n```bash\nsudo ikev2.sh\n```\n\nВы можете настроить следующие параметры: DNS-имя VPN-сервера, имя и срок действия первого клиента, DNS-сервер для VPN-клиентов и необходимость защиты файлов конфигурации клиента паролем.\n\n**Примечание:** Переменная `VPN_SKIP_IKEV2` не действует, если IKEv2 уже настроен на сервере. В этом случае для настройки параметров IKEv2 вы можете сначала [удалить IKEv2](docs/ikev2-howto.md#remove-ikev2), а затем снова настроить его с помощью `sudo ikev2.sh`.\n</details>\n<details>\n<summary>\nВариант 2: Настройка параметров IKEv2 с помощью переменных окружения.\n</summary>\n\nПри установке VPN вы можете при желании указать DNS-имя для адреса сервера IKEv2. DNS-имя должно быть полным доменным именем (FQDN). Пример:\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' sh vpn.sh\n```\n\nАналогично вы можете указать имя для первого клиента IKEv2. По умолчанию используется `vpnclient`, если имя не указано.\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' sh vpn.sh\n```\n\nПо умолчанию клиенты используют [Google Public DNS](https://developers.google.com/speed/public-dns/) при активном VPN. Вы можете указать собственные DNS-серверы для всех режимов VPN. Пример:\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\nПо умолчанию пароль не требуется при импорте конфигурации клиента IKEv2. Вы можете защитить файлы конфигурации клиента случайным паролем.\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes sh vpn.sh\n```\n</details>\n<details>\n<summary>\nДля справки: список параметров IKEv1 и IKEv2.\n</summary>\n\n| Параметр IKEv1\\*            | Значение по умолчанию | Настройка (переменная окружения)\\*\\* |\n| --------------------------- | --------------------- | ------------------------------------ |\n| Адрес сервера (DNS-имя)     | -                     | Нет, но можно подключаться по DNS-имени |\n| Адрес сервера (публичный IP)| Автоопределение       | VPN_PUBLIC_IP                        |\n| Предварительно общий ключ IPsec | Автоматическая генерация | VPN_IPSEC_PSK                    |\n| Имя пользователя VPN        | vpnuser               | VPN_USER                             |\n| Пароль VPN                  | Автоматическая генерация | VPN_PASSWORD                     |\n| DNS-серверы для клиентов    | Google Public DNS     | VPN_DNS_SRV1, VPN_DNS_SRV2           |\n| Пропустить настройку IKEv2  | no                    | VPN_SKIP_IKEV2=yes                   |\n\n\\* Эти параметры IKEv1 используются для режимов IPsec/L2TP и IPsec/XAuth («Cisco IPsec»).  \n\\*\\* Определяются как переменные окружения при запуске vpn(setup).sh.\n\n| Параметр IKEv2\\*            | Значение по умолчанию | Настройка (переменная окружения)\\*\\* | Настройка (интерактивно)\\*\\*\\* |\n| --------------------------- | --------------------- | ------------------------------------ | ------------------------------- |\n| Адрес сервера (DNS-имя)     | -                     | VPN_DNS_NAME                         | ✅                              |\n| Адрес сервера (публичный IP)| Автоопределение       | VPN_PUBLIC_IP                        | ✅                              |\n| Имя первого клиента         | vpnclient             | VPN_CLIENT_NAME                      | ✅                              |\n| DNS-серверы для клиентов    | Google Public DNS     | VPN_DNS_SRV1, VPN_DNS_SRV2           | ✅                              |\n| Защита файлов конфигурации клиента | no            | VPN_PROTECT_CONFIG=yes               | ✅                              |\n| Включить/отключить MOBIKE   | Включено, если поддерживается | ❌                             | ✅                              |\n| Срок действия сертификата клиента | 10 лет (120 месяцев) | VPN_CLIENT_VALIDITY\\*\\*\\*\\*     | ✅                              |\n| Срок действия сертификатов CA и сервера | 10 лет (120 месяцев) | ❌                         | ❌                              |\n| Имя сертификата CA          | IKEv2 VPN CA          | ❌                                   | ❌                              |\n| Размер ключа сертификата    | 3072 бита             | ❌                                   | ❌                              |\n\n\\* Эти параметры IKEv2 используются для режима IKEv2.  \n\\*\\* Определяются как переменные окружения при запуске vpn(setup).sh или при автоматической настройке IKEv2 (`sudo ikev2.sh --auto`).  \n\\*\\*\\* Можно настроить во время интерактивной настройки IKEv2 (`sudo ikev2.sh`). См. вариант 1 выше.  \n\\*\\*\\*\\* Используйте `VPN_CLIENT_VALIDITY`, чтобы указать срок действия сертификата клиента в месяцах. Значение должно быть целым числом от 1 до 120.\n\nПомимо этих параметров, продвинутые пользователи также могут [настроить подсети VPN](docs/advanced-usage.md#customize-vpn-subnets) во время настройки VPN.\n</details>\n\n## Следующие шаги\n\n*Прочитать на других языках: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [日本語](README-ja.md#次のステップ), [Русский](README-ru.md#следующие-шаги).*\n\nНастройте ваш компьютер или устройство для использования VPN. Пожалуйста, обратитесь к следующим инструкциям (на английском языке):\n\n**[Настройка клиентов IKEv2 VPN (рекомендуется)](docs/ikev2-howto.md)**\n\n**[Настройка клиентов IPsec/L2TP VPN](docs/clients.md)**\n\n**[Настройка клиентов IPsec/XAuth («Cisco IPsec»)](docs/clients-xauth.md)**\n\n**Прочитайте [:book: книгу о VPN](docs/vpn-book.md), чтобы получить доступ к [дополнительному контенту](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J).**\n\nНаслаждайтесь собственным VPN! :sparkles::tada::rocket::sparkles:\n\n## Важные замечания\n\n**Пользователи Windows**: для режима IPsec/L2TP требуется [одноразовое изменение реестра](docs/clients.md#windows-error-809), если VPN-сервер или клиент находится за NAT (например, домашним роутером).\n\nОдна и та же учетная запись VPN может использоваться на нескольких ваших устройствах. Однако из-за ограничения IPsec/L2TP, если вы хотите подключить несколько устройств из-за одного NAT (например, домашнего роутера), необходимо использовать режим [IKEv2](docs/ikev2-howto.md) или [IPsec/XAuth](docs/clients-xauth.md). Чтобы просмотреть или изменить учетные записи пользователей VPN, см. [Управление пользователями VPN](docs/manage-users.md).\n\nДля серверов с внешним файрволом (например, [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)) откройте UDP-порты 500 и 4500 для VPN. Пользователям Aliyun см. [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433).\n\nКлиенты настроены использовать [Google Public DNS](https://developers.google.com/speed/public-dns/) при активном VPN. Если вы предпочитаете другого DNS-провайдера, см. [Расширенное использование](docs/advanced-usage.md).\n\nИспользование поддержки ядра может повысить производительность IPsec/L2TP. Она доступна на [всех поддерживаемых ОС](#требования). Пользователям Ubuntu следует установить пакет `linux-modules-extra-$(uname -r)` и выполнить `service xl2tpd restart`.\n\nСкрипты создадут резервные копии существующих файлов конфигурации перед внесением изменений, с суффиксом `.old-date-time`.\n\n## Обновление Libreswan\n\nИспользуйте эту однострочную команду для обновления [Libreswan](https://libreswan.org) ([список изменений](https://github.com/libreswan/libreswan/blob/main/CHANGES) | [объявления](https://lists.libreswan.org)) на вашем VPN-сервере.\n\n```bash\nwget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n```\n\n<details>\n<summary>\nНажмите здесь, если не удаётся скачать.\n</summary>\n\nВы также можете использовать `curl` для загрузки:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/upg -o vpnup.sh && sudo sh vpnup.sh\n```\n\nАльтернативные URL для обновления:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnupgrade.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnupgrade.sh\n```\n\nЕсли вы не можете скачать файл, откройте [vpnupgrade.sh](extras/vpnupgrade.sh), затем нажмите кнопку `Raw` справа. Нажмите `Ctrl/Cmd+A`, чтобы выделить всё, `Ctrl/Cmd+C`, чтобы скопировать, затем вставьте в ваш любимый редактор.\n</details>\n\nПоследняя поддерживаемая версия Libreswan — `5.3`. Проверить установленную версию: `ipsec --version`.\n\n**Примечание:** `xl2tpd` можно обновить с помощью менеджера пакетов вашей системы, например `apt-get` в Ubuntu/Debian.\n\n## Управление пользователями VPN\n\nСм. [Управление пользователями VPN](docs/manage-users.md) (на английском языке).\n\n- [Управление пользователями VPN с помощью вспомогательных скриптов](docs/manage-users.md#manage-vpn-users-using-helper-scripts)\n- [Просмотр пользователей VPN](docs/manage-users.md#view-vpn-users)\n- [Просмотр или обновление IPsec PSK](docs/manage-users.md#view-or-update-the-ipsec-psk)\n- [Ручное управление пользователями VPN](docs/manage-users.md#manually-manage-vpn-users)\n\n## Расширенное использование\n\nСм. [Расширенное использование](docs/advanced-usage.md) (на английском языке).\n\n- [Использование альтернативных DNS-серверов](docs/advanced-usage.md#use-alternative-dns-servers)\n- [Изменения DNS-имени и IP-адреса сервера](docs/advanced-usage.md#dns-name-and-server-ip-changes)\n- [VPN только с IKEv2](docs/advanced-usage.md#ikev2-only-vpn)\n- [Внутренние IP-адреса VPN и трафик](docs/advanced-usage.md#internal-vpn-ips-and-traffic)\n- [Указание публичного IP-адреса VPN-сервера](docs/advanced-usage.md#specify-vpn-servers-public-ip)\n- [Настройка подсетей VPN](docs/advanced-usage.md#customize-vpn-subnets)\n- [Поддержка IPv6](docs/advanced-usage.md#ipv6-support)\n- [Переадресация портов клиентам VPN](docs/advanced-usage.md#port-forwarding-to-vpn-clients)\n- [Раздельная маршрутизация (Split tunneling)](docs/advanced-usage.md#split-tunneling)\n- [Доступ к подсети VPN-сервера](docs/advanced-usage.md#access-vpn-servers-subnet)\n- [Доступ к клиентам VPN из подсети сервера](docs/advanced-usage.md#access-vpn-clients-from-servers-subnet)\n- [Изменение правил IPTables](docs/advanced-usage.md#modify-iptables-rules)\n- [Развёртывание алгоритма управления перегрузкой Google BBR](docs/advanced-usage.md#deploy-google-bbr-congestion-control)\n\n## Удаление VPN\n\nЧтобы удалить IPsec VPN, запустите [вспомогательный скрипт](extras/vpnuninstall.sh):\n\n**Предупреждение:** Этот вспомогательный скрипт удалит IPsec VPN с вашего сервера. Вся конфигурация VPN будет **безвозвратно удалена**, а Libreswan и xl2tpd будут удалены. Это **нельзя отменить**!\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\nНажмите здесь, если не удаётся скачать.\n</summary>\n\nВы также можете использовать `curl` для загрузки:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\nАльтернативные URL скрипта:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\nДля получения дополнительной информации см. [Удаление VPN](docs/uninstall.md).\n\n## Обратная связь и вопросы\n\n- Есть предложение по улучшению этого проекта? Создайте [Предложить улучшение](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose). [Pull request](https://github.com/hwdsl2/setup-ipsec-vpn/pulls) также приветствуются.\n- Если вы нашли воспроизводимую ошибку, создайте отчёт об ошибке для [IPsec VPN](https://github.com/libreswan/libreswan/issues?q=is%3Aissue) или для [скрипты VPN](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose).\n- Есть вопрос? Пожалуйста, сначала выполните поиск по [существующим issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue) и комментариям [в этом Gist](https://gist.github.com/hwdsl2/9030462#comments) и [в моём блоге](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#disqus_thread).\n- Задавайте вопросы, связанные с VPN, в списках рассылки [Libreswan](https://lists.libreswan.org) или [strongSwan](https://lists.strongswan.org), либо прочитайте эти вики: [[1]](https://libreswan.org/wiki/Main_Page) [[2]](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_virtual_private_networks) [[3]](https://wiki.strongswan.org/projects/strongswan/wiki/UserDocumentation) [[4]](https://wiki.gentoo.org/wiki/IPsec_L2TP_VPN_server) [[5]](https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup).\n\n## Лицензия\n\nCopyright (C) 2014-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \nОсновано на [работе Thomas Sarlandie](https://github.com/sarfata/voodooprivacy) (Copyright 2012)\n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nЭта работа распространяется по лицензии [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nТребуется указание авторства: пожалуйста, указывайте моё имя в любых производных работах и сообщайте мне, как вы её улучшили!\n"
  },
  {
    "path": "README-zh-Hant.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [日本語](README-ja.md) | [Русский](README-ru.md)\n\n# IPsec VPN 伺服器一鍵安裝腳本\n\n[![Build Status](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh-Hant.md) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh-Hant.md)\n\n使用 Linux 腳本一鍵快速架設自己的 IPsec VPN 伺服器。支援 IPsec/L2TP、Cisco IPsec 和 IKEv2 協議。\n\nIPsec VPN 可以加密你的網路流量，以防止在透過網際網路傳送時，你和 VPN 伺服器之間的任何人對你的資料進行未經授權的存取。在使用不安全的網路時，這一點特別有用，例如在咖啡廳、機場或旅館房間。\n\n我們將使用 [Libreswan](https://libreswan.org/) 作為 IPsec 伺服器，以及 [xl2tpd](https://github.com/xelerance/xl2tpd) 作為 L2TP 提供者。\n\n**[&raquo; :book: Book: Privacy Tools in the Age of AI](docs/vpn-book-zh-Hant.md) &nbsp;[架設自己的 VPN 伺服器](docs/vpn-book-zh-Hant.md)**\n\n## 快速開始\n\n首先，在你的 Linux 伺服器\\* 上安裝 Ubuntu、Debian 或 CentOS。\n\n使用以下命令快速架設 IPsec VPN 伺服器：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n你的 VPN 登入憑證將會自動隨機生成，並在安裝完成後顯示。\n\n**可選：** 在同一台伺服器上安裝 [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-zh-Hant.md) 和/或 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh-Hant.md)。\n\n<details>\n<summary>\n查看腳本的範例輸出（終端記錄）。\n</summary>\n\n**註：** 此終端記錄僅用於示範目的。該記錄中的 VPN 憑據 **無效**。\n\n<p align=\"center\"><img src=\"docs/images/script-demo.svg\"></p>\n</details>\n<details>\n<summary>\n如果無法下載，請點這裡。\n</summary>\n\n你也可以使用 `curl` 下載：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net -o vpn.sh && sudo sh vpn.sh\n```\n\n或者，你也可以使用這些連結：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\n如果無法下載，打開 [vpnsetup.sh](vpnsetup.sh)，然後點擊右側的 `Raw` 按鈕。按快捷鍵 `Ctrl/Cmd+A` 全選，`Ctrl/Cmd+C` 複製，然後貼上到你喜歡的編輯器。\n</details>\n\n另外，你也可以使用預先建構的 [Docker 映像](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh-Hant.md)。如需了解其他選項以及客戶端設定，請繼續閱讀以下部分。\n\n\\* 一個雲端伺服器、虛擬專用伺服器 (VPS) 或專用伺服器。\n\n## 功能特性\n\n- 全自動的 IPsec VPN 伺服器設定，無需使用者輸入\n- 支援具有強大且快速加密演算法（例如 AES-GCM）的 IKEv2 模式\n- 生成 VPN 設定檔以自動設定 iOS、macOS 和 Android 裝置\n- 支援 Windows、macOS、iOS、Android、Chrome OS 和 Linux 客戶端\n- 包含輔助腳本以管理 VPN 使用者和憑證\n\n## 系統需求\n\n一個雲端伺服器、虛擬專用伺服器 (VPS) 或專用伺服器，安裝以下作業系統之一：\n\n- Ubuntu 24.04 或 22.04\n- Debian 13、12 或 11\n- CentOS Stream 10 或 9\n- Rocky Linux 或 AlmaLinux\n- Oracle Linux\n- Amazon Linux 2\n\n<details>\n<summary>\n其他受支援的 Linux 發行版。\n</summary>\n\n- Raspberry Pi OS (Raspbian)\n- Kali Linux\n- Alpine Linux\n- Red Hat Enterprise Linux (RHEL)\n</details>\n\n這也包括公共雲服務中的 Linux 虛擬機，例如 [DigitalOcean](https://blog.ls20.com/digitalocean)、[Vultr](https://blog.ls20.com/vultr)、[Linode](https://blog.ls20.com/linode)、[OVH](https://www.ovhcloud.com/en/vps/) 和 [Microsoft Azure](https://azure.microsoft.com)。公共雲使用者也可以使用[使用者資料](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#vpnsetup)部署。\n\n使用以下按鈕快速部署：\n\n[![Deploy to Linode](docs/images/linode-deploy-button.png)](https://cloud.linode.com/stackscripts/37239) &nbsp;[![Deploy to AWS](docs/images/aws-deploy-button.png)](aws/README-zh.md) &nbsp;[![Deploy to Azure](docs/images/azure-deploy-button.png)](azure/README-zh.md)\n\n[**&raquo; 我想建立並使用自己的 VPN，但沒有可用的伺服器**](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#gettingavps)\n\n對於有外部防火牆的伺服器（例如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），請為 VPN 開啟 UDP 連接埠 500 和 4500。\n\n另外，你也可以使用預先建構的 [Docker 映像](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh-Hant.md)。進階使用者可以在 [Raspberry Pi](https://www.raspberrypi.com) 上安裝。[[1]](https://elasticbyte.net/posts/setting-up-a-native-cisco-ipsec-vpn-server-using-a-raspberry-pi/) [[2]](https://www.stewright.me/2018/07/create-a-raspberry-pi-vpn-server-using-l2tpipsec/)\n\n:warning: **不要** 在你的 PC 或 Mac 上執行這些腳本！它們只能用在伺服器上！\n\n## 安裝說明\n\n首先，更新你的伺服器：執行 `sudo apt-get update && sudo apt-get dist-upgrade` (Ubuntu/Debian) 或 `sudo yum update` 並重新啟動。此步驟為可選，但建議執行。\n\n要安裝 VPN，請從以下選項中選擇一個：\n\n**選項 1：** 使用腳本隨機生成的 VPN 登入憑證（完成後會顯示）。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n**選項 2：** 編輯腳本並提供你自己的 VPN 登入憑證。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nnano -w vpn.sh\n[替換為你自己的值： YOUR_IPSEC_PSK, YOUR_USERNAME 和 YOUR_PASSWORD]\nsudo sh vpn.sh\n```\n\n**註：** 一個安全的 IPsec PSK 應至少包含 20 個隨機字元。\n\n**選項 3：** 將你自己的 VPN 登入憑證定義為環境變數。\n\n```bash\n# 所有變數值必須用 '單引號' 括起來\n# *不要* 在值中使用這些字元：  \\ \" '\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_IPSEC_PSK='你的IPsec預共享金鑰' \\\nVPN_USER='你的VPN使用者名稱' \\\nVPN_PASSWORD='你的VPN密碼' \\\nsh vpn.sh\n```\n\n你可以選擇在同一台伺服器上安裝 [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-zh-Hant.md) 和/或 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh-Hant.md)。如果你的伺服器執行 CentOS Stream、Rocky Linux 或 AlmaLinux，請先安裝 OpenVPN/WireGuard，然後再安裝 IPsec VPN。\n\n<details>\n<summary>\n如果無法下載，請點這裡。\n</summary>\n\n你也可以使用 `curl` 下載。例如：\n\n```bash\ncurl -fL https://get.vpnsetup.net -o vpn.sh\nsudo sh vpn.sh\n```\n\n或者，你也可以使用這些連結：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\n如果無法下載，打開 [vpnsetup.sh](vpnsetup.sh)，然後點擊右側的 `Raw` 按鈕。按快捷鍵 `Ctrl/Cmd+A` 全選，`Ctrl/Cmd+C` 複製，然後貼上到你喜歡的編輯器。\n</details>\n<details>\n<summary>\n我需要安裝較舊版本的 Libreswan 版本 4。\n</summary>\n\n一般建議使用最新的 [Libreswan](https://libreswan.org/) 版本 5，它是本專案的預設版本。不過，如果你想要安裝較舊版本的 Libreswan 版本 4：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_SWAN_VER=4.15 sh vpn.sh\n```\n\n**註：** 如果 Libreswan 版本 5 已經安裝，你可能需要先[解除安裝 VPN](docs/uninstall-zh.md)，然後再安裝 Libreswan 版本 4。或者，你也可以下載[升級腳本](#升級libreswan)，編輯它並指定 `SWAN_VER=4.15`，然後執行腳本。\n</details>\n\n## 自訂 VPN 選項\n\n### 使用其他 DNS 伺服器\n\n在 VPN 已連線時，客戶端預設設定為使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。在安裝 VPN 時，你可以為所有 VPN 模式指定其他 DNS 伺服器。此為可選設定。示例如下：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\n使用 `VPN_DNS_SRV1` 指定主要 DNS 伺服器，使用 `VPN_DNS_SRV2` 指定次要 DNS 伺服器（可選）。\n\n以下是一些常見的公共 DNS 提供商列表，供你參考。\n\n| 提供商 | 主 DNS | 輔助 DNS | 註解 |\n| ----- | ------ | ------- | ---- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | 本專案預設 |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | 另見：[Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | 阻擋惡意網域 |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | 阻擋網路釣魚網域，可設定。 |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | 提供[網域過濾器](https://cleanbrowsing.org/filters/) |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | 依需求選擇 | 依需求選擇 | 廣告攔截，提供免費方案。[了解更多](https://nextdns.io/?from=bg25bwmp)。 |\n| [Control D](https://controld.com/free-dns) | 依需求選擇 | 依需求選擇 | 廣告攔截，可自訂設定。[了解更多](https://controld.com/free-dns)。 |\n\n如果你需要在安裝 VPN 之後更改 DNS 伺服器，請參見[進階用法](docs/advanced-usage-zh.md)。\n\n**註：** 如果伺服器上已經設定 IKEv2，以上變數對 IKEv2 模式無效。在此情況下，如需自訂 IKEv2 選項（例如 DNS 伺服器），你可以先[移除 IKEv2](docs/ikev2-howto-zh.md#移除-ikev2)，然後執行 `sudo ikev2.sh` 重新設定。\n\n### 自訂 IKEv2 選項\n\n在安裝 VPN 時，進階使用者可以自訂 IKEv2 選項。此為可選設定。\n\n<details open>\n<summary>\n選項 1：在安裝 VPN 時跳過 IKEv2，然後使用自訂選項設定 IKEv2。\n</summary>\n\n在安裝 VPN 時，你可以跳過 IKEv2，只安裝 IPsec/L2TP 和 IPsec/XAuth（\"Cisco IPsec\"）模式：\n\n```bash\nsudo VPN_SKIP_IKEV2=yes sh vpn.sh\n```\n\n（可選）如果要為 VPN 客戶端指定其他 DNS 伺服器，你可以定義 `VPN_DNS_SRV1` 和 `VPN_DNS_SRV2`（可選）。更多資訊請參見[使用其他 DNS 伺服器](#使用其他-dns-伺服器)。\n\n然後執行 IKEv2 輔助腳本，以互動方式使用自訂選項設定 IKEv2：\n\n```bash\nsudo ikev2.sh\n```\n\n你可以自訂以下選項：VPN 伺服器的網域名稱、第一個客戶端的名稱與憑證有效期限、VPN 客戶端的 DNS 伺服器，以及是否對客戶端設定檔進行密碼保護。\n\n**註：** 如果伺服器上已經設定 IKEv2，則 `VPN_SKIP_IKEV2` 變數無效。在此情況下，如需自訂 IKEv2 選項，你可以先[移除 IKEv2](docs/ikev2-howto-zh.md#移除-ikev2)，然後執行 `sudo ikev2.sh` 重新設定。\n</details>\n<details>\n<summary>\n選項 2：使用環境變數自訂 IKEv2 選項。\n</summary>\n\n在安裝 VPN 時，你可以指定一個網域名稱作為 IKEv2 伺服器位址。此為可選設定。該網域名稱必須是完整網域名稱 (FQDN)。示例如下：\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' sh vpn.sh\n```\n\n同樣地，你也可以指定第一個 IKEv2 客戶端的名稱。如果未指定，則使用預設值 `vpnclient`。\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' sh vpn.sh\n```\n\n在 VPN 已連線時，客戶端預設設定為使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。你可以為所有 VPN 模式指定其他 DNS 伺服器。示例如下：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\n預設情況下，匯入 IKEv2 客戶端設定時不需要密碼。你可以選擇使用隨機密碼保護客戶端設定檔。\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes sh vpn.sh\n```\n</details>\n<details>\n<summary>\n供參考：IKEv1 和 IKEv2 參數列表。\n</summary>\n\n| IKEv1 參數\\* |預設值 |自訂（環境變數）\\*\\* |\n| ------------ | ---- | ----------------- |\n|伺服器位址（DNS 網域名稱）| - |不能，但你可以使用 DNS 網域名稱進行連線 |\n|伺服器位址（公網 IP）|自動偵測 | VPN_PUBLIC_IP |\n| IPsec 預共享金鑰 |自動生成 | VPN_IPSEC_PSK |\n| VPN 使用者名稱 | vpnuser | VPN_USER |\n| VPN 密碼 |自動生成 | VPN_PASSWORD |\n|客戶端的 DNS 伺服器 |Google Public DNS | VPN_DNS_SRV1, VPN_DNS_SRV2 |\n|跳過 IKEv2 安裝 |no | VPN_SKIP_IKEV2=yes |\n\n\\* 這些 IKEv1 參數適用於 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式。   \n\\*\\* 在執行 vpn(setup).sh 時將這些定義為環境變數。\n\n| IKEv2 參數\\* |預設值 |自訂（環境變數）\\*\\* |自訂（互動式）\\*\\*\\* |\n| ----------- | ---- | ------------------ | ----------------- |\n|伺服器位址（DNS 網域名稱）| - | VPN_DNS_NAME | ✅ |\n|伺服器位址（公網 IP）|自動偵測 | VPN_PUBLIC_IP | ✅ |\n|第一個客戶端的名稱 | vpnclient | VPN_CLIENT_NAME | ✅ |\n|客戶端的 DNS 伺服器 |Google Public DNS | VPN_DNS_SRV1, VPN_DNS_SRV2 | ✅ |\n|保護客戶端設定檔 |no | VPN_PROTECT_CONFIG=yes | ✅ |\n|啟用/停用 MOBIKE |如果系統支援則啟用 | ❌ | ✅ |\n|客戶端憑證有效期限 | 10 年（120 個月）| VPN_CLIENT_VALIDITY\\*\\*\\*\\* | ✅ |\n| CA 和伺服器憑證有效期限 | 10 年（120 個月）| ❌ | ❌ |\n| CA 憑證名稱 | IKEv2 VPN CA | ❌ | ❌ |\n|憑證金鑰長度 | 3072 bits | ❌ | ❌ |\n\n\\* 這些 IKEv2 參數適用於 IKEv2 模式。   \n\\*\\* 在執行 vpn(setup).sh 時，或在自動模式下設定 IKEv2 時 (`sudo ikev2.sh --auto`) 將這些定義為環境變數。   \n\\*\\*\\* 可以在互動式設定 IKEv2 期間自訂 (`sudo ikev2.sh`)。參見上面的選項 1。   \n\\*\\*\\*\\* 使用 `VPN_CLIENT_VALIDITY` 定義客戶端憑證的有效期限（單位：月）。它必須是 1 到 120 之間的整數。\n\n除了這些參數，高級使用者還可以在安裝時[自訂 VPN 子網](docs/advanced-usage-zh.md#自定义-vpn-子网)。\n</details>\n\n## 下一步\n\n*其他語言版本: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [日本語](README-ja.md#次のステップ), [Русский](README-ru.md#следующие-шаги)。*\n\n設定你的電腦或其他裝置使用 VPN。請參見以下連結（簡體中文）：\n\n**[設定 IKEv2 VPN 客戶端（推薦）](docs/ikev2-howto-zh.md)**\n\n**[設定 IPsec/L2TP VPN 客戶端](docs/clients-zh.md)**\n\n**[設定 IPsec/XAuth (\"Cisco IPsec\") VPN 客戶端](docs/clients-xauth-zh.md)**\n\n**閱讀 [:book: VPN book](docs/vpn-book-zh-Hant.md) 以存取[額外內容](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)。**\n\n開始使用自己的專屬 VPN! :sparkles::tada::rocket::sparkles:\n\n## 重要提示\n\n**Windows 使用者** 對於 IPsec/L2TP 模式，在首次連線之前需要[修改登錄檔](docs/clients-zh.md#windows-错误-809)，以解決 VPN 伺服器或客戶端與 NAT（例如家用路由器）的相容問題。\n\n同一個 VPN 帳戶可以在你的多個裝置上使用。但由於 IPsec/L2TP 的限制，如果需要連線到同一個 NAT（例如家用路由器）後面的多個裝置，你必須使用 [IKEv2](docs/ikev2-howto-zh.md) 或 [IPsec/XAuth](docs/clients-xauth-zh.md) 模式。要查看或變更 VPN 使用者帳戶，請參見[管理 VPN 使用者](docs/manage-users-zh.md)。\n\n對於有外部防火牆的伺服器（例如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），請為 VPN 開啟 UDP 連接埠 500 和 4500。阿里雲使用者請參見 [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433)。\n\n在 VPN 已連線時，客戶端設定為使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。如果偏好其他的網域解析服務，請參見[進階用法](docs/advanced-usage-zh.md)。\n\n使用核心支援有助於提升 IPsec/L2TP 效能。它在所有[支援的系統](#系統需求)上可用。Ubuntu 系統需要安裝 `linux-modules-extra-$(uname -r)` 軟體套件並執行 `service xl2tpd restart`。\n\n這些腳本在變更現有設定檔之前會先建立備份，並使用 `.old-日期-時間` 作為檔名後綴。\n\n## 升級Libreswan\n\n使用以下命令更新你的 VPN 伺服器上的 [Libreswan](https://libreswan.org)（[更新日誌](https://github.com/libreswan/libreswan/blob/main/CHANGES) | [通知清單](https://lists.libreswan.org)）。\n\n```bash\nwget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n```\n\n<details>\n<summary>\n如果無法下載，請點這裡。\n</summary>\n\n你也可以使用 `curl` 下載：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/upg -o vpnup.sh && sudo sh vpnup.sh\n```\n\n或者，你也可以使用這些連結：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnupgrade.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnupgrade.sh\n```\n\n如果無法下載，打開 [vpnupgrade.sh](extras/vpnupgrade.sh)，然後點擊右側的 `Raw` 按鈕。按快捷鍵 `Ctrl/Cmd+A` 全選，`Ctrl/Cmd+C` 複製，然後貼上到你喜歡的編輯器。\n</details>\n\n目前支援的 Libreswan 最新版本是 `5.3`。查看已安裝版本：`ipsec --version`。\n\n**註：** `xl2tpd` 可以使用系統的套件管理器進行更新，例如 Ubuntu/Debian 上的 `apt-get`。\n\n## 管理 VPN 使用者\n\n請參見[管理 VPN 使用者](docs/manage-users-zh.md)（簡體中文）。\n\n- [使用輔助腳本管理 VPN 使用者](docs/manage-users-zh.md#使用辅助脚本管理-vpn-用户)\n- [查看 VPN 使用者](docs/manage-users-zh.md#查看-vpn-用户)\n- [查看或變更 IPsec PSK](docs/manage-users-zh.md#查看或更改-ipsec-psk)\n- [手動管理 VPN 使用者](docs/manage-users-zh.md#手动管理-vpn-用户)\n\n## 進階用法\n\n請參見[進階用法](docs/advanced-usage-zh.md)（簡體中文）。\n\n- [使用其他 DNS 伺服器](docs/advanced-usage-zh.md#使用其他的-dns-服务器)\n- [網域名稱與變更伺服器 IP](docs/advanced-usage-zh.md#域名和更改服务器-ip)\n- [僅限 IKEv2 的 VPN](docs/advanced-usage-zh.md#仅限-ikev2-的-vpn)\n- [VPN 內網 IP 與流量](docs/advanced-usage-zh.md#vpn-内网-ip-和流量)\n- [指定 VPN 伺服器的公有 IP](docs/advanced-usage-zh.md#指定-vpn-服务器的公有-ip)\n- [自訂 VPN 子網](docs/advanced-usage-zh.md#自定义-vpn-子网)\n- [IPv6 支援](docs/advanced-usage-zh.md#ipv6-支持)\n- [轉發連接埠到 VPN 客戶端](docs/advanced-usage-zh.md#转发端口到-vpn-客户端)\n- [VPN 分流](docs/advanced-usage-zh.md#vpn-分流)\n- [存取 VPN 伺服器的網段](docs/advanced-usage-zh.md#访问-vpn-服务器的网段)\n- [VPN 伺服器網段存取 VPN 客戶端](docs/advanced-usage-zh.md#vpn-服务器网段访问-vpn-客户端)\n- [變更 IPTables 規則](docs/advanced-usage-zh.md#更改-iptables-规则)\n- [部署 Google BBR 壅塞控制](docs/advanced-usage-zh.md#部署-google-bbr-拥塞控制)\n\n## 移除 VPN\n\n要移除 IPsec VPN，執行[輔助腳本](extras/vpnuninstall.sh)：\n\n**警告：** 此輔助腳本將從你的伺服器中刪除 IPsec VPN。所有 VPN 設定將被**永久刪除**，並且 Libreswan 和 xl2tpd 將被移除。此操作**無法復原**！\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\n如果無法下載，請點這裡。\n</summary>\n\n你也可以使用 `curl` 下載：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\n或者，你也可以使用這些連結：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\n更多資訊請參見[移除 VPN](docs/uninstall-zh.md)。\n\n## 問題與回饋\n\n- 如果你對本專案有建議，請提交一個[改進建議](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)，或歡迎提交 [Pull request](https://github.com/hwdsl2/setup-ipsec-vpn/pulls)。\n- 如果你發現可重現的程式漏洞，請為 [IPsec VPN](https://github.com/libreswan/libreswan/issues?q=is%3Aissue) 或 [VPN 腳本](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)提交錯誤回報。\n- 有問題想提問？請先搜尋[既有的 issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue) 以及[這個 Gist](https://gist.github.com/hwdsl2/9030462#comments) 和[我的部落格](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#disqus_thread)上已有的留言。\n- VPN 相關問題可在 [Libreswan](https://lists.libreswan.org) 或 [strongSwan](https://lists.strongswan.org) 郵件列表提問，或參考以下網站：[[1]](https://libreswan.org/wiki/Main_Page) [[2]](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_virtual_private_networks) [[3]](https://wiki.strongswan.org/projects/strongswan/wiki/UserDocumentation) [[4]](https://wiki.gentoo.org/wiki/IPsec_L2TP_VPN_server) [[5]](https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup)。\n\n## 授權條款\n\n版權所有 (C) 2014-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n基於 [Thomas Sarlandie 的工作](https://github.com/sarfata/voodooprivacy)（版權所有 2012）\n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n此專案採用 [Creative Commons 姓名標示-相同方式分享 3.0](http://creativecommons.org/licenses/by-sa/3.0/) 授權條款。   \n必須署名：請在任何衍生作品中包含我的名字，並且讓我知道你是如何改進它的！\n"
  },
  {
    "path": "README-zh.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [日本語](README-ja.md) | [Русский](README-ru.md)\n\n# IPsec VPN 服务器一键安装脚本\n\n[![Build Status](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md)\n\n使用 Linux 脚本一键快速搭建自己的 IPsec VPN 服务器。支持 IPsec/L2TP, Cisco IPsec 和 IKEv2 协议。\n\nIPsec VPN 可以加密你的网络流量，以防止在通过因特网传送时，你和 VPN 服务器之间的任何人对你的数据的未经授权的访问。在使用不安全的网络时，这是特别有用的，例如在咖啡厅，机场或旅馆房间。\n\n我们将使用 [Libreswan](https://libreswan.org/) 作为 IPsec 服务器，以及 [xl2tpd](https://github.com/xelerance/xl2tpd) 作为 L2TP 提供者。\n\n**[&raquo; :book: Book: Privacy Tools in the Age of AI](docs/vpn-book-zh.md) &nbsp;[搭建自己的 VPN 服务器](docs/vpn-book-zh.md)**\n\n## 快速开始\n\n首先，在你的 Linux 服务器\\* 上安装 Ubuntu, Debian 或者 CentOS。\n\n使用以下命令快速搭建 IPsec VPN 服务器：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n你的 VPN 登录凭证将会被自动随机生成，并在安装完成后显示。\n\n**可选：** 在同一台服务器上安装 [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-zh.md) 和/或 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh.md)。\n\n<details>\n<summary>\n查看脚本的示例输出（终端记录）。\n</summary>\n\n**注：** 此终端记录仅用于演示目的。该记录中的 VPN 凭据 **无效**。\n\n<p align=\"center\"><img src=\"docs/images/script-demo.svg\"></p>\n</details>\n<details>\n<summary>\n如果无法下载，请点这里。\n</summary>\n\n你也可以使用 `curl` 下载：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net -o vpn.sh && sudo sh vpn.sh\n```\n\n或者，你也可以使用这些链接：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\n如果无法下载，打开 [vpnsetup.sh](vpnsetup.sh)，然后点击右边的 `Raw` 按钮。按快捷键 `Ctrl/Cmd+A` 全选，`Ctrl/Cmd+C` 复制，然后粘贴到你喜欢的编辑器。\n</details>\n\n另外，你也可以使用预构建的 [Docker 镜像](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md)。如需了解其它选项以及客户端配置，请继续阅读以下部分。\n\n\\* 一个云服务器，虚拟专用服务器 (VPS) 或者专用服务器。\n\n## 功能特性\n\n- 全自动的 IPsec VPN 服务器配置，无需用户输入\n- 支持具有强大和快速加密算法（例如 AES-GCM）的 IKEv2 模式\n- 生成 VPN 配置文件以自动配置 iOS, macOS 和 Android 设备\n- 支持 Windows, macOS, iOS, Android, Chrome OS 和 Linux 客户端\n- 包括辅助脚本以管理 VPN 用户和证书\n\n## 系统要求\n\n一个云服务器，虚拟专用服务器 (VPS) 或者专用服务器，安装以下操作系统之一：\n\n- Ubuntu 24.04 或者 22.04\n- Debian 13、12 或者 11\n- CentOS Stream 10 或者 9\n- Rocky Linux 或者 AlmaLinux\n- Oracle Linux\n- Amazon Linux 2\n\n<details>\n<summary>\n其他受支持的 Linux 发行版。\n</summary>\n\n- Raspberry Pi OS (Raspbian)\n- Kali Linux\n- Alpine Linux\n- Red Hat Enterprise Linux (RHEL)\n</details>\n\n这也包括公共云服务中的 Linux 虚拟机，例如 [DigitalOcean](https://blog.ls20.com/digitalocean), [Vultr](https://blog.ls20.com/vultr), [Linode](https://blog.ls20.com/linode), [OVH](https://www.ovhcloud.com/en/vps/) 和 [Microsoft Azure](https://azure.microsoft.com)。公共云用户也可以使用[用户数据](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#vpnsetup)部署。\n\n使用以下按钮快速部署：\n\n[![Deploy to Linode](docs/images/linode-deploy-button.png)](https://cloud.linode.com/stackscripts/37239) &nbsp;[![Deploy to AWS](docs/images/aws-deploy-button.png)](aws/README-zh.md) &nbsp;[![Deploy to Azure](docs/images/azure-deploy-button.png)](azure/README-zh.md)\n\n[**&raquo; 我想建立并使用自己的 VPN，但是没有可用的服务器**](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#gettingavps)\n\n对于有外部防火墙的服务器（比如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），请为 VPN 打开 UDP 端口 500 和 4500。\n\n另外，你也可以使用预构建的 [Docker 镜像](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md)。高级用户可以在 [Raspberry Pi](https://www.raspberrypi.com) 上安装。[[1]](https://elasticbyte.net/posts/setting-up-a-native-cisco-ipsec-vpn-server-using-a-raspberry-pi/) [[2]](https://www.stewright.me/2018/07/create-a-raspberry-pi-vpn-server-using-l2tpipsec/)\n\n:warning: **不要** 在你的 PC 或者 Mac 上运行这些脚本！它们只能用在服务器上！\n\n## 安装说明\n\n首先，更新你的服务器：运行 `sudo apt-get update && sudo apt-get dist-upgrade` (Ubuntu/Debian) 或者 `sudo yum update` 并重启。这一步是可选的，但推荐。\n\n要安装 VPN，请从以下选项中选择一个：\n\n**选项 1:** 使用脚本随机生成的 VPN 登录凭证（完成后会显示）。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n**选项 2:** 编辑脚本并提供你自己的 VPN 登录凭证。\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nnano -w vpn.sh\n[替换为你自己的值： YOUR_IPSEC_PSK, YOUR_USERNAME 和 YOUR_PASSWORD]\nsudo sh vpn.sh\n```\n\n**注：** 一个安全的 IPsec PSK 应该至少包含 20 个随机字符。\n\n**选项 3:** 将你自己的 VPN 登录凭证定义为环境变量。\n\n```bash\n# 所有变量值必须用 '单引号' 括起来\n# *不要* 在值中使用这些字符：  \\ \" '\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_IPSEC_PSK='你的IPsec预共享密钥' \\\nVPN_USER='你的VPN用户名' \\\nVPN_PASSWORD='你的VPN密码' \\\nsh vpn.sh\n```\n\n你可以选择在同一台服务器上安装 [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-zh.md) 和/或 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh.md)。如果你的服务器运行 CentOS Stream, Rocky Linux 或 AlmaLinux，请先安装 OpenVPN/WireGuard，然后安装 IPsec VPN。\n\n<details>\n<summary>\n如果无法下载，请点这里。\n</summary>\n\n你也可以使用 `curl` 下载。例如：\n\n```bash\ncurl -fL https://get.vpnsetup.net -o vpn.sh\nsudo sh vpn.sh\n```\n\n或者，你也可以使用这些链接：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\n如果无法下载，打开 [vpnsetup.sh](vpnsetup.sh)，然后点击右边的 `Raw` 按钮。按快捷键 `Ctrl/Cmd+A` 全选，`Ctrl/Cmd+C` 复制，然后粘贴到你喜欢的编辑器。\n</details>\n<details>\n<summary>\n我需要安装较旧版本的 Libreswan 版本 4。\n</summary>\n\n一般建议使用最新的 [Libreswan](https://libreswan.org/) 版本 5，它是本项目的默认版本。但是，如果你想要安装较旧版本的 Libreswan 版本 4：\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_SWAN_VER=4.15 sh vpn.sh\n```\n\n**注：** 如果 Libreswan 版本 5 已经安装，你可能需要首先[卸载 VPN](docs/uninstall-zh.md)，然后安装 Libreswan 版本 4。或者，你也可以下载[升级脚本](#升级libreswan)，编辑它并指定 `SWAN_VER=4.15`，然后运行脚本。\n</details>\n\n## 自定义 VPN 选项\n\n### 使用其他的 DNS 服务器\n\n在 VPN 已连接时，客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。在安装 VPN 时，你可以为所有的 VPN 模式指定另外的 DNS 服务器。这是可选的。示例如下：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\n使用 `VPN_DNS_SRV1` 指定主 DNS 服务器，使用 `VPN_DNS_SRV2` 指定辅助 DNS 服务器（可选）。\n\n以下是一些流行的公共 DNS 提供商的列表，供你参考。\n\n| 提供商 | 主 DNS | 辅助 DNS | 注释 |\n| ----- | ------ | ------- | ---- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | 本项目默认 |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | 另见：[Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | 阻止恶意域 |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | 阻止网络钓鱼域，可配置。 |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | [域过滤器](https://cleanbrowsing.org/filters/)可用 |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | 按需选择 | 按需选择 | 广告拦截，免费套餐可用。[了解更多](https://nextdns.io/?from=bg25bwmp)。 |\n| [Control D](https://controld.com/free-dns) | 按需选择 | 按需选择 | 广告拦截，可配置。[了解更多](https://controld.com/free-dns)。 |\n\n如果你需要在安装 VPN 之后更改 DNS 服务器，参见[高级用法](docs/advanced-usage-zh.md)。\n\n**注：** 如果服务器上已经配置了 IKEv2，则以上变量对 IKEv2 模式无效。在这种情况下，如需自定义 IKEv2 选项（例如 DNS 服务器），你可以首先[移除 IKEv2](docs/ikev2-howto-zh.md#移除-ikev2)，然后运行 `sudo ikev2.sh` 重新配置。\n\n### 自定义 IKEv2 选项\n\n在安装 VPN 时，高级用户可以自定义 IKEv2 选项。这是可选的。\n\n<details open>\n<summary>\n选项 1: 在安装 VPN 时跳过 IKEv2，然后使用自定义选项配置 IKEv2。\n</summary>\n\n在安装 VPN 时，你可以跳过 IKEv2，仅安装 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式：\n\n```bash\nsudo VPN_SKIP_IKEV2=yes sh vpn.sh\n```\n\n（可选）如需为 VPN 客户端指定另外的 DNS 服务器，你可以定义 `VPN_DNS_SRV1` 和 `VPN_DNS_SRV2`（可选）。有关详细信息，参见[使用其他的 DNS 服务器](#使用其他的-dns-服务器)。\n\n然后运行 IKEv2 辅助脚本以使用自定义选项以交互方式配置 IKEv2:\n\n```bash\nsudo ikev2.sh\n```\n\n你可以自定义以下选项：VPN 服务器的域名，第一个客户端的名称和证书有效期，VPN 客户端的 DNS 服务器以及是否对客户端配置文件进行密码保护。\n\n**注：** 如果服务器上已经配置了 IKEv2，则 `VPN_SKIP_IKEV2` 变量无效。在这种情况下，如需自定义 IKEv2 选项，你可以首先[移除 IKEv2](docs/ikev2-howto-zh.md#移除-ikev2)，然后运行 `sudo ikev2.sh` 重新配置。\n</details>\n<details>\n<summary>\n选项 2: 使用环境变量自定义 IKEv2 选项。\n</summary>\n\n在安装 VPN 时，你可以指定一个域名作为 IKEv2 服务器地址。这是可选的。该域名必须是一个全称域名(FQDN)。示例如下：\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' sh vpn.sh\n```\n\n类似地，你可以指定第一个 IKEv2 客户端的名称。如果未指定，则使用默认值 `vpnclient`。\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' sh vpn.sh\n```\n\n在 VPN 已连接时，客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。你可以为所有的 VPN 模式指定另外的 DNS 服务器。示例如下：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\n默认情况下，导入 IKEv2 客户端配置时不需要密码。你可以选择使用随机密码保护客户端配置文件。\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes sh vpn.sh\n```\n</details>\n<details>\n<summary>\n供参考：IKEv1 和 IKEv2 参数列表。\n</summary>\n\n| IKEv1 参数\\* |默认值 |自定义（环境变量）\\*\\* |\n| ------------ | ---- | ----------------- |\n|服务器地址（DNS域名）| - |不能，但你可以使用 DNS 域名进行连接 |\n|服务器地址（公网IP）|自动检测 | VPN_PUBLIC_IP |\n| IPsec 预共享密钥 |自动生成 | VPN_IPSEC_PSK |\n| VPN 用户名 | vpnuser | VPN_USER |\n| VPN 密码 |自动生成 | VPN_PASSWORD |\n|客户端的 DNS 服务器 |Google Public DNS | VPN_DNS_SRV1, VPN_DNS_SRV2 |\n|跳过 IKEv2 安装 |no | VPN_SKIP_IKEV2=yes |\n\n\\* 这些 IKEv1 参数适用于 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式。   \n\\*\\* 在运行 vpn(setup).sh 时将这些定义为环境变量。\n\n| IKEv2 参数\\* |默认值 |自定义（环境变量）\\*\\* |自定义（交互式）\\*\\*\\* |\n| ----------- | ---- | ------------------ | ----------------- |\n|服务器地址（DNS域名）| - | VPN_DNS_NAME | ✅ |\n|服务器地址（公网IP）|自动检测 | VPN_PUBLIC_IP | ✅ |\n|第一个客户端的名称 | vpnclient | VPN_CLIENT_NAME | ✅ |\n|客户端的 DNS 服务器 |Google Public DNS | VPN_DNS_SRV1, VPN_DNS_SRV2 | ✅ |\n|保护客户端配置文件 |no | VPN_PROTECT_CONFIG=yes | ✅ |\n|启用/禁用 MOBIKE |如果系统支持则启用 | ❌ | ✅ |\n|客户端证书有效期 | 10 年（120 个月）| VPN_CLIENT_VALIDITY\\*\\*\\*\\* | ✅ |\n| CA 和服务器证书有效期 | 10 年（120 个月）| ❌ | ❌ |\n| CA 证书名称 | IKEv2 VPN CA | ❌ | ❌ |\n|证书密钥长度 | 3072 bits | ❌ | ❌ |\n\n\\* 这些 IKEv2 参数适用于 IKEv2 模式。   \n\\*\\* 在运行 vpn(setup).sh 时，或者在自动模式下配置 IKEv2 时 (`sudo ikev2.sh --auto`) 将这些定义为环境变量。   \n\\*\\*\\* 可以在交互式配置 IKEv2 期间自定义 (`sudo ikev2.sh`)。参见上面的选项 1。   \n\\*\\*\\*\\* 使用 `VPN_CLIENT_VALIDITY` 定义客户端证书的有效期（单位：月）。它必须是 1 到 120 之间的整数。\n\n除了这些参数，高级用户还可以在安装时[自定义 VPN 子网](docs/advanced-usage-zh.md#自定义-vpn-子网)。\n</details>\n\n## 下一步\n\n*其他语言版本: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [日本語](README-ja.md#次のステップ), [Русский](README-ru.md#следующие-шаги)。*\n\n配置你的计算机或其它设备使用 VPN。请参见：\n\n**[配置 IKEv2 VPN 客户端（推荐）](docs/ikev2-howto-zh.md)**\n\n**[配置 IPsec/L2TP VPN 客户端](docs/clients-zh.md)**\n\n**[配置 IPsec/XAuth (\"Cisco IPsec\") VPN 客户端](docs/clients-xauth-zh.md)**\n\n**阅读 [:book: VPN book](docs/vpn-book-zh.md) 以访问[额外内容](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)。**\n\n开始使用自己的专属 VPN! :sparkles::tada::rocket::sparkles:\n\n## 重要提示\n\n**Windows 用户** 对于 IPsec/L2TP 模式，在首次连接之前需要[修改注册表](docs/clients-zh.md#windows-错误-809)，以解决 VPN 服务器或客户端与 NAT（比如家用路由器）的兼容问题。\n\n同一个 VPN 账户可以在你的多个设备上使用。但是由于 IPsec/L2TP 的局限性，如果需要连接在同一个 NAT（比如家用路由器）后面的多个设备，你必须使用 [IKEv2](docs/ikev2-howto-zh.md) 或者 [IPsec/XAuth](docs/clients-xauth-zh.md) 模式。要查看或更改 VPN 用户账户，请参见[管理 VPN 用户](docs/manage-users-zh.md)。\n\n对于有外部防火墙的服务器（比如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），请为 VPN 打开 UDP 端口 500 和 4500。阿里云用户请参见 [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433)。\n\n在 VPN 已连接时，客户端配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。如果偏好其它的域名解析服务，请参见[高级用法](docs/advanced-usage-zh.md)。\n\n使用内核支持有助于提高 IPsec/L2TP 性能。它在所有[受支持的系统](#系统要求)上可用。Ubuntu 系统需要安装 `linux-modules-extra-$(uname -r)` 软件包并运行 `service xl2tpd restart`。\n\n这些脚本在更改现有的配置文件之前会先做备份，使用 `.old-日期-时间` 为文件名后缀。\n\n## 升级Libreswan\n\n使用以下命令更新你的 VPN 服务器上的 [Libreswan](https://libreswan.org)（[更新日志](https://github.com/libreswan/libreswan/blob/main/CHANGES) | [通知列表](https://lists.libreswan.org)）。\n\n```bash\nwget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n```\n\n<details>\n<summary>\n如果无法下载，请点这里。\n</summary>\n\n你也可以使用 `curl` 下载：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/upg -o vpnup.sh && sudo sh vpnup.sh\n```\n\n或者，你也可以使用这些链接：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnupgrade.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnupgrade.sh\n```\n\n如果无法下载，打开 [vpnupgrade.sh](extras/vpnupgrade.sh)，然后点击右边的 `Raw` 按钮。按快捷键 `Ctrl/Cmd+A` 全选，`Ctrl/Cmd+C` 复制，然后粘贴到你喜欢的编辑器。\n</details>\n\n当前支持的 Libreswan 最新版本是 `5.3`。查看已安装版本：`ipsec --version`。\n\n**注：** `xl2tpd` 可以使用系统的软件包管理器进行更新，例如 Ubuntu/Debian 上的 `apt-get`。\n\n## 管理 VPN 用户\n\n请参见[管理 VPN 用户](docs/manage-users-zh.md)。\n\n- [使用辅助脚本管理 VPN 用户](docs/manage-users-zh.md#使用辅助脚本管理-vpn-用户)\n- [查看 VPN 用户](docs/manage-users-zh.md#查看-vpn-用户)\n- [查看或更改 IPsec PSK](docs/manage-users-zh.md#查看或更改-ipsec-psk)\n- [手动管理 VPN 用户](docs/manage-users-zh.md#手动管理-vpn-用户)\n\n## 高级用法\n\n请参见[高级用法](docs/advanced-usage-zh.md)。\n\n- [使用其他的 DNS 服务器](docs/advanced-usage-zh.md#使用其他的-dns-服务器)\n- [域名和更改服务器 IP](docs/advanced-usage-zh.md#域名和更改服务器-ip)\n- [仅限 IKEv2 的 VPN](docs/advanced-usage-zh.md#仅限-ikev2-的-vpn)\n- [VPN 内网 IP 和流量](docs/advanced-usage-zh.md#vpn-内网-ip-和流量)\n- [指定 VPN 服务器的公有 IP](docs/advanced-usage-zh.md#指定-vpn-服务器的公有-ip)\n- [自定义 VPN 子网](docs/advanced-usage-zh.md#自定义-vpn-子网)\n- [IPv6 支持](docs/advanced-usage-zh.md#ipv6-支持)\n- [转发端口到 VPN 客户端](docs/advanced-usage-zh.md#转发端口到-vpn-客户端)\n- [VPN 分流](docs/advanced-usage-zh.md#vpn-分流)\n- [访问 VPN 服务器的网段](docs/advanced-usage-zh.md#访问-vpn-服务器的网段)\n- [VPN 服务器网段访问 VPN 客户端](docs/advanced-usage-zh.md#vpn-服务器网段访问-vpn-客户端)\n- [更改 IPTables 规则](docs/advanced-usage-zh.md#更改-iptables-规则)\n- [部署 Google BBR 拥塞控制](docs/advanced-usage-zh.md#部署-google-bbr-拥塞控制)\n\n## 卸载 VPN\n\n要卸载 IPsec VPN，运行[辅助脚本](extras/vpnuninstall.sh)：\n\n**警告：** 此辅助脚本将从你的服务器中删除 IPsec VPN。所有的 VPN 配置将被**永久删除**，并且 Libreswan 和 xl2tpd 将被移除。此操作**不可撤销**！\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\n如果无法下载，请点这里。\n</summary>\n\n你也可以使用 `curl` 下载：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\n或者，你也可以使用这些链接：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\n更多信息请参见[卸载 VPN](docs/uninstall-zh.md)。\n\n## 问题和反馈\n\n- 如果你有对本项目的建议，请提交一个[改进建议](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)，或者欢迎提交 [Pull request](https://github.com/hwdsl2/setup-ipsec-vpn/pulls)。\n- 如果你发现了一个可重复的程序漏洞，请为 [IPsec VPN](https://github.com/libreswan/libreswan/issues?q=is%3Aissue) 或者 [VPN 脚本](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose)提交一个错误报告。\n- 有问题需要提问？请先搜索[已有的 issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue) 以及在[这个 Gist](https://gist.github.com/hwdsl2/9030462#comments) 和[我的博客](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#disqus_thread)上已有的留言。\n- VPN 的相关问题可在 [Libreswan](https://lists.libreswan.org) 或 [strongSwan](https://lists.strongswan.org) 邮件列表提问，或者参考这些网站：[[1]](https://libreswan.org/wiki/Main_Page) [[2]](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_virtual_private_networks) [[3]](https://wiki.strongswan.org/projects/strongswan/wiki/UserDocumentation) [[4]](https://wiki.gentoo.org/wiki/IPsec_L2TP_VPN_server) [[5]](https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup)。\n\n## 授权协议\n\n版权所有 (C) 2014-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n基于 [Thomas Sarlandie 的工作](https://github.com/sarfata/voodooprivacy) (版权所有 2012)\n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n这个项目是以[知识共享署名-相同方式共享3.0](http://creativecommons.org/licenses/by-sa/3.0/) 许可协议授权。   \n必须署名： 请包括我的名字在任何衍生产品，并且让我知道你是如何改善它的！\n"
  },
  {
    "path": "README.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [日本語](README-ja.md) | [Русский](README-ru.md)\n\n# IPsec VPN Server Auto Setup Scripts\n\n[![Build Status](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml/badge.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/actions/workflows/main.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/setup-ipsec-vpn/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server)\n\nSet up your own IPsec VPN server in just a few minutes, with IPsec/L2TP, Cisco IPsec and IKEv2.\n\nAn IPsec VPN encrypts your network traffic, so that nobody between you and the VPN server can eavesdrop on your data as it travels via the Internet. This is especially useful when using unsecured networks, e.g. at coffee shops, airports or hotel rooms.\n\nWe will use [Libreswan](https://libreswan.org/) as the IPsec server, and [xl2tpd](https://github.com/xelerance/xl2tpd) as the L2TP provider.\n\n**[&raquo; :book: Book: Privacy Tools in the Age of AI](docs/vpn-book.md) &nbsp;[Build Your Own VPN Server](docs/vpn-book.md)**\n\n## Quick start\n\nFirst, prepare your Linux server\\* with an install of Ubuntu, Debian or CentOS.\n\nUse this one-liner to set up an IPsec VPN server:\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\nYour VPN login details will be randomly generated, and displayed when finished.\n\n**Optional:** Install [WireGuard](https://github.com/hwdsl2/wireguard-install) and/or [OpenVPN](https://github.com/hwdsl2/openvpn-install) on the same server.\n\n<details>\n<summary>\nSee the script in action (terminal recording).\n</summary>\n\n**Note:** This recording is for demo purposes only. VPN credentials in this recording are **NOT** valid.\n\n<p align=\"center\"><img src=\"docs/images/script-demo.svg\"></p>\n</details>\n<details>\n<summary>\nClick here if you are unable to download.\n</summary>\n\nYou may also use `curl` to download:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net -o vpn.sh && sudo sh vpn.sh\n```\n\nAlternative setup URLs:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nIf you are unable to download, open [vpnsetup.sh](vpnsetup.sh), then click the `Raw` button on the right. Press `Ctrl/Cmd+A` to select all, `Ctrl/Cmd+C` to copy, then paste into your favorite editor.\n</details>\n\nA pre-built [Docker image](https://github.com/hwdsl2/docker-ipsec-vpn-server) is also available. For other options and client setup, read the sections below.\n\n\\* A cloud server, virtual private server (VPS) or dedicated server.\n\n## Features\n\n- Fully automated IPsec VPN server setup, no user input needed\n- Supports IKEv2 with strong and fast ciphers (e.g. AES-GCM)\n- Generates VPN profiles to auto-configure iOS, macOS and Android devices\n- Supports Windows, macOS, iOS, Android, Chrome OS and Linux as VPN clients\n- Includes helper scripts to manage VPN users and certificates\n\n## Requirements\n\nA cloud server, virtual private server (VPS) or dedicated server, with an install of:\n\n- Ubuntu 24.04 or 22.04\n- Debian 13, 12 or 11\n- CentOS Stream 10 or 9\n- Rocky Linux or AlmaLinux\n- Oracle Linux\n- Amazon Linux 2\n\n<details>\n<summary>\nOther supported Linux distributions.\n</summary>\n\n- Raspberry Pi OS (Raspbian)\n- Kali Linux\n- Alpine Linux\n- Red Hat Enterprise Linux (RHEL)\n</details>\n\nThis also includes Linux VMs in public clouds, such as [DigitalOcean](https://blog.ls20.com/digitalocean), [Vultr](https://blog.ls20.com/vultr), [Linode](https://blog.ls20.com/linode), [OVH](https://www.ovhcloud.com/en/vps/) and [Microsoft Azure](https://azure.microsoft.com). Public cloud users can also deploy using [user data](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#vpnsetup).\n\nQuick deploy to:\n\n[![Deploy to Linode](docs/images/linode-deploy-button.png)](https://cloud.linode.com/stackscripts/37239) &nbsp;[![Deploy to AWS](docs/images/aws-deploy-button.png)](aws/README.md) &nbsp;[![Deploy to Azure](docs/images/azure-deploy-button.png)](azure/README.md)\n\n[**&raquo; I want to run my own VPN but don't have a server for that**](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#gettingavps)\n\nFor servers with an external firewall (e.g. [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)), open UDP ports 500 and 4500 for the VPN.\n\nA pre-built [Docker image](https://github.com/hwdsl2/docker-ipsec-vpn-server) is also available. Advanced users can install on a [Raspberry Pi](https://www.raspberrypi.com). [[1]](https://elasticbyte.net/posts/setting-up-a-native-cisco-ipsec-vpn-server-using-a-raspberry-pi/) [[2]](https://www.stewright.me/2018/07/create-a-raspberry-pi-vpn-server-using-l2tpipsec/)\n\n:warning: **DO NOT** run these scripts on your PC or Mac! They should only be used on a server!\n\n## Installation\n\nFirst, update your server with `sudo apt-get update && sudo apt-get dist-upgrade` (Ubuntu/Debian) or `sudo yum update` and reboot. This is optional, but recommended.\n\nTo install the VPN, please choose one of the following options:\n\n**Option 1:** Have the script generate random VPN credentials for you (will be displayed when finished).\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh && sudo sh vpn.sh\n```\n\n**Option 2:** Edit the script and provide your own VPN credentials.\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nnano -w vpn.sh\n[Replace with your own values: YOUR_IPSEC_PSK, YOUR_USERNAME and YOUR_PASSWORD]\nsudo sh vpn.sh\n```\n\n**Note:** A secure IPsec PSK should consist of at least 20 random characters.\n\n**Option 3:** Define your VPN credentials as environment variables.\n\n```bash\n# All values MUST be placed inside 'single quotes'\n# DO NOT use these special characters within values: \\ \" '\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_IPSEC_PSK='your_ipsec_pre_shared_key' \\\nVPN_USER='your_vpn_username' \\\nVPN_PASSWORD='your_vpn_password' \\\nsh vpn.sh\n```\n\nYou may optionally install [WireGuard](https://github.com/hwdsl2/wireguard-install) and/or [OpenVPN](https://github.com/hwdsl2/openvpn-install) on the same server. If your server runs CentOS Stream, Rocky Linux or AlmaLinux, first install OpenVPN/WireGuard, then install the IPsec VPN.\n\n<details>\n<summary>\nClick here if you are unable to download.\n</summary>\n\nYou may also use `curl` to download. For example:\n\n```bash\ncurl -fL https://get.vpnsetup.net -o vpn.sh\nsudo sh vpn.sh\n```\n\nAlternative setup URLs:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/vpnsetup.sh\n```\n\nIf you are unable to download, open [vpnsetup.sh](vpnsetup.sh), then click the `Raw` button on the right. Press `Ctrl/Cmd+A` to select all, `Ctrl/Cmd+C` to copy, then paste into your favorite editor.\n</details>\n<details>\n<summary>\nI want to install the older Libreswan version 4.\n</summary>\n\nIt is generally recommended to use the latest [Libreswan](https://libreswan.org/) version 5, which is the default version in this project. However, if you want to install the older Libreswan version 4:\n\n```bash\nwget https://get.vpnsetup.net -O vpn.sh\nsudo VPN_SWAN_VER=4.15 sh vpn.sh\n```\n\n**Note:** If Libreswan version 5 is already installed, you may need to first [Uninstall the VPN](docs/uninstall.md) before installing Libreswan version 4. Alternatively, download the [update script](#upgrade-libreswan), edit it to specify `SWAN_VER=4.15`, then run the script.\n</details>\n\n## Customize VPN options\n\n### Use alternative DNS servers\n\nBy default, clients are set to use [Google Public DNS](https://developers.google.com/speed/public-dns/) when the VPN is active. When installing the VPN, you may optionally specify custom DNS server(s) for all VPN modes. Example:\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\nUse `VPN_DNS_SRV1` to specify the primary DNS server, and `VPN_DNS_SRV2` to specify the secondary DNS server (optional).\n\nBelow is a list of some popular public DNS providers for your reference.\n\n| Provider | Primary DNS | Secondary DNS | Notes |\n| -------- | ----------- | ------------- | ----- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | Default in this project |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | See also: [Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | Blocks malicious domains |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | Blocks phishing domains, configurable. |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | [Domain filters](https://cleanbrowsing.org/filters/) available |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | Varies | Varies | Ad blocking, free tier available. [Learn more](https://nextdns.io/?from=bg25bwmp). |\n| [Control D](https://controld.com/free-dns) | Varies | Varies | Ad blocking, configurable. [Learn more](https://controld.com/free-dns). |\n\nIf you need to change DNS servers after VPN setup, see [Advanced usage](docs/advanced-usage.md).\n\n**Note:** If IKEv2 is already set up on the server, the variables above have no effect for IKEv2 mode. In that case, to customize IKEv2 options such as DNS servers, you can first [remove IKEv2](docs/ikev2-howto.md#remove-ikev2), then set it up again using `sudo ikev2.sh`.\n\n### Customize IKEv2 options\n\nWhen installing the VPN, advanced users can optionally customize IKEv2 options.\n\n<details open>\n<summary>\nOption 1: Skip IKEv2 during VPN setup, then set up IKEv2 using custom options.\n</summary>\n\nWhen installing the VPN, you can skip IKEv2 and only install the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes:\n\n```bash\nsudo VPN_SKIP_IKEV2=yes sh vpn.sh\n```\n\n(Optional) If you want to specify custom DNS server(s) for VPN clients, define `VPN_DNS_SRV1` and optionally `VPN_DNS_SRV2`. See [Use alternative DNS servers](#use-alternative-dns-servers) for details.\n\nAfter that, run the IKEv2 helper script to set up IKEv2 interactively using custom options:\n\n```bash\nsudo ikev2.sh\n```\n\nYou can customize the following options: VPN server's DNS name, name and validity period of the first client, DNS server for VPN clients and whether to password protect client config files.\n\n**Note:** The `VPN_SKIP_IKEV2` variable has no effect if IKEv2 is already set up on the server. In that case, to customize IKEv2 options, you can first [remove IKEv2](docs/ikev2-howto.md#remove-ikev2), then set it up again using `sudo ikev2.sh`.\n</details>\n<details>\n<summary>\nOption 2: Customize IKEv2 options using environment variables.\n</summary>\n\nWhen installing the VPN, you can optionally specify a DNS name for the IKEv2 server address. The DNS name must be a fully qualified domain name (FQDN). Example:\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' sh vpn.sh\n```\n\nSimilarly, you may specify a name for the first IKEv2 client. The default is `vpnclient` if not specified.\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' sh vpn.sh\n```\n\nBy default, clients are set to use [Google Public DNS](https://developers.google.com/speed/public-dns/) when the VPN is active. You may specify custom DNS server(s) for all VPN modes. Example:\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 sh vpn.sh\n```\n\nBy default, no password is required when importing IKEv2 client configuration. You can choose to protect client config files using a random password.\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes sh vpn.sh\n```\n</details>\n<details>\n<summary>\nFor reference: List of IKEv1 and IKEv2 parameters.\n</summary>\n\n| IKEv1 parameter\\*           | Default value         | Customize (env variable)\\*\\*             |\n| --------------------------- | --------------------- | ---------------------------------------- |\n| Server address (DNS name)   | -                     | No, but you can connect using a DNS name |\n| Server address (public IP)  | Auto detect           | VPN_PUBLIC_IP                            |\n| IPsec pre-shared key        | Auto generate         | VPN_IPSEC_PSK                            |\n| VPN username                | vpnuser               | VPN_USER                                 |\n| VPN password                | Auto generate         | VPN_PASSWORD                             |\n| DNS servers for clients     | Google Public DNS     | VPN_DNS_SRV1, VPN_DNS_SRV2               |\n| Skip IKEv2 setup            | no                    | VPN_SKIP_IKEV2=yes                       |\n\n\\* These IKEv1 parameters are for IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.   \n\\*\\* Define these as environment variables when running vpn(setup).sh.\n\n| IKEv2 parameter\\*           | Default value         | Customize (env variable)\\*\\* | Customize (interactive)\\*\\*\\* |\n| --------------------------- | --------------------- | ---------------------------- | ----------------------------- |\n| Server address (DNS name)   | -                     | VPN_DNS_NAME                 | ✅                            |\n| Server address (public IP)  | Auto detect           | VPN_PUBLIC_IP                | ✅                            |\n| Name of first client        | vpnclient             | VPN_CLIENT_NAME              | ✅                            |\n| DNS servers for clients     | Google Public DNS     | VPN_DNS_SRV1, VPN_DNS_SRV2   | ✅                            |\n| Protect client config files | no                    | VPN_PROTECT_CONFIG=yes       | ✅                            |\n| Enable/Disable MOBIKE       | Enable if supported   | ❌                           | ✅                            |\n| Client cert validity        | 10 years (120 months) | VPN_CLIENT_VALIDITY\\*\\*\\*\\*  | ✅                            |\n| CA & server cert validity   | 10 years (120 months) | ❌                           | ❌                            |\n| CA certificate name         | IKEv2 VPN CA          | ❌                           | ❌                            |\n| Certificate key size        | 3072 bits             | ❌                           | ❌                            |\n\n\\* These IKEv2 parameters are for IKEv2 mode.   \n\\*\\* Define these as environment variables when running vpn(setup).sh, or when setting up IKEv2 in auto mode (`sudo ikev2.sh --auto`).   \n\\*\\*\\* Can be customized during interactive IKEv2 setup (`sudo ikev2.sh`). Refer to option 1 above.   \n\\*\\*\\*\\* Use `VPN_CLIENT_VALIDITY` to specify the client cert validity period in months. Must be an integer between 1 and 120.\n\nIn addition to these parameters, advanced users can also [customize VPN subnets](docs/advanced-usage.md#customize-vpn-subnets) during VPN setup.\n</details>\n\n## Next steps\n\n*Read this in other languages: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [日本語](README-ja.md#次のステップ), [Русский](README-ru.md#следующие-шаги).*\n\nGet your computer or device to use the VPN. Please refer to:\n\n**[Configure IKEv2 VPN Clients (recommended)](docs/ikev2-howto.md)**\n\n**[Configure IPsec/L2TP VPN Clients](docs/clients.md)**\n\n**[Configure IPsec/XAuth (\"Cisco IPsec\") VPN Clients](docs/clients-xauth.md)**\n\n**Read [:book: VPN book](docs/vpn-book.md) to access [extra content](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J).**\n\nEnjoy your very own VPN! :sparkles::tada::rocket::sparkles:\n\n## Important notes\n\n**Windows users**: For IPsec/L2TP mode, a [one-time registry change](docs/clients.md#windows-error-809) is required if the VPN server or client is behind NAT (e.g. home router).\n\nThe same VPN account can be used by your multiple devices. However, due to an IPsec/L2TP limitation, if you wish to connect multiple devices from behind the same NAT (e.g. home router), you must use [IKEv2](docs/ikev2-howto.md) or [IPsec/XAuth](docs/clients-xauth.md) mode. To view or update VPN user accounts, see [Manage VPN users](docs/manage-users.md).\n\nFor servers with an external firewall (e.g. [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)), open UDP ports 500 and 4500 for the VPN. Aliyun users, see [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433).\n\nClients are set to use [Google Public DNS](https://developers.google.com/speed/public-dns/) when the VPN is active. If another DNS provider is preferred, see [Advanced usage](docs/advanced-usage.md).\n\nUsing kernel support could improve IPsec/L2TP performance. It is available on [all supported OS](#requirements). Ubuntu users should install the `linux-modules-extra-$(uname -r)` package and run `service xl2tpd restart`.\n\nThe scripts will backup existing config files before making changes, with `.old-date-time` suffix.\n\n## Upgrade Libreswan\n\nUse this one-liner to update [Libreswan](https://libreswan.org) ([changelog](https://github.com/libreswan/libreswan/blob/main/CHANGES) | [announce](https://lists.libreswan.org)) on your VPN server.\n\n```bash\nwget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n```\n\n<details>\n<summary>\nClick here if you are unable to download.\n</summary>\n\nYou may also use `curl` to download:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/upg -o vpnup.sh && sudo sh vpnup.sh\n```\n\nAlternative update URLs:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnupgrade.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnupgrade.sh\n```\n\nIf you are unable to download, open [vpnupgrade.sh](extras/vpnupgrade.sh), then click the `Raw` button on the right. Press `Ctrl/Cmd+A` to select all, `Ctrl/Cmd+C` to copy, then paste into your favorite editor.\n</details>\n\nThe latest supported Libreswan version is `5.3`. Check installed version: `ipsec --version`.\n\n**Note:** `xl2tpd` can be updated using your system's package manager, such as `apt-get` on Ubuntu/Debian.\n\n## Manage VPN users\n\nSee [Manage VPN users](docs/manage-users.md).\n\n- [Manage VPN users using helper scripts](docs/manage-users.md#manage-vpn-users-using-helper-scripts)\n- [View VPN users](docs/manage-users.md#view-vpn-users)\n- [View or update the IPsec PSK](docs/manage-users.md#view-or-update-the-ipsec-psk)\n- [Manually manage VPN users](docs/manage-users.md#manually-manage-vpn-users)\n\n## Advanced usage\n\nSee [Advanced usage](docs/advanced-usage.md).\n\n- [Use alternative DNS servers](docs/advanced-usage.md#use-alternative-dns-servers)\n- [DNS name and server IP changes](docs/advanced-usage.md#dns-name-and-server-ip-changes)\n- [IKEv2-only VPN](docs/advanced-usage.md#ikev2-only-vpn)\n- [Internal VPN IPs and traffic](docs/advanced-usage.md#internal-vpn-ips-and-traffic)\n- [Specify VPN server's public IP](docs/advanced-usage.md#specify-vpn-servers-public-ip)\n- [Customize VPN subnets](docs/advanced-usage.md#customize-vpn-subnets)\n- [IPv6 support](docs/advanced-usage.md#ipv6-support)\n- [Port forwarding to VPN clients](docs/advanced-usage.md#port-forwarding-to-vpn-clients)\n- [Split tunneling](docs/advanced-usage.md#split-tunneling)\n- [Access VPN server's subnet](docs/advanced-usage.md#access-vpn-servers-subnet)\n- [Access VPN clients from server's subnet](docs/advanced-usage.md#access-vpn-clients-from-servers-subnet)\n- [Modify IPTables rules](docs/advanced-usage.md#modify-iptables-rules)\n- [Deploy Google BBR congestion control](docs/advanced-usage.md#deploy-google-bbr-congestion-control)\n\n## Uninstall the VPN\n\nTo uninstall IPsec VPN, run the [helper script](extras/vpnuninstall.sh):\n\n**Warning:** This helper script will remove IPsec VPN from your server. All VPN configuration will be **permanently deleted**, and Libreswan and xl2tpd will be removed. This **cannot be undone**!\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\nClick here if you are unable to download.\n</summary>\n\nYou may also use `curl` to download:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\nAlternative script URLs:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\nFor more information, see [Uninstall the VPN](docs/uninstall.md).\n\n## Feedback & Questions\n\n- Have a suggestion for this project? Open an [Enhancement request](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose). [Pull requests](https://github.com/hwdsl2/setup-ipsec-vpn/pulls) are also welcome.\n- If you found a reproducible bug, open a bug report for the [IPsec VPN](https://github.com/libreswan/libreswan/issues?q=is%3Aissue) or for the [VPN scripts](https://github.com/hwdsl2/setup-ipsec-vpn/issues/new/choose).\n- Got a question? Please first search [existing issues](https://github.com/hwdsl2/setup-ipsec-vpn/issues?q=is%3Aissue) and comments [in this Gist](https://gist.github.com/hwdsl2/9030462#comments) and [on my blog](https://blog.ls20.com/ipsec-l2tp-vpn-auto-setup-for-ubuntu-12-04-on-amazon-ec2/#disqus_thread).\n- Ask VPN related questions on the [Libreswan](https://lists.libreswan.org) or [strongSwan](https://lists.strongswan.org) mailing list, or read these wikis: [[1]](https://libreswan.org/wiki/Main_Page) [[2]](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-securing_virtual_private_networks) [[3]](https://wiki.strongswan.org/projects/strongswan/wiki/UserDocumentation) [[4]](https://wiki.gentoo.org/wiki/IPsec_L2TP_VPN_server) [[5]](https://wiki.archlinux.org/index.php/Openswan_L2TP/IPsec_VPN_client_setup).\n\n## License\n\nCopyright (C) 2014-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \nBased on [the work of Thomas Sarlandie](https://github.com/sarfata/voodooprivacy) (Copyright 2012)\n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nThis work is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nAttribution required: please include my name in any derivative and let me know how you have improved it!\n"
  },
  {
    "path": "aws/README-zh.md",
    "content": "[English](README.md) | [中文](README-zh.md)\n\n# 使用 CloudFormation 在 Amazon EC2 上部署\n\n使用这个模板，你可以在 Amazon Elastic Compute Cloud（Amazon EC2）上快速搭建一个 IPsec VPN 服务器。在继续之前，请参见 EC2 [定价细节](https://aws.amazon.com/cn/ec2/pricing/on-demand/)。在部署中使用 `t2.micro` 或 `t3.micro` 服务器实例可能符合 [AWS 免费套餐](https://aws.amazon.com/cn/free/)的资格。\n\n可用的自定义参数：\n\n- Amazon EC2 实例类型\n> <details><summary><strong>注：</strong> 在某些 AWS 区域中，此模版提供的某些实例类型可能不可用。（点击查看详情）\n> </summary>\n> \n> 比如 `m5a.large` 可能无法在 `ap-east-1` 区域部署（仅为假设）。在此情况下，你会在部署过程中遇到此错误：`The requested configuration is currently not supported. Please check the documentation for supported configurations`。新开放的 AWS 区域更容易出现此问题，因为它们提供的实例类型较少。如需了解更多关于实例可用性的信息，请参见 [https://instances.vantage.sh/](https://instances.vantage.sh/)。</details>\n\n- VPN 服务器的操作系统（Ubuntu **24.04**/22.04, Debian 12/11, Amazon Linux 2）\n- 你的 VPN 用户名\n- 你的 VPN 密码\n- 你的 VPN IPsec PSK（预共享密钥）\n\n> **注：** 一个安全的 IPsec PSK 应该至少包含 20 个随机字符。\\*不要\\* 在值中使用这些字符： `\\ \" '`\n\n确保使用 **AWS 账户根用户** 或者有 **管理员权限** 的 **IAM 用户** 部署此模板。\n\n右键单击这个 [**模板链接**](https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/aws/cloudformation-template-ipsec.json)，并将它保存到你的计算机上的一个新文件。然后在 [\"创建堆栈\" 向导](https://console.aws.amazon.com/cloudformation/home#/stacks/new)中将其作为模板源上传。要指定一个 AWS 区域，你可以使用导航栏上你的帐户信息右侧的选择器。继续创建堆栈，在最后一步你需要确认（选择）此模板可以创建 IAM 资源。\n\n当你在最后一步中点击 \"create stack\" 之后，请等待堆栈创建和 VPN 安装完成，可能需要最多 15 分钟。一旦堆栈的部署状态变成 **\"CREATE_COMPLETE\"** ，你就可以连接到 VPN 服务器了。单击 **Outputs** 选项卡以查看你的 VPN 登录信息，然后继续下一步：[配置 VPN 客户端](../README-zh.md#下一步)。\n\n点击下面的图标开始：\n\n[![Launch stack](images/cloudformation-launch-stack-button.png)](https://console.aws.amazon.com/cloudformation/home#/stacks/new)\n\n## 延伸阅读\n\n了解有关此 CloudFormation 模板设计的更多信息：\n\n[Introduction to AWS CloudFormation with Example Project Walk-Through](https://nixsanctuary.com/introduction-to-aws-cloudformation-with-example-project-walk-through/)\n\n## 屏幕截图\n\n<details>\n<summary>\n点这里查看屏幕截图。\n</summary>\n\n![上传模板](images/upload-the-template.png)\n![指定参数](images/specify-parameters.png)\n![确认 IAM](images/confirm-iam.png)\n![显示密钥](images/show-key.png)\n</details>\n\n## 常见问题\n\n<details>\n<summary>\n如何在部署结束后提取 IKEv2 连接配置文件？\n</summary>\n\n部署完成之后，生成的 IKEv2 配置文件已经被上传到了一个新创建的 AWS Simple Storage Service (S3) 储存桶。下载配置文件的链接可以在 **Outputs** 页面下找到。\n\n点击下载链接下载名为 `profiles.zip` 的压缩包文件。解压密码为**你在创建堆栈时输入的 VPN 连接密码**。\n\n值得注意的是，IKEv2 配置文件的下载链接将会在**1天后过期**，从堆栈部署完成时算起。如果你将堆栈删除，存放 IKEv2 配置文件的储存桶不会被自动删除。\n\n关于如何在 IKEv2 模式下配置你的客户端，请参见: [IKEv2 VPN 配置和使用指南](../docs/ikev2-howto-zh.md)。\n\n![IKEv2 配置文件](images/credentials.png)\n\n</details>\n\n<details>\n<summary>\n部署后如何通过 SSH 连接到服务器？\n</summary>\n\n**选项 1:** 使用 [EC2 Instance Connect](https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html) 进行连接。\n\n**选项 2:** 使用 SSH 连接到服务器。详情如下。\n\n你需要你的 Amazon EC2 实例的用户名和私钥，才能通过 SSH 登录到该实例。\n\nEC2 上的每个 Linux 服务器发行版本都有它自己的默认登录用户名。新实例默认禁用密码登录，必须使用私钥或 “密钥对” 登录。\n\n默认用户名列表：\n> **参考链接：** [https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/connection-prereqs.html#connection-prereqs-private-key](https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/connection-prereqs.html#connection-prereqs-private-key)\n\n| 发行版本 | 默认登录用户名 |\n| --- | --- |\n| Ubuntu |  `ubuntu` |\n| Debian | `admin` |\n| Amazon Linux 2 | `ec2-user` |\n\n此模板在部署期间为你生成一个密钥对。在成功创建堆栈后，你可以使用以下的其中一种方式来获取私钥。\n\n1. 在 **Outputs** 页面下拷贝密钥对 ID ，然后使用以下命令来提取私钥内容并且将其保存为一个证书文件：\n\n   > **注:** 在使用以下命令前，你需要在你的电脑上正确的安装和配置好 AWS 命令行。更多关于开始使用 AWS 命令行的信息，请参照 [Get started with the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) 。\n\n   ```\n   $ aws ssm get-parameter --region your-region --name /ec2/keypair/your-key-pair-id --with-decryption --query Parameter.Value --output text > new-key-file.pem\n   ```\n\n   ![显示密钥 ID](images/show-key-id.png)\n\n2. 直接从 **Outputs** 页面拷贝私钥对内容 ，然后将其保存入一个证书文件。请注意在保存到你的计算机之前，你可能需要修改私钥的格式，比如用换行符替换所有的空格。在保存后，需要为该私钥文件设置[适当的权限](https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/connection-prereqs.html#connection-prereqs-private-key)才能使用。\n\n   ![显示密钥内容](images/show-key-id.png)\n\n要为私钥文件设置适当的权限，请在该文件所在的目录下运行以下命令：\n\n```bash\n$ sudo chmod 400 new-key-file.pem\n```\n\n使用 SSH 登录到 EC2 实例的示例命令：\n\n```bash\n$ ssh -i path/to/your/new-key-file.pem instance-username@instance-ip-address\n```\n</details>\n\n<details>\n<summary>\n如何删除 CloudFormation 堆栈？\n</summary>\n\n你可以使用 CloudFormation 堆栈页面上的 \"Delete\" 按钮删除你创建的 CloudFormation 堆栈和它相关的资源。请注意，删除堆栈时存放生成的 IKEv2 配置文件的 S3 储存桶不会被自动删除。参见上面的 \"如何在部署结束后提取 IKEv2 连接配置文件\"。\n</details>\n\n## 作者\n\n版权所有 (C) 2020-2025 [Scott X. L.](https://github.com/scottpedia) <[ge105@ncf.ca](mailto:ge105@ncf.ca)>\n"
  },
  {
    "path": "aws/README.md",
    "content": "[English](README.md) | [中文](README-zh.md)\n\n# Deploy to Amazon EC2 using CloudFormation\n\nThis template will create a fully-working IPsec VPN server on Amazon Elastic Compute Cloud (Amazon EC2). Please make sure to check the EC2 [pricing details](https://aws.amazon.com/ec2/pricing/on-demand/) before continuing. Using a `t2.micro` or `t3.micro` server instance for your deployment may qualify for the [AWS Free Tier](https://aws.amazon.com/free/).\n\nAvailable customization parameters:\n\n- Amazon EC2 instance type\n> <details><summary><strong>Note</strong>: It is possible that not all instance type options offered by this template are available in a specific AWS region.(expand for details)\n> </summary>\n> \n> For example, you may not be able to deploy an `m5a.large` instance in `ap-east-1` (hypothetically). In that case, you might experience the following error during deployment: `The requested configuration is currently not supported. Please check the documentation for supported configurations`. Newly released regions are more prone to having this problem as there are less variety of instances. For more info about instance type availability, refer to [https://instances.vantage.sh/](https://instances.vantage.sh/).</details>\n\n- OS for your VPN server (Ubuntu **24.04**/22.04, Debian 12/11, Amazon Linux 2)\n- Your VPN username\n- Your VPN password\n- Your VPN IPsec PSK (pre-shared key)\n\n> **Note:** A secure IPsec PSK should consist of at least 20 random characters. DO NOT use these special characters within values: `\\ \" '`\n\nMake sure to deploy this template with an **AWS Account Root User** or an **IAM Account** with **Administrator Access**.\n\nRight-click this [**template link**](https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/aws/cloudformation-template-ipsec.json) and save as a file on your computer. Then upload it as the template source in the [stack creation wizard](https://console.aws.amazon.com/cloudformation/home#/stacks/new). You may choose an AWS region using the selector to the right of your account information on the navigation bar. Continue creating the stack, and in the final step make sure to confirm that this template may create IAM resources.\n\nAfter you click \"create stack\" in the final step, please wait for the stack creation and VPN setup to complete, which may take up to 15 minutes. As soon as the stack's status changes to **\"CREATE_COMPLETE\"**, you are ready to connect to the VPN server. Click the **Outputs** tab to view your VPN login details. Then continue to [Next steps: Configure VPN Clients](../README.md#next-steps).\n\nClick the icon below to start:\n\n[![Launch stack](images/cloudformation-launch-stack-button.png)](https://console.aws.amazon.com/cloudformation/home#/stacks/new)\n\n## Further reading\n\nLearn more about the design of this CloudFormation template:\n\n[Introduction to AWS CloudFormation with Example Project Walk-Through](https://nixsanctuary.com/introduction-to-aws-cloudformation-with-example-project-walk-through/)\n\n## Screenshots\n\n<details>\n<summary>\nClick here to view screenshots.\n</summary>\n\n![Upload the template](images/upload-the-template.png)\n![Specify parameters](images/specify-parameters.png)\n![Confirm IAM](images/confirm-iam.png)\n![Show key](images/show-key.png)\n</details>\n\n## FAQs\n\n<details>\n<summary>\nHow to retrieve the IKEv2 credentials following the deployment?\n</summary>\n\nAfter the deployment completes, connection credentials generated for IKEv2 mode are uploaded to a newly created AWS Simple Storage Service (S3) bucket. The download link is then provided under the **Outputs** tab.\n\nSimply click on the link to download an archive named `profiles.zip`. To extract the contents from the archive, you will be prompted to enter a password, which is the **VPN password you specified when creating the stack**.\n\nIt's important to note that the link provided for downloading the IKEv2 credentials **will expire in 1 day** following the successful deployment of the stack. If you delete the stack, the bucket that stores the IKEv2 crendentials will not be automatically deleted.\n\nTo learn more about how to configure your clients using IKEv2 mode, please refer to: [Guide: How to Set Up and Use IKEv2 VPN](../docs/ikev2-howto.md).\n\n![Credentials](images/credentials.png)\n\n</details>\n\n<details>\n<summary>\nHow to connect to the server via SSH after deployment?\n</summary>\n\n**Option 1:** Connect using [EC2 Instance Connect](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html).\n\n**Option 2:** Connect to the server using SSH. See details below.\n\nYou need to know the username and the private key for your Amazon EC2 instance in order to login to it via SSH.\n\nEach Linux server distribution on EC2 has its own default login username. Password login is disabled by default for new instances, and the use of private keys, or \"key pairs\", is enforced.\n\nList of default usernames:\n> **Reference:** [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connection-prereqs.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connection-prereqs.html)\n\n| Distribution | Default Login Username |\n| --- | --- |\n| Ubuntu |  `ubuntu` |\n| Debian | `admin` |\n| Amazon Linux 2 | `ec2-user` |\n\nThis template generates a key pair for you during deployment, and to acquire the private key you can choose one of the following two methods.\n\n1. Copy the key pair ID displayed under the **Outputs** tab, and use the following command to retrieve the private key material and save it into a certificate file:\n\n   > **Note:** You need to first properly set up the AWS CLI on your computer before using the following command. For more information on how to get started with AWS CLI, please refer to [Get started with the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html).\n\n   ```\n   $ aws ssm get-parameter --region your-region --name /ec2/keypair/your-key-pair-id --with-decryption --query Parameter.Value --output text > new-key-file.pem\n   ```\n\n   ![Show key ID](images/show-key-id.png)\n\n2. Copy the private key material directly from the **Outputs** tab, and save it into a certificate file. Note that You may need to format the private key by replacing all spaces with newlines, before saving to a file. The file will need to be set with [proper permissions](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connection-prereqs.html#connection-prereqs-private-key) before using.\n\n   ![Show key material](images/show-key.png)\n\nTo apply proper permissions to your private key file, run the following command under the directory where the file is located:\n\n```bash\n$ sudo chmod 400 new-key-file.pem\n```\n\nExample command to login to your EC2 instance using SSH:\n\n```bash\n$ ssh -i path/to/your/new-key-file.pem instance-username@instance-ip-address\n```\n</details>\n\n<details>\n<summary>\nHow to delete the CloudFormation stack?\n</summary>\n\nYou may use the \"Delete\" button on the CloudFormation stack page to delete the CloudFormation stack you created and its associated resources. Note that when deleting the stack, the S3 bucket that stores the generated IKEv2 credentials will not be automatically deleted. Refer to \"How to retrieve the IKEv2 credentials following the deployment\" above.\n</details>\n\n## Author\n\nCopyright (C) 2020-2025 [Scott X. L.](https://github.com/scottpedia) <[ge105@ncf.ca](mailto:ge105@ncf.ca)>\n"
  },
  {
    "path": "aws/cloudformation-template-ipsec.json",
    "content": "{\n    \"Metadata\": {\n        \"README\": {\n            \"Fn::Join\": [\n                \"\\n\",\n                [\n                    \"\",\n                    \"AWS Cloudformation Template for deploying IPSec VPN Servers on AWS EC2,\",\n                    \"based on the work of Lin Song <linsongui@gmail.com> : https://github.com/hwdsl2/setup-ipsec-vpn\",\n                    \"The latest version of this template can be found at : https://github.com/hwdsl2/setup-ipsec-vpn/aws\",\n                    \"\",\n                    \"Copyright (C) 2020-2025 Scott X. L. <ge105@ncf.ca>\",\n                    \"\",\n                    \"This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\",\n                    \"Unported License: http://creativecommons.org/licenses/by-sa/3.0/\",\n                    \"\",\n                    \"Attribution required: Please include my name in any derivative and let me\",\n                    \"know how you have improved it!\",\n                    \"\"\n                ]\n            ]\n        }\n    },\n    \"AWSTemplateFormatVersion\": \"2010-09-09\",\n    \"Mappings\": {\n        \"OS\": {\n            \"Ubuntu2204\": {\n                \"HelperInstallationCommands\": \"export DEBIAN_FRONTEND=noninteractive\\napt-get -yq update\\napt-get -yq install python3-pip zip awscli\\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\"\n            },\n            \"Ubuntu2404\": {\n                \"HelperInstallationCommands\": \"export DEBIAN_FRONTEND=noninteractive\\nrm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED\\napt-get -yq update\\napt-get -yq install python3-pip zip\\nsnap install aws-cli --classic\\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\"\n            },\n            \"Debian11\": {\n                \"HelperInstallationCommands\": \"export DEBIAN_FRONTEND=noninteractive\\napt-get -yq update\\napt-get -yq install python3-pip zip awscli\\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\"\n            },\n            \"Debian12\": {\n                \"HelperInstallationCommands\": \"export DEBIAN_FRONTEND=noninteractive\\nrm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED\\napt-get -yq update\\napt-get -yq install python3-pip zip awscli\\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\"\n            },\n            \"AmazonLinux2\": {\n                \"HelperInstallationCommands\": \"export PATH=\\\"$PATH:/opt/aws/bin\\\"\"\n            }\n        }\n    },\n    \"Resources\": {\n        \"IAMInstanceProfile\": {\n            \"Type\": \"AWS::IAM::InstanceProfile\",\n            \"Properties\": {\n                \"InstanceProfileName\": {\n                    \"Ref\": \"KeyPair\"\n                },\n                \"Path\": \"/setup-ipsec-vpn/\",\n                \"Roles\": [\n                    {\n                        \"Ref\": \"S3ExecutionRole\"\n                    }\n                ]\n            },\n            \"DependsOn\": [\n                \"S3ExecutionRole\",\n                \"KeyPair\"\n            ]\n        },\n        \"Ikev2S3Bucket\": {\n            \"Type\": \"AWS::S3::Bucket\",\n            \"DeletionPolicy\": \"Retain\",\n            \"Properties\": {\n                \"PublicAccessBlockConfiguration\": {\n                    \"BlockPublicAcls\": false,\n                    \"BlockPublicPolicy\": false,\n                    \"IgnorePublicAcls\": false,\n                    \"RestrictPublicBuckets\": false\n                },\n                \"LifecycleConfiguration\": {\n                    \"Rules\": [\n                        {\n                            \"Id\": \"DeletionAfterOneDay\",\n                            \"Status\": \"Enabled\",\n                            \"ExpirationInDays\": 1\n                        }\n                    ]\n                },\n                \"BucketName\": {\n                    \"Fn::GetAtt\": [\n                        \"KeyPairDisplayFunctionInfo\",\n                        \"Combination\"\n                    ]\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"KeyPair\"\n            ]\n        },\n        \"OpenBucketPolicy\": {\n            \"Type\": \"AWS::S3::BucketPolicy\",\n            \"Properties\": {\n                \"Bucket\": {\n                    \"Ref\": \"Ikev2S3Bucket\"\n                },\n                \"PolicyDocument\": {\n                    \"Version\": \"2012-10-17\",\n                    \"Statement\": [\n                        {\n                            \"Effect\": \"Allow\",\n                            \"Principal\": \"*\",\n                            \"Action\": \"s3:GetObject\",\n                            \"Resource\": {\n                                \"Fn::Join\": [\n                                    \"\",\n                                    [\n                                        \"arn:aws:s3:::\",\n                                        {\n                                            \"Ref\": \"Ikev2S3Bucket\"\n                                        },\n                                        \"/*\"\n                                    ]\n                                ]\n                            }\n                        }\n                    ]\n                }\n            }\n        },\n        \"VpnVpc\": {\n            \"Type\": \"AWS::EC2::VPC\",\n            \"Properties\": {\n                \"CidrBlock\": \"10.0.0.0/24\"\n            },\n            \"Metadata\": {}\n        },\n        \"VpnSubnet\": {\n            \"Type\": \"AWS::EC2::Subnet\",\n            \"Properties\": {\n                \"VpcId\": {\n                    \"Ref\": \"VpnVpc\"\n                },\n                \"CidrBlock\": \"10.0.0.0/24\",\n                \"MapPublicIpOnLaunch\": true,\n                \"AvailabilityZone\": {\n                    \"Fn::Select\": [\n                        \"0\",\n                        {\n                            \"Fn::GetAZs\": \"\"\n                        }\n                    ]\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"VpnVpc\",\n                \"VpcInternetGateway\"\n            ]\n        },\n        \"VpnRouteTable\": {\n            \"Type\": \"AWS::EC2::RouteTable\",\n            \"Properties\": {\n                \"VpcId\": {\n                    \"Ref\": \"VpnVpc\"\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"VpnSubnet\"\n            ]\n        },\n        \"PublicInternetRoute\": {\n            \"Type\": \"AWS::EC2::Route\",\n            \"Properties\": {\n                \"DestinationCidrBlock\": \"0.0.0.0/0\",\n                \"RouteTableId\": {\n                    \"Ref\": \"VpnRouteTable\"\n                },\n                \"GatewayId\": {\n                    \"Ref\": \"VpcInternetGateway\"\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"VpnRouteTable\",\n                \"VpcInternetGateway\",\n                \"InternetGatewayAttachment\"\n            ]\n        },\n        \"VpnInstance\": {\n            \"Type\": \"AWS::EC2::Instance\",\n            \"CreationPolicy\": {\n                \"ResourceSignal\": {\n                    \"Timeout\": \"PT15M\"\n                }\n            },\n            \"Properties\": {\n                \"IamInstanceProfile\": {\n                    \"Ref\": \"IAMInstanceProfile\"\n                },\n                \"UserData\": {\n                    \"Fn::Base64\": {\n                        \"Fn::Join\": [\n                            \"\\n\",\n                            [\n                                \"#!/bin/bash -xe\",\n                                { \"Fn::Sub\": \"trap 'cfn-signal -e 1 --resource VpnInstance --stack ${AWS::StackName} --region ${AWS::Region}' ERR\" },\n                                \"sleep 60\",\n                                {\n                                    \"Fn::FindInMap\": [\n                                        \"OS\",\n                                        {\n                                            \"Ref\": \"OS\"\n                                        },\n                                        \"HelperInstallationCommands\"\n                                    ]\n                                },\n                                { \"Fn::Sub\": \"export VPN_IPSEC_PSK='${VpnIpsecPsk}'\" },\n                                { \"Fn::Sub\": \"export VPN_USER='${VpnUser}'\" },\n                                { \"Fn::Sub\": \"export VPN_PASSWORD='${VpnPassword}'\" },\n                                \"wget -t 3 -T 30 -nv -O vpn.sh https://github.com/hwdsl2/setup-ipsec-vpn/raw/master/vpnsetup.sh\",\n                                \"sh vpn.sh\",\n                                \"mkdir /root/profiles\",\n                                \"cp /root/vpnclient* /root/profiles\",\n                                { \"Fn::Sub\": \"cd /root/ && zip -er --password '${VpnPassword}' profiles.zip ./profiles\" },\n                                { \"Fn::Sub\": \"aws s3 cp /root/profiles.zip s3://${Ikev2S3Bucket}/\" },\n                                { \"Fn::Sub\": \"cfn-signal -e 0 --stack ${AWS::StackName} --resource VpnInstance --region ${AWS::Region}\" }\n                            ]\n                        ]\n                    }\n                },\n                \"SecurityGroupIds\": [\n                    {\n                        \"Fn::GetAtt\": [\n                            \"VpnSecurityGroup\",\n                            \"GroupId\"\n                        ]\n                    }\n                ],\n                \"SubnetId\": {\n                    \"Ref\": \"VpnSubnet\"\n                },\n                \"AvailabilityZone\": {\n                    \"Fn::Select\": [\n                        \"0\",\n                        {\n                            \"Fn::GetAZs\": \"\"\n                        }\n                    ]\n                },\n                \"InstanceType\": {\n                    \"Ref\": \"InstanceType\"\n                },\n                \"KeyName\": {\n                    \"Ref\": \"KeyPair\"\n                },\n                \"ImageId\": {\n                    \"Fn::GetAtt\": [\n                        \"AMIInfo\",\n                        \"AMIId\"\n                    ]\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"VpnRouteTable\",\n                \"KeyPair\",\n                \"AMIInfoFunction\",\n                \"VpnSecurityGroup\",\n                \"Ikev2S3Bucket\",\n                \"IAMInstanceProfile\"\n            ]\n        },\n        \"KeyPair\": {\n            \"Type\": \"AWS::EC2::KeyPair\",\n            \"Properties\": {\n                \"KeyName\": {\n                    \"Fn::Join\": [\n                        \"-\",\n                        [\n                            \"setup-ipsec-vpn\",\n                            {\n                                \"Ref\": \"AWS::StackName\"\n                            }\n                        ]\n                    ]\n                }\n            }\n        },\n        \"VpnSecurityGroup\": {\n            \"Type\": \"AWS::EC2::SecurityGroup\",\n            \"Properties\": {\n                \"GroupDescription\": \"The VPN Security Group, allowing ingress UDP traffic at port 4500 and 500.\",\n                \"GroupName\": \"VpnSecurityGroup\",\n                \"VpcId\": {\n                    \"Ref\": \"VpnVpc\"\n                },\n                \"SecurityGroupIngress\": [\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"IpProtocol\": \"tcp\",\n                        \"FromPort\": 22,\n                        \"ToPort\": 22\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"IpProtocol\": \"udp\",\n                        \"FromPort\": 500,\n                        \"ToPort\": 500\n                    },\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"IpProtocol\": \"udp\",\n                        \"FromPort\": 4500,\n                        \"ToPort\": 4500\n                    }\n                ],\n                \"SecurityGroupEgress\": [\n                    {\n                        \"CidrIp\": \"0.0.0.0/0\",\n                        \"IpProtocol\": -1\n                    }\n                ]\n            },\n            \"Metadata\": {}\n        },\n        \"VpcInternetGateway\": {\n            \"Type\": \"AWS::EC2::InternetGateway\",\n            \"Properties\": {},\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"VpnVpc\"\n            ]\n        },\n        \"SubnetRouteTableAssociation\": {\n            \"Type\": \"AWS::EC2::SubnetRouteTableAssociation\",\n            \"Properties\": {\n                \"RouteTableId\": {\n                    \"Ref\": \"VpnRouteTable\"\n                },\n                \"SubnetId\": {\n                    \"Ref\": \"VpnSubnet\"\n                }\n            },\n            \"Metadata\": {}\n        },\n        \"KeyPairDisplayFunction\": {\n            \"Type\": \"AWS::Lambda::Function\",\n            \"Properties\": {\n                \"Handler\": \"index.handler\",\n                \"Runtime\": \"python3.12\",\n                \"Role\": {\n                    \"Fn::GetAtt\": [\n                        \"LambdaExecutionRole\",\n                        \"Arn\"\n                    ]\n                },\n                \"Code\": {\n                    \"ZipFile\": {\n                        \"Fn::Join\": [\n                            \"\\n\",\n                            [\n                                \"import boto3\",\n                                \"import cfnresponse\",\n                                \"import string\",\n                                \"import random\",\n                                \"import traceback\",\n                                \"'''\",\n                                \"This python program should be embedded into its designated cloudformation\",\n                                \"template as the inline code of one of the lambda functions.\",\n                                \"Its function is to create a random combination of 20 characters for the naming of the Ikev2S3Bucket, and\",\n                                \"to retrieve the private key material for display under the Outputs tab.\",\n                                \"'''\",\n                                \"def handler(event, context):\",\n                                \"   try:\",\n                                \"       if event['RequestType'] == 'Delete':\",\n                                \"           cfnresponse.send(event, context, cfnresponse.SUCCESS, {})\",\n                                \"       elif event['RequestType'] == 'Create':\",\n                                \"           rCombination = 'setup-ipsec-vpn-' + ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(20)).lower()\",\n                                \"           region = event['ResourceProperties']['Region']\",\n                                \"           ssm = boto3.client('ssm',region)\",\n                                \"           response = ssm.get_parameter(\",\n                                {\n                                    \"Fn::Join\": [\n                                        \"\",\n                                        [\n                                            \"               Name='/ec2/keypair/\",\n                                            {\n                                                \"Fn::GetAtt\": [\n                                                    \"KeyPair\",\n                                                    \"KeyPairId\"\n                                                ]\n                                            },\n                                            \"',\"\n                                        ]\n                                    ]\n                                },\n                                \"               WithDecryption=True\",\n                                \"           )\",\n                                \"           keyMaterial = response['Parameter']['Value']\",\n                                \"           cfnresponse.send(event, context, cfnresponse.SUCCESS, {'KeyMaterial':keyMaterial, 'Combination':rCombination}, 'KeyPairDisplayFunctionInfo')\",\n                                \"   except Exception as e:\",\n                                \"       cfnresponse.send(event, context, cfnresponse.FAILED, {'ErrorMsg':traceback.format_exc()})\"\n                            ]\n                        ]\n                    }\n                },\n                \"Timeout\": 30\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"LambdaExecutionRole\",\n                \"KeyPair\"\n            ]\n        },\n        \"KeyPairDisplayFunctionInfo\": {\n            \"Type\": \"Custom::KeyPairDisplayFunctionInfo\",\n            \"Properties\": {\n                \"Region\": {\n                    \"Ref\": \"AWS::Region\"\n                },\n                \"ServiceToken\": {\n                    \"Fn::GetAtt\": [\n                        \"KeyPairDisplayFunction\",\n                        \"Arn\"\n                    ]\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"KeyPairDisplayFunction\",\n                \"KeyPair\"\n            ]\n        },\n        \"AMIInfo\": {\n            \"Type\": \"Custom::AMIInfo\",\n            \"Properties\": {\n                \"Region\": {\n                    \"Ref\": \"AWS::Region\"\n                },\n                \"ServiceToken\": {\n                    \"Fn::GetAtt\": [\n                        \"AMIInfoFunction\",\n                        \"Arn\"\n                    ]\n                },\n                \"Distribution\": {\n                    \"Ref\": \"OS\"\n                }\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"AMIInfoFunction\"\n            ]\n        },\n        \"AMIInfoFunction\": {\n            \"Type\": \"AWS::Lambda::Function\",\n            \"Properties\": {\n                \"Handler\": \"index.handler\",\n                \"Runtime\": \"python3.12\",\n                \"Role\": {\n                    \"Fn::GetAtt\": [\n                        \"LambdaExecutionRole\",\n                        \"Arn\"\n                    ]\n                },\n                \"Code\": {\n                    \"ZipFile\": {\n                        \"Fn::Join\": [\n                            \"\\n\",\n                            [\n                                \"import boto3\",\n                                \"import cfnresponse\",\n                                \"import traceback\",\n                                \"'''\",\n                                \"This python script should be embeded into its designated cloudformation template.\",\n                                \"Its function is to sort out the correct AMI image to use for each of the distribution options available.\",\n                                \"'''\",\n                                \"def creation_date(e):\",\n                                \"   return e['CreationDate']\",\n                                \"\",\n                                \"def handler(event, context):\",\n                                \"   try:\",\n                                \"       regionName = event['ResourceProperties']['Region']\",\n                                \"       distribution = event['ResourceProperties']['Distribution']\",\n                                \"       ec2 = boto3.client('ec2',regionName)\",\n                                \"       AMIName = {\",\n                                \"           'Ubuntu2204': 'ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*',\",\n                                \"           'Ubuntu2404': 'ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*',\",\n                                \"           'Debian11': 'debian-11-amd64-*',\",\n                                \"           'Debian12': 'debian-12-amd64-*',\",\n                                \"           'AmazonLinux2': 'amzn2-ami-hvm-*.*-x86_64-gp2',\",\n                                \"       }[distribution]\",\n                                \"       response = ec2.describe_images(Filters=[{'Name':'name', 'Values':[AMIName]}], Owners=['099720109477', '136693071363', 'amazon'])\",\n                                \"       images = response['Images']\",\n                                \"       images.sort(key=creation_date,reverse=True)\",\n                                \"       AMIId = images[0]['ImageId']\",\n                                \"       cfnresponse.send(event, context, cfnresponse.SUCCESS, {'AMIId':AMIId}, 'AMIInfo')\",\n                                \"   except Exception:\",\n                                \"       cfnresponse.send(event, context, cfnresponse.FAILED, {'ErrorMsg':traceback.format_exc()})\"\n                            ]\n                        ]\n                    }\n                },\n                \"Timeout\": 30\n            },\n            \"Metadata\": {},\n            \"DependsOn\": [\n                \"LambdaExecutionRole\"\n            ]\n        },\n        \"LambdaExecutionRole\": {\n            \"Type\": \"AWS::IAM::Role\",\n            \"Properties\": {\n                \"AssumeRolePolicyDocument\": {\n                    \"Version\": \"2012-10-17\",\n                    \"Statement\": [\n                        {\n                            \"Effect\": \"Allow\",\n                            \"Principal\": {\n                                \"Service\": \"lambda.amazonaws.com\"\n                            },\n                            \"Action\": [\n                                \"sts:AssumeRole\"\n                            ]\n                        }\n                    ]\n                },\n                \"Path\": \"/\",\n                \"Policies\": [\n                    {\n                        \"PolicyName\": \"root\",\n                        \"PolicyDocument\": {\n                            \"Version\": \"2012-10-17\",\n                            \"Statement\": [\n                                {\n                                    \"Effect\": \"Allow\",\n                                    \"Action\": \"*\",\n                                    \"Resource\": \"*\"\n                                }\n                            ]\n                        }\n                    }\n                ]\n            },\n            \"Metadata\": {}\n        },\n        \"S3ExecutionRole\": {\n            \"Type\": \"AWS::IAM::Role\",\n            \"Properties\": {\n                \"AssumeRolePolicyDocument\": {\n                    \"Version\": \"2012-10-17\",\n                    \"Statement\": [\n                        {\n                            \"Effect\": \"Allow\",\n                            \"Principal\": {\n                                \"Service\": [\n                                    \"ec2.amazonaws.com\"\n                                ]\n                            },\n                            \"Action\": [\n                                \"sts:AssumeRole\"\n                            ]\n                        }\n                    ]\n                },\n                \"Path\": \"/\",\n                \"Policies\": [\n                    {\n                        \"PolicyName\": \"s3-bucket-specific-policy\",\n                        \"PolicyDocument\": {\n                            \"Version\": \"2012-10-17\",\n                            \"Statement\": [\n                                {\n                                    \"Effect\": \"Allow\",\n                                    \"Action\": \"s3:PutObject\",\n                                    \"Resource\": [\n                                        {\n                                            \"Fn::Join\": [\n                                                \"\",\n                                                [\n                                                    {\n                                                        \"Fn::GetAtt\": [\n                                                            \"Ikev2S3Bucket\",\n                                                            \"Arn\"\n                                                        ]\n                                                    },\n                                                    \"/*\"\n                                                ]\n                                            ]\n                                        }\n                                    ]\n                                }\n                            ]\n                        }\n                    }\n                ]\n            },\n            \"Metadata\": {}\n        },\n        \"InternetGatewayAttachment\": {\n            \"Type\": \"AWS::EC2::VPCGatewayAttachment\",\n            \"Properties\": {\n                \"InternetGatewayId\": {\n                    \"Ref\": \"VpcInternetGateway\"\n                },\n                \"VpcId\": {\n                    \"Ref\": \"VpnVpc\"\n                }\n            },\n            \"Metadata\": {}\n        }\n    },\n    \"Parameters\": {\n        \"VpnUser\": {\n            \"Type\": \"String\",\n            \"Description\": \"Your VPN username\"\n        },\n        \"VpnIpsecPsk\": {\n            \"Type\": \"String\",\n            \"Description\": \"Your VPN IPsec PSK (pre-shared key)\"\n        },\n        \"VpnPassword\": {\n            \"Type\": \"String\",\n            \"Description\": \"Your VPN password\"\n        },\n        \"OS\": {\n            \"Type\": \"String\",\n            \"Description\": \"The OS of your VPN server. Default: Ubuntu 24.04\",\n            \"Default\": \"Ubuntu2404\",\n            \"AllowedValues\": [\n                \"Ubuntu2404\",\n                \"Ubuntu2204\",\n                \"Debian12\",\n                \"Debian11\",\n                \"AmazonLinux2\"\n            ]\n        },\n        \"InstanceType\": {\n            \"Type\": \"String\",\n            \"Description\": \"The instance type of your VPN server. Using t2.micro or t3.micro may qualify for the AWS Free Tier.\",\n            \"AllowedValues\": [\n                \"t2.micro\",\n                \"t3.nano\",\n                \"m5.large\",\n                \"t3.micro\",\n                \"t3.small\",\n                \"t2.nano\",\n                \"t2.small\",\n                \"t3a.nano\",\n                \"t3a.micro\",\n                \"t3a.small\",\n                \"m5a.large\",\n                \"t1.micro\"\n            ],\n            \"Default\": \"t2.micro\"\n        }\n    },\n    \"Outputs\": {\n        \"1VPNAddress\": {\n            \"Description\": \"This is the public IP of your newly-launched VPN server.\",\n            \"Value\": {\n                \"Fn::GetAtt\": [\n                    \"VpnInstance\",\n                    \"PublicIp\"\n                ]\n            }\n        },\n        \"2VPNUsername\": {\n            \"Description\": \"Your VPN username\",\n            \"Value\": {\n                \"Ref\": \"VpnUser\"\n            }\n        },\n        \"3VPNPassword\": {\n            \"Description\": \"Your VPN password\",\n            \"Value\": {\n                \"Ref\": \"VpnPassword\"\n            }\n        },\n        \"4VPNKey\": {\n            \"Description\": \"Your VPN IPsec PSK (pre-shared key)\",\n            \"Value\": {\n                \"Ref\": \"VpnIpsecPsk\"\n            }\n        },\n        \"5EC2PrivateKeyId\": {\n            \"Description\": \"The ID of the key pair created. For more information regarding how to retrieve the private key for authentication, please refer to: https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/aws/README.md#faqs\",\n            \"Value\": {\n                \"Fn::GetAtt\": [\n                    \"KeyPair\",\n                    \"KeyPairId\"\n                ]\n            }\n        },\n        \"6EC2PrivateKeyMaterial\": {\n            \"Description\": \"The content of your private key for accessing the VPN server via SSH. Save it as a file for use when connecting.\",\n            \"Value\": {\n                \"Fn::GetAtt\": [\n                    \"KeyPairDisplayFunctionInfo\",\n                    \"KeyMaterial\"\n                ]\n            }\n        },\n        \"7NextStep\": {\n            \"Description\": \"Learn how to configure VPN clients.\",\n            \"Value\": \"https://github.com/hwdsl2/setup-ipsec-vpn#next-steps\"\n        },\n        \"8WarningForDebianUsers\": {\n            \"Description\": \"Please be noted that due to Debian images on AWS EC2 using cloud kernels, you are unable to use IPSec/L2TP mode if your server is running Debian. For more information, please refer to the link to the left.\",\n            \"Value\": \"https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#debian-kernel\"\n        },\n        \"9RetrieveYourIkev2Credentials\": {\n            \"Description\": \"Please use the following link to download your IKEv2 connection credentials. The password to the ZIP file that stores the credentials, is the same password used to connect to your VPN server. The download link for the credentials will expire in ONE day.\",\n            \"Value\": {\n                \"Fn::Join\": [\n                    \"\",\n                    [\n                        \"https://\",\n                        {\n                            \"Fn::GetAtt\": [\n                                \"Ikev2S3Bucket\",\n                                \"RegionalDomainName\"\n                            ]\n                        },\n                        \"/profiles.zip\"\n                    ]\n                ]\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "azure/README-zh.md",
    "content": "[English](README.md) | [中文](README-zh.md)\n\n# 在 Microsoft Azure 上部署\n\n使用这个模板，你可以在 Microsoft Azure Cloud 上快速搭建一个 VPN 服务器（[定价细节](https://azure.microsoft.com/zh-cn/pricing/details/virtual-machines/)）。\n\n可根据偏好设置以下选项：\n\n - Username for VPN **and** SSH （VPN 和 SSH 用户名）\n - Password for VPN **and** SSH （VPN 和 SSH 密码）\n - IPsec Pre-Shared Key for VPN （IPsec 预共享密钥）\n - Operating System Image （操作系统镜像，Ubuntu 24.04 或 22.04）\n - Virtual Machine Size （虚拟机大小，默认值： Standard_B1s）\n\n**注：** \\*不要\\* 在值中使用这些字符： `\\ \" '`\n\n请单击以下按钮开始：\n\n[![Deploy to Azure](../docs/images/azure-deploy-button.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fhwdsl2%2Fsetup-ipsec-vpn%2Fmaster%2Fazure%2Fazuredeploy.json)\n\n在完成部署之后，Azure 会有提示。下一步：[配置 VPN 客户端](../README-zh.md#下一步)。\n\n**注：** 在使用 SSH 连接到服务器时，请使用你在部署模板中指定的用户名和密码。如果要添加或者导出 IKEv2 客户端，运行 `sudo ikev2.sh`。如果你在输入正确的登录凭证后仍然无法使用 SSH 连接到服务器，请参见[解决与 Azure Linux VM 的 SSH 连接失败、出错或被拒绝的问题](https://learn.microsoft.com/zh-cn/troubleshoot/azure/virtual-machines/linux/troubleshoot-ssh-connection)和/或[无法 SSH 到 Azure Linux VM，因为权限太开放](https://learn.microsoft.com/zh-cn/troubleshoot/azure/virtual-machines/linux/troubleshoot-ssh-permissions-too-open)。\n\n## 作者\n\n版权所有 (C) 2016 [Daniel Falkner](https://github.com/derdanu)   \n版权所有 (C) 2017-2025 [Lin Song](https://github.com/hwdsl2)\n\n## 屏幕截图\n\n<details>\n<summary>\n单击查看屏幕截图。\n</summary>\n\n![Azure Custom Deployment](custom_deployment_screenshot.png)\n</details>\n"
  },
  {
    "path": "azure/README.md",
    "content": "[English](README.md) | [中文](README-zh.md)\n\n# Deploy to Microsoft Azure\n\nThis template will create a fully working VPN server on the Microsoft Azure Cloud ([pricing details](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/)).\n\nCustomizable with the following options:\n\n - Username for VPN **and** SSH\n - Password for VPN **and** SSH\n - IPsec Pre-Shared Key for VPN\n - Operating System Image (Ubuntu 24.04 or 22.04)\n - Virtual Machine Size (Default: Standard_B1s)\n\n**Note:** DO NOT use these special characters within values: `\\ \" '`\n\nPress this button to start:\n\n[![Deploy to Azure](../docs/images/azure-deploy-button.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fhwdsl2%2Fsetup-ipsec-vpn%2Fmaster%2Fazure%2Fazuredeploy.json)\n\nWhen the deployment finishes, Azure displays a notification. Next steps: [Configure VPN Clients](../README.md#next-steps).\n\n**Note:** When connecting to the server using SSH, use the username and password you specified in the deployment template. To add or export IKEv2 clients, run `sudo ikev2.sh`. If somehow you still cannot SSH into the VM after entering the correct login credentials, see [Troubleshoot SSH connections to an Azure Linux VM that fails, errors out, or is refused](https://learn.microsoft.com/en-us/troubleshoot/azure/virtual-machines/linux/troubleshoot-ssh-connection) and/or [Can't SSH to Azure Linux VM because permissions are too open](https://learn.microsoft.com/en-us/troubleshoot/azure/virtual-machines/linux/troubleshoot-ssh-permissions-too-open).\n\n## Authors\n\nCopyright (C) 2016 [Daniel Falkner](https://github.com/derdanu)   \nCopyright (C) 2017-2025 [Lin Song](https://github.com/hwdsl2)\n\n## Screenshot\n\n<details>\n<summary>\nClick to see screenshot.\n</summary>\n\n![Azure Custom Deployment](custom_deployment_screenshot.png)\n</details>\n"
  },
  {
    "path": "azure/azuredeploy.json",
    "content": "{\n  \"$schema\": \"https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#\",\n  \"contentVersion\": \"1.0.0.0\",\n  \"parameters\": {\n    \"username\": {\n      \"type\": \"string\",\n      \"minLength\": 1,\n      \"metadata\": {\n        \"description\": \"Username for VPN and SSH\"\n      }\n    },\n    \"password\": {\n      \"type\": \"securestring\",\n      \"metadata\": {\n        \"description\": \"Password for VPN and SSH\"\n      }\n    },\n   \"preSharedKey\": {\n      \"type\": \"securestring\",\n      \"metadata\": {\n        \"description\": \"IPsec Pre-Shared Key for VPN\"\n      }\n    },\n    \"image\": {\n      \"type\": \"string\",\n      \"allowedValues\": [\n        \"ubuntu24.04\",\n        \"ubuntu22.04\"\n      ],\n      \"defaultValue\": \"ubuntu24.04\",\n      \"metadata\": {\n        \"description\": \"OS to use. Ubuntu 24.04 or 22.04.\"\n      }\n    },\n    \"VMSize\": {\n      \"type\": \"string\",\n      \"defaultValue\": \"Standard_B1s\",\n      \"allowedValues\": [\n        \"Standard_B1ls\",\n        \"Standard_B1s\",\n        \"Standard_B1ms\",\n        \"Standard_B2s\",\n        \"Standard_B2ms\"\n      ],\n      \"metadata\": {\n        \"description\": \"The size of the Virtual Machine.\"\n      }\n    }\n  },\n  \"variables\": {\n    \"quote\": \"'\",\n    \"location\": \"[resourceGroup().location]\",\n    \"vmName\": \"vpnserver\",\n    \"virtualNetworkName\": \"vpnVnet\",\n    \"addressPrefix\": \"10.0.0.0/16\",\n    \"subnetName\": \"VPNSubnet\",\n    \"subnetPrefix\": \"10.0.1.0/24\",\n    \"apiVersion\": \"2015-06-15\",\n    \"storageName\": \"[concat(uniqueString(resourceGroup().id), 'vpnsa')]\",\n    \"vhdStorageType\": \"Standard_LRS\",\n    \"vnetId\": \"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]\",\n    \"SubnetRef\": \"[concat(variables('vnetId'), '/subnets/', variables('subnetName'))]\",\n    \"ubuntu24.04\": {\n      \"publisher\": \"Canonical\",\n      \"offer\": \"0001-com-ubuntu-server-noble\",\n      \"sku\": \"24_04-lts\",\n      \"version\": \"latest\"\n    },\n    \"ubuntu22.04\": {\n      \"publisher\": \"Canonical\",\n      \"offer\": \"0001-com-ubuntu-server-jammy\",\n      \"sku\": \"22_04-lts\",\n      \"version\": \"latest\"\n    },\n    \"installScriptURL\": \"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/azure/install.sh\",\n    \"installCommand\": \"[concat('sh install.sh ', variables('quote'), parameters('preSharedKey'), variables('quote'), ' ', variables('quote'), parameters('username'), variables('quote'), ' ', variables('quote'), parameters('password'), variables('quote'))]\"\n  },\n  \"resources\": [\n    {\n      \"type\": \"Microsoft.Storage/storageAccounts\",\n      \"name\": \"[variables('storageName')]\",\n      \"apiVersion\": \"2016-01-01\",\n      \"location\": \"[variables('location')]\",\n      \"tags\": {\n        \"displayName\": \"StorageAccount\"\n      },\n      \"properties\": {},\n      \"sku\": {\n        \"name\": \"[variables('vhdStorageType')]\"\n      },\n      \"kind\": \"Storage\"\n    },\n    {\n      \"apiVersion\": \"[variables('apiVersion')]\",\n      \"type\": \"Microsoft.Network/virtualNetworks\",\n      \"name\": \"[variables('virtualNetworkName')]\",\n      \"location\": \"[variables('location')]\",\n      \"tags\": {\n        \"displayName\": \"VirtualNetwork\"\n      },\n      \"properties\": {\n        \"addressSpace\": {\n          \"addressPrefixes\": [\n            \"[variables('addressPrefix')]\"\n          ]\n        },\n        \"subnets\": [\n          {\n            \"name\": \"[variables('subnetName')]\",\n            \"properties\": {\n              \"addressPrefix\": \"[variables('subnetPrefix')]\"\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"apiVersion\": \"[variables('apiVersion')]\",\n      \"type\": \"Microsoft.Network/networkInterfaces\",\n      \"name\": \"[concat(variables('vmName'), 'nic')]\",\n      \"location\": \"[resourceGroup().location]\",\n      \"tags\": {\n        \"displayName\": \"NetworkInterface\"\n      },\n      \"dependsOn\": [\n        \"[concat('Microsoft.Network/virtualNetworks/', concat(variables('virtualNetworkName')))]\",\n        \"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('vmName'), 'pip'))]\",\n        \"[concat('Microsoft.Network/networkSecurityGroups/', concat(variables('vmName'), 'nsg'))]\"\n      ],\n      \"properties\": {\n        \"ipConfigurations\": [\n          {\n            \"name\": \"ipconfig1\",\n            \"properties\": {\n              \"privateIPAllocationMethod\": \"Dynamic\",\n              \"publicIPAddress\": {\n                \"id\": \"[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('vmName'), 'pip'))]\"\n              },\n              \"subnet\": {\n                \"id\": \"[variables('subnetRef')]\"\n              }\n            }\n          }\n        ],\n        \"networkSecurityGroup\": {\n          \"id\": \"[resourceId('Microsoft.Network/networkSecurityGroups', concat(variables('vmName'), 'nsg'))]\"\n        }\n      }\n    },\n    {\n      \"type\": \"Microsoft.Compute/virtualMachines\",\n      \"name\": \"[variables('vmName')]\",\n      \"apiVersion\": \"2016-03-30\",\n      \"location\": \"[resourceGroup().location]\",\n      \"tags\": {\n        \"displayName\": \"VirtualMachine\"\n      },\n      \"dependsOn\": [\n        \"[concat('Microsoft.Network/networkInterfaces/', concat(variables('vmName'), 'nic'))]\"\n      ],\n      \"properties\": {\n        \"hardwareProfile\": {\n          \"vmSize\": \"[parameters('vmSize')]\"\n        },\n        \"osProfile\": {\n          \"computerName\": \"[variables('vmName')]\",\n          \"adminUsername\": \"[parameters('username')]\",\n          \"adminPassword\": \"[parameters('password')]\"\n        },\n        \"storageProfile\": {\n          \"imageReference\": \"[variables(parameters('image'))]\",\n          \"osDisk\": {\n            \"name\": \"osdisk\",\n            \"vhd\": {\n              \"uri\": \"[concat(reference(resourceId('Microsoft.Storage/storageAccounts/', variables('storageName'))).primaryEndpoints.blob, 'vmachines/', variables('vmName'), '.vhd')]\"\n            },\n            \"caching\": \"ReadWrite\",\n            \"createOption\": \"FromImage\"\n          }\n        },\n        \"networkProfile\": {\n          \"networkInterfaces\": [\n            {\n              \"id\": \"[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmName'), 'nic'))]\"\n            }\n          ]\n        }\n      }\n    },\n    {\n      \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\n      \"name\": \"[concat(variables('vmName'),'/installcustomscript')]\",\n      \"apiVersion\": \"[variables('apiVersion')]\",\n      \"location\": \"[resourceGroup().location]\",\n      \"tags\": {\n        \"displayName\": \"VirtualMachineCustomScriptExtension\"\n      },\n      \"dependsOn\": [\n        \"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]\"\n      ],\n      \"properties\": {\n        \"publisher\": \"Microsoft.Azure.Extensions\",\n        \"type\": \"CustomScript\",\n        \"typeHandlerVersion\": \"2.0\",\n        \"autoUpgradeMinorVersion\": true,\n        \"settings\": {\n          \"fileUris\": [ \"[variables('installScriptURL')]\" ],\n          \"commandToExecute\": \"[variables('installCommand')]\"\n        }\n      }\n    },\n    {\n      \"type\": \"Microsoft.Network/networkSecurityGroups\",\n      \"name\": \"[concat(variables('vmName'), 'nsg')]\",\n      \"tags\": {\n        \"displayName\": \"NetworkSecurityGroup\"\n      },\n      \"apiVersion\": \"[variables('apiVersion')]\",\n      \"location\": \"[resourceGroup().location]\",\n      \"properties\": {\n        \"securityRules\": [\n          {\n            \"name\": \"default-ssh\",\n            \"properties\": {\n              \"protocol\": \"Tcp\",\n              \"sourcePortRange\": \"*\",\n              \"destinationPortRange\": \"22\",\n              \"sourceAddressPrefix\": \"*\",\n              \"destinationAddressPrefix\": \"*\",\n              \"access\": \"Allow\",\n              \"priority\": 1000,\n              \"direction\": \"Inbound\"\n            }\n          },\n          {\n            \"name\": \"default-udp-500\",\n            \"properties\": {\n              \"protocol\": \"Udp\",\n              \"sourcePortRange\": \"*\",\n              \"destinationPortRange\": \"500\",\n              \"sourceAddressPrefix\": \"*\",\n              \"destinationAddressPrefix\": \"*\",\n              \"access\": \"Allow\",\n              \"priority\": 2000,\n              \"direction\": \"Inbound\"\n            }\n          },\n          {\n            \"name\": \"default-udp-4500\",\n            \"properties\": {\n              \"protocol\": \"Udp\",\n              \"sourcePortRange\": \"*\",\n              \"destinationPortRange\": \"4500\",\n              \"sourceAddressPrefix\": \"*\",\n              \"destinationAddressPrefix\": \"*\",\n              \"access\": \"Allow\",\n              \"priority\": 2001,\n              \"direction\": \"Inbound\"\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"apiVersion\": \"[variables('apiVersion')]\",\n      \"type\": \"Microsoft.Network/publicIPAddresses\",\n      \"name\": \"[concat(variables('vmName'), 'pip')]\",\n      \"location\": \"[resourceGroup().location]\",\n      \"tags\": {\n        \"displayName\": \"PublicIPAddress\"\n      },\n      \"properties\": {\n        \"publicIPAllocationMethod\": \"Static\"\n      }\n    }\n  ],\n  \"outputs\": {\n    \"Public IP\": {\n      \"type\": \"string\",\n      \"value\": \"[reference(concat(variables('vmName'), 'pip')).ipAddress]\"\n    }\n  }\n}\n"
  },
  {
    "path": "azure/azuredeploy.parameters.json",
    "content": "{\n  \"$schema\": \"https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#\",\n  \"contentVersion\": \"1.0.0.0\",\n  \"parameters\": {\n    \"username\": {\n      \"value\": \"Vpnuser\"\n    },\n    \"password\": {\n      \"value\": \"Password123#\"\n    },\n    \"preSharedKey\": {\n      \"value\": \"mypsksupersecure\"\n    }\n  }\n}"
  },
  {
    "path": "azure/install.sh",
    "content": "#!/bin/sh\n\nexport VPN_IPSEC_PSK=\"$1\"\nexport VPN_USER=\"$2\"\nexport VPN_PASSWORD=\"$3\"\n\nwget -t 3 -T 30 -nv -O vpn.sh https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/vpnsetup.sh && sh vpn.sh\n"
  },
  {
    "path": "docs/advanced-usage-zh.md",
    "content": "[English](advanced-usage.md) | [中文](advanced-usage-zh.md)\n\n# 高级用法\n\n* [使用其他的 DNS 服务器](#使用其他的-dns-服务器)\n* [域名和更改服务器 IP](#域名和更改服务器-ip)\n* [仅限 IKEv2 的 VPN](#仅限-ikev2-的-vpn)\n* [VPN 内网 IP 和流量](#vpn-内网-ip-和流量)\n* [指定 VPN 服务器的公有 IP](#指定-vpn-服务器的公有-ip)\n* [自定义 VPN 子网](#自定义-vpn-子网)\n* [IPv6 支持](#ipv6-支持)\n* [转发端口到 VPN 客户端](#转发端口到-vpn-客户端)\n* [VPN 分流](#vpn-分流)\n* [访问 VPN 服务器的网段](#访问-vpn-服务器的网段)\n* [VPN 服务器网段访问 VPN 客户端](#vpn-服务器网段访问-vpn-客户端)\n* [更改 IPTables 规则](#更改-iptables-规则)\n* [部署 Google BBR 拥塞控制](#部署-google-bbr-拥塞控制)\n\n## 使用其他的 DNS 服务器\n\n在 VPN 已连接时，客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。如果偏好其它的域名解析服务，你可以编辑以下文件：`/etc/ppp/options.xl2tpd`, `/etc/ipsec.conf` 和 `/etc/ipsec.d/ikev2.conf`（如果存在），并替换 `8.8.8.8` 和 `8.8.4.4`。然后运行 `service ipsec restart` 和 `service xl2tpd restart`。\n\n以下是一些流行的公共 DNS 提供商的列表，供你参考。\n\n| 提供商 | 主 DNS | 辅助 DNS | 注释 |\n| ----- | ------ | ------- | ---- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | 本项目默认 |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | 另见：[Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | 阻止恶意域 |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | 阻止网络钓鱼域，可配置。 |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | [域过滤器](https://cleanbrowsing.org/filters/)可用 |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | 按需选择 | 按需选择 | 广告拦截，免费套餐可用。[了解更多](https://nextdns.io/?from=bg25bwmp)。 |\n| [Control D](https://controld.com/free-dns) | 按需选择 | 按需选择 | 广告拦截，可配置。[了解更多](https://controld.com/free-dns)。 |\n\n高级用户可以在运行 VPN 安装脚本时定义 `VPN_DNS_SRV1` 和 `VPN_DNS_SRV2`（可选）。有关更多详细信息，请参见[自定义 VPN 选项](../README-zh.md#自定义-vpn-选项)。\n\n你可以为特定的 IKEv2 客户端设置不同的 DNS 服务器。对于此用例，请参见 [#1562](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1562#issuecomment-2151361658)。\n\n如果你的用例需要使用 IPTables 规则将 DNS 流量重定向到另一台服务器，请参见 [#1565](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1565)。\n\n在某些情况下，你可能希望 VPN 客户端仅使用指定的 DNS 服务器来解析内部域名，并使用其本地配置的 DNS 服务器来解析所有其他域名。这可以使用 `modecfgdomains` 选项进行配置，例如 `modecfgdomains=\"internal.example.com, home\"`。对于 IKEv2，将此选项添加到 `/etc/ipsec.d/ikev2.conf` 中的 `conn ikev2-cp` 小节。对于 IPsec/XAuth (\"Cisco IPsec\")，将此选项添加到 `/etc/ipsec.conf` 中的 `conn xauth-psk` 小节。然后运行 `service ipsec restart`。IPsec/L2TP 模式不支持此选项。\n\n## 域名和更改服务器 IP\n\n对于 [IPsec/L2TP](clients-zh.md) 和 [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth-zh.md) 模式，你可以在不需要额外配置的情况下使用一个域名（比如 `vpn.example.com`）而不是 IP 地址连接到 VPN 服务器。另外，一般来说，在服务器的 IP 更改后，比如在恢复一个映像到具有不同 IP 的新服务器后，VPN 会继续正常工作，虽然可能需要重启服务器。\n\n对于 [IKEv2](ikev2-howto-zh.md) 模式，如果你想要 VPN 在服务器的 IP 更改后继续正常工作，参见[这一小节](ikev2-howto-zh.md#更改-ikev2-服务器地址)。或者，你也可以在[配置 IKEv2](ikev2-howto-zh.md#使用辅助脚本配置-ikev2) 时指定一个域名作为 IKEv2 服务器地址。该域名必须是一个全称域名(FQDN)。示例如下：\n\n```\nsudo VPN_DNS_NAME='vpn.example.com' ikev2.sh --auto\n```\n\n另外，你也可以自定义 IKEv2 选项，通过在运行[辅助脚本](ikev2-howto-zh.md#使用辅助脚本配置-ikev2)时去掉 `--auto` 参数来实现。\n\n## 仅限 IKEv2 的 VPN\n\n使用 Libreswan 4.2 或更新版本，高级用户可以为 VPN 服务器启用仅限 IKEv2 模式。当启用该模式时，VPN 客户端仅能使用 IKEv2 连接到 VPN 服务器。所有的 IKEv1 连接（包括 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式）将被丢弃。\n\n要启用仅限 IKEv2 模式，首先按照[自述文件](../README-zh.md)中的说明安装 VPN 服务器并且配置 IKEv2。然后运行[辅助脚本](../extras/ikev2onlymode.sh)并按提示操作。\n\n```bash\nwget https://get.vpnsetup.net/ikev2only -O ikev2only.sh\nsudo bash ikev2only.sh\n```\n\n要禁用仅限 IKEv2 模式，再次运行辅助脚本并选择适当的选项。\n\n<details>\n<summary>\n另外，你也可以手动启用仅限 IKEv2 模式。\n</summary>\n\n另外，你也可以手动启用仅限 IKEv2 模式。首先使用 `ipsec --version` 命令检查 Libreswan 版本，并[更新 Libreswan](../README-zh.md#升级libreswan)（如果需要）。然后编辑 VPN 服务器上的 `/etc/ipsec.conf`。将 `ikev1-policy=accept` 替换为 `ikev1-policy=drop`。如果该行不存在，则在 `config setup` 小节的末尾添加 `ikev1-policy=drop`，开头必须空两格。保存文件并运行 `service ipsec restart`。在完成后，你可以使用 `ipsec status` 命令来验证仅启用了 `ikev2-cp` 连接。\n</details>\n\n## VPN 内网 IP 和流量\n\n在使用 [IPsec/L2TP](clients-zh.md) 模式连接时，VPN 服务器在虚拟网络 `192.168.42.0/24` 内具有内网 IP `192.168.42.1`。为客户端分配的内网 IP 在这个范围内：`192.168.42.10` 到 `192.168.42.250`。要找到为特定的客户端分配的 IP，可以查看该 VPN 客户端上的连接状态。\n\n在使用 [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth-zh.md) 或 [IKEv2](ikev2-howto-zh.md) 模式连接时，VPN 服务器在虚拟网络 `192.168.43.0/24` 内 **没有** 内网 IP。为客户端分配的内网 IP 在这个范围内：`192.168.43.10` 到 `192.168.43.250`。\n\n你可以使用这些 VPN 内网 IP 进行通信。但是请注意，为 VPN 客户端分配的 IP 是动态的，而且客户端设备上的防火墙可能会阻止这些流量。\n\n高级用户可以将静态 IP 分配给 VPN 客户端。这是可选的。展开以查看详细信息。\n\n<details>\n<summary>\nIPsec/L2TP 模式：为 VPN 客户端分配静态 IP\n</summary>\n\n下面的示例 **仅适用于** IPsec/L2TP 模式。这些命令必须用 `root` 账户运行。\n\n1. 首先为要分配静态 IP 的每个 VPN 客户端创建一个新的 VPN 用户。参见[管理 VPN 用户](manage-users-zh.md)。该文档包含辅助脚本，以方便管理 VPN 用户。\n1. 编辑 VPN 服务器上的 `/etc/xl2tpd/xl2tpd.conf`。将 `ip range = 192.168.42.10-192.168.42.250` 替换为比如 `ip range = 192.168.42.100-192.168.42.250`。这样可以缩小自动分配的 IP 地址池，从而使更多的 IP 可以作为静态 IP 分配给客户端。\n1. 编辑 VPN 服务器上的 `/etc/ppp/chap-secrets`。例如，如果文件内容是：\n   ```\n   \"username1\"  l2tpd  \"password1\"  *\n   \"username2\"  l2tpd  \"password2\"  *\n   \"username3\"  l2tpd  \"password3\"  *\n   ```\n\n   假设你要为 VPN 用户 `username2` 分配静态 IP `192.168.42.2`，为 VPN 用户 `username3` 分配静态 IP `192.168.42.3`，同时保持 `username1` 不变（从池中自动分配）。在编辑完成后，文件内容应该如下所示：\n   ```\n   \"username1\"  l2tpd  \"password1\"  *\n   \"username2\"  l2tpd  \"password2\"  192.168.42.2\n   \"username3\"  l2tpd  \"password3\"  192.168.42.3\n   ```\n\n   **注：** 分配的静态 IP 必须来自子网 `192.168.42.0/24`，并且必须 **不是** 来自自动分配的 IP 地址池（参见上面的 `ip range`）。另外，`192.168.42.1` 保留给 VPN 服务器本身使用。在上面的示例中，你只能分配 `192.168.42.2-192.168.42.99` 范围内的静态 IP。\n1. **（重要）** 重启 xl2tpd 服务：\n   ```\n   service xl2tpd restart\n   ```\n</details>\n\n<details>\n<summary>\nIPsec/XAuth (\"Cisco IPsec\") 模式：为 VPN 客户端分配静态 IP\n</summary>\n\n下面的示例 **仅适用于** IPsec/XAuth (\"Cisco IPsec\") 模式。这些命令必须用 `root` 账户运行。\n\n1. 首先为要分配静态 IP 的每个 VPN 客户端创建一个新的 VPN 用户。参见[管理 VPN 用户](manage-users-zh.md)。该文档包含辅助脚本，以方便管理 VPN 用户。\n1. 编辑 VPN 服务器上的 `/etc/ipsec.conf`。将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为比如 `rightaddresspool=192.168.43.100-192.168.43.250`。这样可以缩小自动分配的 IP 地址池，从而使更多的 IP 可以作为静态 IP 分配给客户端。\n1. 编辑 VPN 服务器上的 `/etc/ipsec.d/ikev2.conf`（如果存在）。将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为与上一步 **相同的值**。\n1. 编辑 VPN 服务器上的 `/etc/ipsec.d/passwd`。例如，如果文件内容是：\n   ```\n   username1:password1hashed:xauth-psk\n   username2:password2hashed:xauth-psk\n   username3:password3hashed:xauth-psk\n   ```\n\n   假设你要为 VPN 用户 `username2` 分配静态 IP `192.168.43.2`，为 VPN 用户 `username3` 分配静态 IP `192.168.43.3`，同时保持 `username1` 不变（从池中自动分配）。在编辑完成后，文件内容应该如下所示：\n   ```\n   username1:password1hashed:xauth-psk\n   username2:password2hashed:xauth-psk:192.168.42.2\n   username3:password3hashed:xauth-psk:192.168.42.3\n   ```\n\n   **注：** 分配的静态 IP 必须来自子网 `192.168.43.0/24`，并且必须 **不是** 来自自动分配的 IP 地址池（参见上面的 `rightaddresspool`）。在上面的示例中，你只能分配 `192.168.43.1-192.168.43.99` 范围内的静态 IP。\n1. **（重要）** 重启 IPsec 服务：\n   ```\n   service ipsec restart\n   ```\n</details>\n\n<details>\n<summary>\nIKEv2 模式：为 VPN 客户端分配静态 IP\n</summary>\n\n下面的示例 **仅适用于** IKEv2 模式。这些命令必须用 `root` 账户运行。\n\n1. 首先为要分配静态 IP 的每个客户端创建一个新的 IKEv2 客户端证书，并且在纸上记下每个客户端的名称。参见[添加客户端证书](ikev2-howto-zh.md#添加客户端证书)。\n1. 编辑 VPN 服务器上的 `/etc/ipsec.d/ikev2.conf`。将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为比如 `rightaddresspool=192.168.43.100-192.168.43.250`。这样可以缩小自动分配的 IP 地址池，从而使更多的 IP 可以作为静态 IP 分配给客户端。\n1. 编辑 VPN 服务器上的 `/etc/ipsec.conf`。将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为与上一步 **相同的值**。\n1. 再次编辑 VPN 服务器上的 `/etc/ipsec.d/ikev2.conf`。例如，如果文件内容是：\n   ```\n   conn ikev2-cp\n     left=%defaultroute\n     ... ...\n   ```\n\n   假设你要为 IKEv2 客户端 `client1` 分配静态 IP `192.168.43.4`，为客户端 `client2` 分配静态 IP `192.168.43.5`，同时保持其它客户端不变（从池中自动分配）。在编辑完成后，文件内容应该如下所示：\n   ```\n   conn ikev2-cp\n     left=%defaultroute\n     ... ...\n\n   conn ikev2-shared\n     # 复制/粘贴 ikev2-cp 小节中 *除了下面三项之外* 的所有内容\n     # rightid, rightaddresspool, auto=add\n\n   conn client1\n     rightid=@client1\n     rightaddresspool=192.168.43.4-192.168.43.4\n     auto=add\n     also=ikev2-shared\n\n   conn client2\n     rightid=@client2\n     rightaddresspool=192.168.43.5-192.168.43.5\n     auto=add\n     also=ikev2-shared\n   ```\n\n   **注：** 为要分配静态 IP 的每个客户端添加一个新的 `conn` 小节。`rightid=` 右边的客户端名称必须添加 `@` 前缀。该客户端名称必须与你在[添加客户端证书](ikev2-howto-zh.md#添加客户端证书)时指定的名称完全一致。分配的静态 IP 必须来自子网 `192.168.43.0/24`，并且必须 **不是** 来自自动分配的 IP 地址池（参见上面的 `rightaddresspool`）。在上面的示例中，你只能分配 `192.168.43.1-192.168.43.99` 范围内的静态 IP。\n\n   **注：** 对于 Windows 7/8/10/11 和 [RouterOS](ikev2-howto-zh.md#routeros) 客户端，你必须对 `rightid=` 使用不同的语法。例如，如果客户端名称为 `client1`，则在上面的示例中设置 `rightid=\"CN=client1, O=IKEv2 VPN\"`。\n1. **（重要）** 重启 IPsec 服务：\n   ```\n   service ipsec restart\n   ```\n</details>\n\n在默认配置下，允许客户端之间的流量。如果你想要 **不允许** 客户端之间的流量，可以在 VPN 服务器上运行以下命令。将它们添加到 `/etc/rc.local` 以便在重启后继续有效。\n\n```\niptables -I FORWARD 2 -i ppp+ -o ppp+ -s 192.168.42.0/24 -d 192.168.42.0/24 -j DROP\niptables -I FORWARD 3 -s 192.168.43.0/24 -d 192.168.43.0/24 -j DROP\niptables -I FORWARD 4 -i ppp+ -d 192.168.43.0/24 -j DROP\niptables -I FORWARD 5 -s 192.168.43.0/24 -o ppp+ -j DROP\n```\n\n## 指定 VPN 服务器的公有 IP\n\n在具有多个公有 IP 地址的服务器上，高级用户可以使用变量 `VPN_PUBLIC_IP` 为 VPN 服务器指定一个公有 IP。例如，如果服务器的 IP 为 `192.0.2.1` 和 `192.0.2.2`，并且你想要 VPN 服务器使用 `192.0.2.2`：\n\n```\nsudo VPN_PUBLIC_IP=192.0.2.2 sh vpn.sh\n```\n\n请注意，如果在服务器上已经配置了 IKEv2，则此变量对 IKEv2 模式无效。在这种情况下，你可以移除 IKEv2 并使用自定义选项重新配置它。参见[使用辅助脚本配置 IKEv2](ikev2-howto-zh.md#使用辅助脚本配置-ikev2)。\n\n如果你想要 VPN 客户端在 VPN 连接处于活动状态时使用指定的公有 IP 作为其 \"出站 IP\"，并且指定的 IP **不是** 服务器上的主 IP（或默认路由），则可能需要额外的配置。在这种情况下，你可能需要更改服务器上的 IPTables 规则。如果要在重启后继续有效，你可以将这些命令添加到 `/etc/rc.local`。\n\n继续上面的例子，如果你希望 \"出站 IP\" 为 `192.0.2.2`：\n\n```\n# 获取默认网络接口名称\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\n# 移除 MASQUERADE 规则\niptables -t nat -D POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j MASQUERADE\niptables -t nat -D POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j MASQUERADE\n# 添加 SNAT 规则\niptables -t nat -I POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j SNAT --to 192.0.2.2\niptables -t nat -I POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j SNAT --to 192.0.2.2\n```\n\n**注：** 以上方法仅适用于服务器的默认网络接口对应多个公有 IP 的情况。如果服务器有多个网络接口，对应不同的公有 IP，则此方法无效。\n\n要检查一个已连接的 VPN 客户端的 \"出站 IP\"，你可以在该客户端上打开浏览器并到[这里](https://www.ipchicken.com)检测 IP 地址。\n\n## 自定义 VPN 子网\n\n默认情况下，IPsec/L2TP VPN 客户端将使用内部 VPN 子网 `192.168.42.0/24`，而 IPsec/XAuth (\"Cisco IPsec\") 和 IKEv2 VPN 客户端将使用内部 VPN 子网 `192.168.43.0/24`。有关更多详细信息，请参见 [VPN 内网 IP 和流量](#vpn-内网-ip-和流量)。\n\n对于大多数用例，没有必要也 **不建议** 自定义这些子网。但是，如果你的用例需要它，你可以在安装 VPN 时指定自定义子网。\n\n**重要：** 你只能在 **初始 VPN 安装时** 指定自定义子网。如果 IPsec VPN 已安装，你 **必须** 首先[卸载 VPN](uninstall-zh.md)，然后指定自定义子网并重新安装。否则，VPN 可能会停止工作。\n\n```\n# 示例：为 IPsec/L2TP 模式指定自定义 VPN 子网\n# 注：必须指定所有三个变量。\nsudo VPN_L2TP_NET=10.1.0.0/16 \\\nVPN_L2TP_LOCAL=10.1.0.1 \\\nVPN_L2TP_POOL=10.1.0.10-10.1.254.254 \\\nsh vpn.sh\n```\n\n```\n# 示例：为 IPsec/XAuth 和 IKEv2 模式指定自定义 VPN 子网\n# 注：必须指定以下两个变量。\nsudo VPN_XAUTH_NET=10.2.0.0/16 \\\nVPN_XAUTH_POOL=10.2.0.10-10.2.254.254 \\\nsh vpn.sh\n```\n\n在上面的例子中，`VPN_L2TP_LOCAL` 是在 IPsec/L2TP 模式下的 VPN 服务器的内网 IP。`VPN_L2TP_POOL` 和 `VPN_XAUTH_POOL` 是为 VPN 客户端自动分配的 IP 地址池。\n\n## IPv6 支持\n\n如果你的 VPN 服务器拥有公共（全局单播）IPv6 地址并且满足以下要求，IKEv2 客户端的 IPv6 支持将在 VPN 安装时自动启用，无需手动配置。\n\n**注：** IPv6 支持已在 Android 上使用 strongSwan VPN 客户端进行测试。其他平台（例如 Windows、macOS、iOS）可能存在限制，或者需要进行额外配置才能使 IPv6 通过 IKEv2 VPN 正常工作。\n\n**注：** 对于 **Windows** 客户端，你需要在 PowerShell 窗口中运行以下命令一次，以通过 VPN 路由 IPv6 流量。将 `IKEv2 VPN X.X.X.X` 替换为你的 VPN 连接的实际名称。完成后，重新连接到 IKEv2 VPN。\n\n```powershell\nAdd-VpnConnectionRoute -ConnectionName \"IKEv2 VPN X.X.X.X\" -DestinationPrefix ::/1\nAdd-VpnConnectionRoute -ConnectionName \"IKEv2 VPN X.X.X.X\" -DestinationPrefix 8000::/1\n```\n\n启用 IPv6 后，IKEv2 VPN 客户端将同时获得来自 `192.168.43.0/24` 地址池的 IPv4 地址和来自 `fddd:500:500:500::/64` 地址池的 IPv6 地址。VPN 服务器通过将客户端地址池的 IPv6 流量伪装（NAT）为服务器自身的 IPv6 地址，从而使 VPN 客户端能够通过该隧道获得完整的 IPv6 互联网访问。\n\n**要求：**\n- VPN 服务器必须拥有可路由的全局单播 IPv6 地址（即以 `2` 或 `3` 开头的地址）。链路本地地址 (`fe80::/10`) 和 ULA 地址 (`fc00::/7`) 不满足要求。\n- Libreswan 5.0 或更新版本（VPN 安装脚本默认使用 5.x）。\n- IPv6 仅支持 **IKEv2 模式**。IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式不支持 IPv6。\n\n要验证 IPv6 是否正常工作，请使用 IKEv2 连接到 VPN，然后检查你的 IPv6 地址，例如使用 [test-ipv6.com](https://test-ipv6.com)。\n\n你可以在安装 VPN 时选择指定自定义 IPv6 地址池子网，这是可选的。该子网必须是 `/64` ULA 范围内的子网（推荐使用 `fddd::/16`）。\n\n```\n# 示例：为 IKEv2 模式指定自定义 IPv6 地址池子网\nsudo VPN_IP6_NET=fddd:1234:5678:9012::/64 \\\nsh vpn.sh\n```\n\n**注：** `VPN_IP6_NET` 变量只能在初始 VPN 安装时指定。\n\n## 转发端口到 VPN 客户端\n\n在某些情况下，你可能想要将 VPN 服务器上的端口转发到一个已连接的 VPN 客户端。这可以通过在 VPN 服务器上添加 IPTables 规则来实现。\n\n**警告：** 端口转发会将 VPN 客户端上的端口暴露给整个因特网，这可能会带来**安全风险**！**不建议**这样做，除非你的用例需要它。\n\n**注：** 为 VPN 客户端分配的内网 IP 是动态的，而且客户端设备上的防火墙可能会阻止转发的流量。如果要将静态 IP 分配给 VPN 客户端，请参见 [VPN 内网 IP 和流量](#vpn-内网-ip-和流量)。要找到为特定的客户端分配的 IP，可以查看该 VPN 客户端上的连接状态。\n\n示例 1：将 VPN 服务器上的 TCP 端口 443 转发到位于 `192.168.42.10` 的 IPsec/L2TP 客户端。\n```\n# 获取默认网络接口名称\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\niptables -I FORWARD 2 -i \"$netif\" -o ppp+ -p tcp --dport 443 -j ACCEPT\niptables -t nat -A PREROUTING -i \"$netif\" -p tcp --dport 443 -j DNAT --to 192.168.42.10\n```\n\n示例 2：将 VPN 服务器上的 UDP 端口 123 转发到位于 `192.168.43.10` 的 IKEv2（或 IPsec/XAuth）客户端。\n```\n# 获取默认网络接口名称\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\niptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -p udp --dport 123 -j ACCEPT\niptables -t nat -A PREROUTING -i \"$netif\" ! -s 192.168.43.0/24 -p udp --dport 123 -j DNAT --to 192.168.43.10\n```\n\n如果你想要这些规则在重启后仍然有效，可以将这些命令添加到 `/etc/rc.local`。要删除添加的 IPTables 规则，请再次运行这些命令，但是将 `-I FORWARD 2` 替换为 `-D FORWARD`，并且将 `-A PREROUTING` 替换为 `-D PREROUTING`。\n\n## VPN 分流\n\n在启用 VPN 分流 (split tunneling) 时，VPN 客户端将仅通过 VPN 隧道发送特定目标子网的流量。其他流量 **不会** 通过 VPN 隧道。这允许你通过 VPN 安全访问指定的网络，而无需通过 VPN 发送所有客户端的流量。VPN 分流有一些局限性，而且并非所有的 VPN 客户端都支持。\n\n高级用户可以为 [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth-zh.md) 和/或 [IKEv2](ikev2-howto-zh.md) 模式启用 VPN 分流。这是可选的。展开查看详情。IPsec/L2TP 模式不支持此功能（Windows 除外，见下文）。\n\n<details>\n<summary>\nIPsec/XAuth (\"Cisco IPsec\") 模式：启用 VPN 分流 (split tunneling)\n</summary>\n\n下面的示例 **仅适用于** IPsec/XAuth (\"Cisco IPsec\") 模式。这些命令必须用 `root` 账户运行。\n\n1. 编辑 VPN 服务器上的 `/etc/ipsec.conf`。在 `conn xauth-psk` 小节中，将 `leftsubnet=0.0.0.0/0` 替换为你想要 VPN 客户端通过 VPN 隧道发送流量的子网。例如：   \n   对于单个子网：\n   ```\n   leftsubnet=10.123.123.0/24\n   ```\n   对于多个子网（使用 `leftsubnets`）：\n   ```\n   leftsubnets=\"10.123.123.0/24,10.100.0.0/16\"\n   ```\n1. **（重要）** 重启 IPsec 服务：\n   ```\n   service ipsec restart\n   ```\n</details>\n\n<details>\n<summary>\nIKEv2 模式：启用 VPN 分流 (split tunneling)\n</summary>\n\n下面的示例 **仅适用于** IKEv2 模式。这些命令必须用 `root` 账户运行。\n\n1. 编辑 VPN 服务器上的 `/etc/ipsec.d/ikev2.conf`。在 `conn ikev2-cp` 小节中，将 `leftsubnet=0.0.0.0/0` 替换为你想要 VPN 客户端通过 VPN 隧道发送流量的子网。例如：   \n   对于单个子网：\n   ```\n   leftsubnet=10.123.123.0/24\n   ```\n   对于多个子网（使用 `leftsubnets`）：\n   ```\n   leftsubnets=\"10.123.123.0/24,10.100.0.0/16\"\n   ```\n1. **（重要）** 重启 IPsec 服务：\n   ```\n   service ipsec restart\n   ```\n\n**注：** 高级用户可以为特定的 IKEv2 客户端设置不同的 VPN 分流配置。请参见 [VPN 内网 IP 和流量](#vpn-内网-ip-和流量)部分并展开 \"IKEv2 模式：为 VPN 客户端分配静态 IP\"。在该部分中的示例的基础上，你可以将 `leftsubnet=...` 选项添加到特定 IKEv2 客户端的 `conn` 小节，然后重启 IPsec 服务。\n</details>\n\n另外，Windows 用户也可以通过手动添加路由的方式启用 VPN 分流：\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. **Windows 11:** 选择 **网络和 Internet 设置**，然后在打开的页面中单击 **高级网络设置**。单击 **更多网络适配器选项**。   \n   **Windows 10:** 选择 **打开\"网络和 Internet\"设置**，然后在打开的页面中单击 **网络和共享中心**。单击左侧的 **更改适配器设置**。   \n   **Windows 8/7:** 选择 **打开网络和共享中心**。单击左侧的 **更改适配器设置**。\n1. 右键单击新的 VPN 连接，并选择 **属性**。\n1. 单击 **网络** 选项卡，选择 **Internet Protocol Version 4 (TCP/IPv4)**，然后单击 **属性**。\n1. 单击 **高级**，然后取消选中 **在远程网络上使用默认网关**。\n1. 单击 **确定** 以关闭 **属性** 对话框。\n1. **（重要）** 断开 VPN 连接，然后重新连接。\n1. 假设你想要 VPN 客户端通过 VPN 隧道发送流量的子网是 `10.123.123.0/24`。打开[提升权限命令提示符](http://www.cnblogs.com/xxcanghai/p/4610054.html)并运行以下命令之一。   \n   对于 IKEv2 和 IPsec/XAuth (\"Cisco IPsec\") 模式：\n   ```\n   route add -p 10.123.123.0 mask 255.255.255.0 192.168.43.1\n   ```\n   对于 IPsec/L2TP 模式：\n   ```\n   route add -p 10.123.123.0 mask 255.255.255.0 192.168.42.1\n   ```\n1. 完成后，VPN 客户端将通过 VPN 隧道仅发送指定子网的流量。其他流量将绕过 VPN。\n\n## 访问 VPN 服务器的网段\n\n连接到 VPN 后，VPN 客户端通常可以访问与 VPN 服务器位于同一本地子网内的其他设备上运行的服务，而无需进行其他配置。例如，如果 VPN 服务器的本地子网为 `192.168.0.0/24`，并且一个 Nginx 服务器在 IP `192.168.0.2` 上运行，则 VPN 客户端可以使用 IP `192.168.0.2`来访问 Nginx 服务器。\n\n请注意，如果 VPN 服务器具有多个网络接口（例如 `eth0` 和 `eth1`），并且你想要 VPN 客户端访问服务器上 **不用于** Internet 访问的网络接口后面的本地子网，则需要进行额外的配置。在此情形下，你必须运行以下命令来添加 IPTables 规则。为了在重启后仍然有效，你可以将这些命令添加到 `/etc/rc.local`。\n\n```bash\n# 将 eth1 替换为 VPN 服务器上你想要客户端访问的网络接口名称\nnetif=eth1\niptables -I FORWARD 2 -i \"$netif\" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT\niptables -I FORWARD 2 -i ppp+ -o \"$netif\" -j ACCEPT\niptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT\niptables -I FORWARD 2 -s 192.168.43.0/24 -o \"$netif\" -j ACCEPT\niptables -t nat -I POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j MASQUERADE\niptables -t nat -I POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j MASQUERADE\n```\n\n## VPN 服务器网段访问 VPN 客户端\n\n在某些情况下，你可能需要从 VPN 服务器位于同一本地子网内的其他设备访问 VPN 客户端上的服务。这可以通过以下几个步骤实现。\n\n假设 VPN 服务器 IP 是 `10.1.0.2`，你想要访问 VPN 客户端的设备的 IP 是 `10.1.0.3`。\n\n1. 在 VPN 服务器上添加 IPTables 规则以允许该流量。例如：\n   ```\n   # 获取默认网络接口名称\n   netif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\n   iptables -I FORWARD 2 -i \"$netif\" -o ppp+ -s 10.1.0.3 -j ACCEPT\n   iptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -s 10.1.0.3 -j ACCEPT\n   ```\n2. 在你想要访问 VPN 客户端的设备上添加路由规则。例如：\n   ```\n   # 将 eth0 替换为设备的本地子网的网络接口名称\n   route add -net 192.168.42.0 netmask 255.255.255.0 gw 10.1.0.2 dev eth0\n   route add -net 192.168.43.0 netmask 255.255.255.0 gw 10.1.0.2 dev eth0\n   ```\n\n在 [VPN 内网 IP 和流量](#vpn-内网-ip-和流量)小节了解 VPN 内网 IP 的更多信息。\n\n## 更改 IPTables 规则\n\n如果你想要在安装后更改 IPTables 规则，请编辑 `/etc/iptables.rules` 和/或 `/etc/iptables/rules.v4` (Ubuntu/Debian)，或者 `/etc/sysconfig/iptables` (CentOS/RHEL)。然后重启服务器。\n\n如果启用了 [IPv6 支持](#ipv6-支持)，相应的 ip6tables 规则将保存在 `/etc/ip6tables.rules` 和 `/etc/iptables/rules.v6` (Ubuntu/Debian)，或者 `/etc/sysconfig/ip6tables` (CentOS/RHEL)。\n\n**注：** 如果你的服务器运行 CentOS Linux（或类似系统），并且在安装 VPN 时 firewalld 处于活动状态，则可能已配置 nftables。在这种情况下，编辑 `/etc/sysconfig/nftables.conf` 而不是 `/etc/sysconfig/iptables`。\n\n## 部署 Google BBR 拥塞控制\n\nVPN 服务器搭建完成后，可以通过部署 Google BBR 拥塞控制算法提升性能。\n\n这通常只需要在配置文件 `/etc/sysctl.conf` 中插入设定即可完成。但是部分 Linux 发行版可能需要额外更新 Linux 内核。\n\n详细的部署方法，可以参考[这篇文档](bbr-zh.md)。\n\n## 授权协议\n\n版权所有 (C) 2021-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n这个项目是以[知识共享署名-相同方式共享3.0](http://creativecommons.org/licenses/by-sa/3.0/) 许可协议授权。   \n必须署名： 请包括我的名字在任何衍生产品，并且让我知道你是如何改善它的！\n"
  },
  {
    "path": "docs/advanced-usage.md",
    "content": "[English](advanced-usage.md) | [中文](advanced-usage-zh.md)\n\n# Advanced Usage\n\n* [Use alternative DNS servers](#use-alternative-dns-servers)\n* [DNS name and server IP changes](#dns-name-and-server-ip-changes)\n* [IKEv2-only VPN](#ikev2-only-vpn)\n* [Internal VPN IPs and traffic](#internal-vpn-ips-and-traffic)\n* [Specify VPN server's public IP](#specify-vpn-servers-public-ip)\n* [Customize VPN subnets](#customize-vpn-subnets)\n* [IPv6 support](#ipv6-support)\n* [Port forwarding to VPN clients](#port-forwarding-to-vpn-clients)\n* [Split tunneling](#split-tunneling)\n* [Access VPN server's subnet](#access-vpn-servers-subnet)\n* [Access VPN clients from server's subnet](#access-vpn-clients-from-servers-subnet)\n* [Modify IPTables rules](#modify-iptables-rules)\n* [Deploy Google BBR congestion control](#deploy-google-bbr-congestion-control)\n\n## Use alternative DNS servers\n\nBy default, clients are set to use [Google Public DNS](https://developers.google.com/speed/public-dns/) when the VPN is active. If another DNS provider is preferred, you may replace `8.8.8.8` and `8.8.4.4` in these files: `/etc/ppp/options.xl2tpd`, `/etc/ipsec.conf` and `/etc/ipsec.d/ikev2.conf` (if exists). Then run `service ipsec restart` and `service xl2tpd restart`.\n\nBelow is a list of some popular public DNS providers for your reference.\n\n| Provider | Primary DNS | Secondary DNS | Notes |\n| -------- | ----------- | ------------- | ----- |\n| [Google Public DNS](https://developers.google.com/speed/public-dns) | 8.8.8.8 | 8.8.4.4 | Default in this project |\n| [Cloudflare](https://1.1.1.1/dns/) | 1.1.1.1 | 1.0.0.1 | See also: [Cloudflare for families](https://1.1.1.1/family/) |\n| [Quad9](https://www.quad9.net) | 9.9.9.9 | 149.112.112.112 | Blocks malicious domains |\n| [OpenDNS](https://www.opendns.com/home-internet-security/) | 208.67.222.222 | 208.67.220.220 | Blocks phishing domains, configurable. |\n| [CleanBrowsing](https://cleanbrowsing.org/filters/) | 185.228.168.9 | 185.228.169.9 | [Domain filters](https://cleanbrowsing.org/filters/) available |\n| [NextDNS](https://nextdns.io/?from=bg25bwmp) | Varies | Varies | Ad blocking, free tier available. [Learn more](https://nextdns.io/?from=bg25bwmp). |\n| [Control D](https://controld.com/free-dns) | Varies | Varies | Ad blocking, configurable. [Learn more](https://controld.com/free-dns). |\n\nAdvanced users can define `VPN_DNS_SRV1` and optionally `VPN_DNS_SRV2` when running the VPN setup script. For more details, see [Customize VPN options](../README.md#customize-vpn-options).\n\nIt is possible to set different DNS server(s) for specific IKEv2 client(s). For this use case, please refer to [#1562](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1562#issuecomment-2151361658).\n\nIf your use case requires redirecting DNS traffic to another server using IPTables rules, see [#1565](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1565).\n\nIn certain circumstances, you may want VPN clients to use the specified DNS server(s) only for resolving internal domain name(s), and use their locally configured DNS servers to resolve all other domain names. This can be configured using the `modecfgdomains` option, e.g. `modecfgdomains=\"internal.example.com, home\"`. Add this option to section `conn ikev2-cp` in `/etc/ipsec.d/ikev2.conf` for IKEv2, and to section `conn xauth-psk` in `/etc/ipsec.conf` for IPsec/XAuth (\"Cisco IPsec\"). Then run `service ipsec restart`. IPsec/L2TP mode does not support this option.\n\n## DNS name and server IP changes\n\nFor [IPsec/L2TP](clients.md) and [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth.md) modes, you may use a DNS name (e.g. `vpn.example.com`) instead of an IP address to connect to the VPN server, without additional configuration. In addition, the VPN should generally continue to work after server IP changes, such as after restoring a snapshot to a new server with a different IP, although a reboot may be required.\n\nFor [IKEv2](ikev2-howto.md) mode, if you want the VPN to continue to work after server IP changes, read [this section](ikev2-howto.md#change-ikev2-server-address). Alternatively, you may specify a DNS name for the IKEv2 server address when [setting up IKEv2](ikev2-howto.md#set-up-ikev2-using-helper-script). The DNS name must be a fully qualified domain name (FQDN). Example:\n\n```\nsudo VPN_DNS_NAME='vpn.example.com' ikev2.sh --auto\n```\n\nAlternatively, you may customize IKEv2 options by running the [helper script](ikev2-howto.md#set-up-ikev2-using-helper-script) without the `--auto` parameter.\n\n## IKEv2-only VPN\n\nUsing Libreswan 4.2 or newer, advanced users can enable IKEv2-only mode on the VPN server. With IKEv2-only mode enabled, VPN clients can only connect to the VPN server using IKEv2. All IKEv1 connections (including IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes) will be dropped.\n\nTo enable IKEv2-only mode, first install the VPN server and set up IKEv2 using instructions in the [README](../README.md). Then run the [helper script](../extras/ikev2onlymode.sh) and follow the prompts.\n\n```bash\nwget https://get.vpnsetup.net/ikev2only -O ikev2only.sh\nsudo bash ikev2only.sh\n```\n\nTo disable IKEv2-only mode, run the helper script again and select the appropriate option.\n\n<details>\n<summary>\nAlternatively, you may manually enable IKEv2-only mode.\n</summary>\n\nAlternatively, you may manually enable IKEv2-only mode. First check Libreswan version using `ipsec --version`, and [update Libreswan](../README.md#upgrade-libreswan) if needed. Then edit `/etc/ipsec.conf` on the VPN server. Replace `ikev1-policy=accept` with `ikev1-policy=drop`. If the line does not exist, append `ikev1-policy=drop` to the end of the `config setup` section, indented by two spaces. Save the file and run `service ipsec restart`. When finished, you can run `ipsec status` to verify that only the `ikev2-cp` connection is enabled.\n</details>\n\n## Internal VPN IPs and traffic\n\nWhen connecting using [IPsec/L2TP](clients.md) mode, the VPN server has internal IP `192.168.42.1` within the VPN subnet `192.168.42.0/24`. Clients are assigned internal IPs from `192.168.42.10` to `192.168.42.250`. To check which IP is assigned to a client, view the connection status on the VPN client.\n\nWhen connecting using [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth.md) or [IKEv2](ikev2-howto.md) mode, the VPN server does NOT have an internal IP within the VPN subnet `192.168.43.0/24`. Clients are assigned internal IPs from `192.168.43.10` to `192.168.43.250`.\n\nYou may use these internal VPN IPs for communication. However, note that the IPs assigned to VPN clients are dynamic, and firewalls on client devices may block such traffic.\n\nAdvanced users may optionally assign static IPs to VPN clients. Expand for details.\n\n<details>\n<summary>\nIPsec/L2TP mode: Assign static IPs to VPN clients\n</summary>\n\nThe example below **ONLY** applies to IPsec/L2TP mode. Commands must be run as `root`.\n\n1. First, create a new VPN user for each VPN client that you want to assign a static IP to. Refer to [Manage VPN Users](manage-users.md). Helper scripts are included for convenience.\n1. Edit `/etc/xl2tpd/xl2tpd.conf` on the VPN server. Replace `ip range = 192.168.42.10-192.168.42.250` with e.g. `ip range = 192.168.42.100-192.168.42.250`. This reduces the pool of auto-assigned IP addresses, so that more IPs are available to assign to clients as static IPs.\n1. Edit `/etc/ppp/chap-secrets` on the VPN server. For example, if the file contains:\n   ```\n   \"username1\"  l2tpd  \"password1\"  *\n   \"username2\"  l2tpd  \"password2\"  *\n   \"username3\"  l2tpd  \"password3\"  *\n   ```\n\n   Let's assume that you want to assign static IP `192.168.42.2` to VPN user `username2`, assign static IP `192.168.42.3` to VPN user `username3`, while keeping `username1` unchanged (auto-assign from the pool). After editing, the file should look like:\n   ```\n   \"username1\"  l2tpd  \"password1\"  *\n   \"username2\"  l2tpd  \"password2\"  192.168.42.2\n   \"username3\"  l2tpd  \"password3\"  192.168.42.3\n   ```\n\n   **Note:** The assigned static IP(s) must be from the subnet `192.168.42.0/24`, and must NOT be from the pool of auto-assigned IPs (see `ip range` above). In addition, `192.168.42.1` is reserved for the VPN server itself. In the example above, you can only assign static IP(s) from the range `192.168.42.2-192.168.42.99`.\n1. **(Important)** Restart the xl2tpd service:\n   ```\n   service xl2tpd restart\n   ```\n</details>\n\n<details>\n<summary>\nIPsec/XAuth (\"Cisco IPsec\") mode: Assign static IPs to VPN clients\n</summary>\n\nThe example below **ONLY** applies to IPsec/XAuth (\"Cisco IPsec\") mode. Commands must be run as `root`.\n\n1. First, create a new VPN user for each VPN client that you want to assign a static IP to. Refer to [Manage VPN Users](manage-users.md). Helper scripts are included for convenience.\n1. Edit `/etc/ipsec.conf` on the VPN server. Replace `rightaddresspool=192.168.43.10-192.168.43.250` with e.g. `rightaddresspool=192.168.43.100-192.168.43.250`. This reduces the pool of auto-assigned IP addresses, so that more IPs are available to assign to clients as static IPs.\n1. Edit `/etc/ipsec.d/ikev2.conf` on the VPN server (if exists). Replace `rightaddresspool=192.168.43.10-192.168.43.250` with the **same value** as the previous step.\n1. Edit `/etc/ipsec.d/passwd` on the VPN server. For example, if the file contains:\n   ```\n   username1:password1hashed:xauth-psk\n   username2:password2hashed:xauth-psk\n   username3:password3hashed:xauth-psk\n   ```\n\n   Let's assume that you want to assign static IP `192.168.43.2` to VPN user `username2`, assign static IP `192.168.43.3` to VPN user `username3`, while keeping `username1` unchanged (auto-assign from the pool). After editing, the file should look like:\n   ```\n   username1:password1hashed:xauth-psk\n   username2:password2hashed:xauth-psk:192.168.42.2\n   username3:password3hashed:xauth-psk:192.168.42.3\n   ```\n\n   **Note:** The assigned static IP(s) must be from the subnet `192.168.43.0/24`, and must NOT be from the pool of auto-assigned IPs (see `rightaddresspool` above). In the example above, you can only assign static IP(s) from the range `192.168.43.1-192.168.43.99`.\n1. **(Important)** Restart the IPsec service:\n   ```\n   service ipsec restart\n   ```\n</details>\n\n<details>\n<summary>\nIKEv2 mode: Assign static IPs to VPN clients\n</summary>\n\nThe example below **ONLY** applies to IKEv2 mode. Commands must be run as `root`.\n\n1. First, create a new IKEv2 client certificate for each client that you want to assign a static IP to, and write down the name of each IKEv2 client. Refer to [Add a client certificate](ikev2-howto.md#add-a-client-certificate).\n1. Edit `/etc/ipsec.d/ikev2.conf` on the VPN server. Replace `rightaddresspool=192.168.43.10-192.168.43.250` with e.g. `rightaddresspool=192.168.43.100-192.168.43.250`. This reduces the pool of auto-assigned IP addresses, so that more IPs are available to assign to clients as static IPs.\n1. Edit `/etc/ipsec.conf` on the VPN server. Replace `rightaddresspool=192.168.43.10-192.168.43.250` with the **same value** as the previous step.\n1. Edit `/etc/ipsec.d/ikev2.conf` on the VPN server again. For example, if the file contains:\n   ```\n   conn ikev2-cp\n     left=%defaultroute\n     ... ...\n   ```\n\n   Let's assume that you want to assign static IP `192.168.43.4` to IKEv2 client `client1`, assign static IP `192.168.43.5` to client `client2`, while keeping other clients unchanged (auto-assign from the pool). After editing, the file should look like:\n   ```\n   conn ikev2-cp\n     left=%defaultroute\n     ... ...\n\n   conn ikev2-shared\n     # COPY everything from the ikev2-cp section, EXCEPT FOR:\n     # rightid, rightaddresspool, auto=add\n\n   conn client1\n     rightid=@client1\n     rightaddresspool=192.168.43.4-192.168.43.4\n     auto=add\n     also=ikev2-shared\n\n   conn client2\n     rightid=@client2\n     rightaddresspool=192.168.43.5-192.168.43.5\n     auto=add\n     also=ikev2-shared\n   ```\n\n   **Note:** Add a new `conn` section for each client that you want to assign a static IP to. You must add a `@` prefix to the client name for `rightid=`. The client name must exactly match the name you specified when [adding the client certificate](ikev2-howto.md#add-a-client-certificate). The assigned static IP(s) must be from the subnet `192.168.43.0/24`, and must NOT be from the pool of auto-assigned IPs (see `rightaddresspool` above). In the example above, you can only assign static IP(s) from the range `192.168.43.1-192.168.43.99`.\n\n   **Note:** For Windows 7/8/10/11 and [RouterOS](ikev2-howto.md#routeros) clients, you must use a different syntax for `rightid=`. For example, if the client name is `client1`, set `rightid=\"CN=client1, O=IKEv2 VPN\"` in the example above.\n1. **(Important)** Restart the IPsec service:\n   ```\n   service ipsec restart\n   ```\n</details>\n\nClient-to-client traffic is allowed by default. If you want to **disallow** client-to-client traffic, run the following commands on the VPN server. Add them to `/etc/rc.local` to persist after reboot.\n\n```\niptables -I FORWARD 2 -i ppp+ -o ppp+ -s 192.168.42.0/24 -d 192.168.42.0/24 -j DROP\niptables -I FORWARD 3 -s 192.168.43.0/24 -d 192.168.43.0/24 -j DROP\niptables -I FORWARD 4 -i ppp+ -d 192.168.43.0/24 -j DROP\niptables -I FORWARD 5 -s 192.168.43.0/24 -o ppp+ -j DROP\n```\n\n## Specify VPN server's public IP\n\nOn servers with multiple public IP addresses, advanced users can specify a public IP for the VPN server using variable `VPN_PUBLIC_IP`. For example, if the server has IPs `192.0.2.1` and `192.0.2.2`, and you want the VPN server to use `192.0.2.2`:\n\n```\nsudo VPN_PUBLIC_IP=192.0.2.2 sh vpn.sh\n```\n\nNote that this variable has no effect for IKEv2 mode, if IKEv2 is already set up on the server. In this case, you may remove IKEv2 and set it up again using custom options. Refer to [Set up IKEv2 using helper script](ikev2-howto.md#set-up-ikev2-using-helper-script).\n\nAdditional configuration may be required if you want VPN clients to use the specified public IP as their \"outgoing IP\" when the VPN connection is active, and the specified IP is NOT the main IP (or default route) on the server. In this case, you may need to change IPTables rules on the server. To persist after reboot, you can add these commands to `/etc/rc.local`.\n\nContinuing with the example above, if you want the \"outgoing IP\" to be `192.0.2.2`:\n\n```\n# Get default network interface name\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\n# Remove MASQUERADE rules\niptables -t nat -D POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j MASQUERADE\niptables -t nat -D POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j MASQUERADE\n# Add SNAT rules\niptables -t nat -I POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j SNAT --to 192.0.2.2\niptables -t nat -I POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j SNAT --to 192.0.2.2\n```\n\n**Note:** The method above only applies if the VPN server's default network interface maps to multiple public IPs. This method may not work if the server has multiple network interfaces, each with a different public IP.\n\nTo check the \"outgoing IP\" for a connected VPN client, you may open a browser on the client and [look up the IP address on Google](https://www.google.com/search?q=my+ip).\n\n## Customize VPN subnets\n\nBy default, IPsec/L2TP VPN clients will use internal VPN subnet `192.168.42.0/24`, while IPsec/XAuth (\"Cisco IPsec\") and IKEv2 VPN clients will use internal VPN subnet `192.168.43.0/24`. For more details, see [Internal VPN IPs and traffic](#internal-vpn-ips-and-traffic).\n\nFor most use cases, it is NOT necessary and NOT recommended to customize these subnets. If your use case requires it, however, you may specify custom subnet(s) when installing the VPN.\n\n**Important:** You may only specify custom subnets **during initial VPN install**. If the IPsec VPN is already installed, you **must** first [uninstall the VPN](uninstall.md), then specify custom subnets and re-install. Otherwise, the VPN may stop working.\n\n```\n# Example: Specify custom VPN subnet for IPsec/L2TP mode\n# Note: All three variables must be specified.\nsudo VPN_L2TP_NET=10.1.0.0/16 \\\nVPN_L2TP_LOCAL=10.1.0.1 \\\nVPN_L2TP_POOL=10.1.0.10-10.1.254.254 \\\nsh vpn.sh\n```\n\n```\n# Example: Specify custom VPN subnet for IPsec/XAuth and IKEv2 modes\n# Note: Both variables must be specified.\nsudo VPN_XAUTH_NET=10.2.0.0/16 \\\nVPN_XAUTH_POOL=10.2.0.10-10.2.254.254 \\\nsh vpn.sh\n```\n\nIn the examples above, `VPN_L2TP_LOCAL` is the VPN server's internal IP for IPsec/L2TP mode. `VPN_L2TP_POOL` and `VPN_XAUTH_POOL` are the pools of auto-assigned IP addresses for VPN clients.\n\n## IPv6 support\n\nIf your VPN server has a public (global unicast) IPv6 address and the requirements below are met, IPv6 support for IKEv2 clients is automatically enabled during VPN setup. No manual configuration is needed.\n\n**Note:** IPv6 support has been tested on Android using the strongSwan VPN client. Other platforms (e.g. Windows, macOS, iOS) may have limitations or require additional configuration for IPv6 to work over the IKEv2 VPN.\n\n**Note:** For **Windows** clients, you need to run the following commands once in a PowerShell window to route IPv6 traffic through the VPN. Replace `IKEv2 VPN X.X.X.X` with the actual name of your VPN connection. When finished, reconnect to the IKEv2 VPN.\n\n```powershell\nAdd-VpnConnectionRoute -ConnectionName \"IKEv2 VPN X.X.X.X\" -DestinationPrefix ::/1\nAdd-VpnConnectionRoute -ConnectionName \"IKEv2 VPN X.X.X.X\" -DestinationPrefix 8000::/1\n```\n\nWhen IPv6 is enabled, IKEv2 VPN clients receive both an IPv4 address from the `192.168.43.0/24` pool and an IPv6 address from the `fddd:500:500:500::/64` pool. The VPN server masquerades IPv6 traffic from the client pool through the server's own IPv6 address, giving VPN clients full IPv6 internet access through the tunnel.\n\n**Requirements:**\n- The VPN server must have a routable global unicast IPv6 address (i.e., an address starting with `2` or `3`). Link-local (`fe80::/10`) and ULA (`fc00::/7`) addresses are not sufficient.\n- Libreswan 5.0 or newer (the VPN setup scripts use 5.x by default).\n- IPv6 is only supported for **IKEv2 mode**. IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes do not support IPv6.\n\nTo verify that IPv6 is working, connect to the VPN using IKEv2 and check your IPv6 address, e.g. using [test-ipv6.com](https://test-ipv6.com).\n\nYou may optionally specify a custom IPv6 pool subnet when installing the VPN. The subnet must be a `/64` from the ULA range (`fddd::/16` is recommended).\n\n```\n# Example: Specify custom IPv6 pool subnet for IKEv2 mode\nsudo VPN_IP6_NET=fddd:1234:5678:9012::/64 \\\nsh vpn.sh\n```\n\n**Note:** The `VPN_IP6_NET` variable may only be specified during initial VPN install.\n\n## Port forwarding to VPN clients\n\nIn certain circumstances, you may want to forward port(s) on the VPN server to a connected VPN client. This can be done by adding IPTables rules on the VPN server.\n\n**Warning:** Port forwarding will expose port(s) on the VPN client to the entire Internet, which could be a **security risk**! This is NOT recommended, unless your use case requires it.\n\n**Note:** The internal VPN IPs assigned to VPN clients are dynamic, and firewalls on client devices may block forwarded traffic. To assign static IPs to VPN clients, see [Internal VPN IPs and traffic](#internal-vpn-ips-and-traffic). To check which IP is assigned to a client, view the connection status on the VPN client.\n\nExample 1: Forward TCP port 443 on the VPN server to the IPsec/L2TP client at `192.168.42.10`.\n```\n# Get default network interface name\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\niptables -I FORWARD 2 -i \"$netif\" -o ppp+ -p tcp --dport 443 -j ACCEPT\niptables -t nat -A PREROUTING -i \"$netif\" -p tcp --dport 443 -j DNAT --to 192.168.42.10\n```\n\nExample 2: Forward UDP port 123 on the VPN server to the IKEv2 (or IPsec/XAuth) client at `192.168.43.10`.\n```\n# Get default network interface name\nnetif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\niptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -p udp --dport 123 -j ACCEPT\niptables -t nat -A PREROUTING -i \"$netif\" ! -s 192.168.43.0/24 -p udp --dport 123 -j DNAT --to 192.168.43.10\n```\n\nIf you want the rules to persist after reboot, you may add these commands to `/etc/rc.local`. To remove the added IPTables rules, run the commands again, but replace `-I FORWARD 2` with `-D FORWARD`, and replace `-A PREROUTING` with `-D PREROUTING`.\n\n## Split tunneling\n\nWith split tunneling, VPN clients will only send traffic for specific destination subnet(s) through the VPN tunnel. Other traffic will NOT go through the VPN tunnel. This allows you to gain secure access to a network through your VPN, without routing all your client's traffic through the VPN. Split tunneling has some limitations, and is not supported by all VPN clients.\n\nAdvanced users can optionally enable split tunneling for the [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth.md) and/or [IKEv2](ikev2-howto.md) modes. Expand for details. IPsec/L2TP mode does not support this feature (except on Windows, see below).\n\n<details>\n<summary>\nIPsec/XAuth (\"Cisco IPsec\") mode: Enable split tunneling\n</summary>\n\nThe example below **ONLY** applies to IPsec/XAuth (\"Cisco IPsec\") mode. Commands must be run as `root`.\n\n1. Edit `/etc/ipsec.conf` on the VPN server. In the section `conn xauth-psk`, replace `leftsubnet=0.0.0.0/0` with the subnet(s) you want VPN clients to send traffic through the VPN tunnel. For example:   \n   For a single subnet:\n   ```\n   leftsubnet=10.123.123.0/24\n   ```\n   For multiple subnets (use `leftsubnets` instead):\n   ```\n   leftsubnets=\"10.123.123.0/24,10.100.0.0/16\"\n   ```\n1. **(Important)** Restart the IPsec service:\n   ```\n   service ipsec restart\n   ```\n</details>\n\n<details>\n<summary>\nIKEv2 mode: Enable split tunneling\n</summary>\n\nThe example below **ONLY** applies to IKEv2 mode. Commands must be run as `root`.\n\n1. Edit `/etc/ipsec.d/ikev2.conf` on the VPN server. In the section `conn ikev2-cp`, replace `leftsubnet=0.0.0.0/0` with the subnet(s) you want VPN clients to send traffic through the VPN tunnel. For example:   \n   For a single subnet:\n   ```\n   leftsubnet=10.123.123.0/24\n   ```\n   For multiple subnets (use `leftsubnets` instead):\n   ```\n   leftsubnets=\"10.123.123.0/24,10.100.0.0/16\"\n   ```\n1. **(Important)** Restart the IPsec service:\n   ```\n   service ipsec restart\n   ```\n\n**Note:** Advanced users can set a different split tunneling configuration for specific IKEv2 client(s). Refer to section [Internal VPN IPs and traffic](#internal-vpn-ips-and-traffic) and expand \"IKEv2 mode: Assign static IPs to VPN clients\". Based on the example in that section, you may add the `leftsubnet=...` option to the `conn` section of the specific IKEv2 client, then restart the IPsec service.\n</details>\n\nAlternatively, Windows users can enable split tunneling by manually adding routes:\n\n1. Right-click on the wireless/network icon in your system tray.\n1. **Windows 11:** Select **Network and Internet settings**, then on the page that opens, click **Advanced network settings**. Click **More network adapter options**.   \n   **Windows 10:** Select **Open Network & Internet settings**, then on the page that opens, click **Network and Sharing Center**. On the left, click **Change adapter settings**.   \n   **Windows 8/7:** Select **Open Network and Sharing Center**. On the left, click **Change adapter settings**.\n1. Right-click on the new VPN connection, and choose **Properties**.\n1. Click the **Network** tab. Select **Internet Protocol Version 4 (TCP/IPv4)**, then click **Properties**.\n1. Click **Advanced**. Uncheck **Use default gateway on remote network**.\n1. Click **OK** to close the **Properties** window.\n1. **(Important)** Disconnect the VPN, then re-connect.\n1. Assume that the subnet you want VPN clients to send traffic through the VPN tunnel is `10.123.123.0/24`. Open an [elevated command prompt](http://www.winhelponline.com/blog/open-elevated-command-prompt-windows/) and run one of the following commands:   \n   For IKEv2 and IPsec/XAuth (\"Cisco IPsec\") modes:\n   ```\n   route add -p 10.123.123.0 mask 255.255.255.0 192.168.43.1\n   ```\n   For IPsec/L2TP mode:\n   ```\n   route add -p 10.123.123.0 mask 255.255.255.0 192.168.42.1\n   ```\n1. When finished, VPN clients will send traffic through the VPN tunnel for the specified subnet only. Other traffic will bypass the VPN.\n\n## Access VPN server's subnet\n\nAfter connecting to the VPN, VPN clients can generally access services running on other devices that are within the same local subnet as the VPN server, without additional configuration. For example, if the VPN server's local subnet is `192.168.0.0/24`, and an Nginx server is running on IP `192.168.0.2`, VPN clients can use IP `192.168.0.2` to access the Nginx server.\n\nPlease note, additional configuration is required if the VPN server has multiple network interfaces (e.g. `eth0` and `eth1`), and you want VPN clients to access the local subnet behind the network interface that is NOT for Internet access. In this scenario, you must run the following commands to add IPTables rules. To persist after reboot, you may add these commands to `/etc/rc.local`.\n\n```bash\n# Replace eth1 with the name of the network interface\n# on the VPN server that you want VPN clients to access\nnetif=eth1\niptables -I FORWARD 2 -i \"$netif\" -o ppp+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT\niptables -I FORWARD 2 -i ppp+ -o \"$netif\" -j ACCEPT\niptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT\niptables -I FORWARD 2 -s 192.168.43.0/24 -o \"$netif\" -j ACCEPT\niptables -t nat -I POSTROUTING -s 192.168.43.0/24 -o \"$netif\" -m policy --dir out --pol none -j MASQUERADE\niptables -t nat -I POSTROUTING -s 192.168.42.0/24 -o \"$netif\" -j MASQUERADE\n```\n\n## Access VPN clients from server's subnet\n\nIn certain circumstances, you may need to access services on VPN clients from other devices that are on the same local subnet as the VPN server. This can be done using the following steps.\n\nAssume that the VPN server IP is `10.1.0.2`, and the IP of the device from which you want to access VPN clients is `10.1.0.3`.\n\n1. Add IPTables rules on the VPN server to allow this traffic. For example:\n   ```\n   # Get default network interface name\n   netif=$(ip -4 route list 0/0 | grep -m 1 -Po '(?<=dev )(\\S+)')\n   iptables -I FORWARD 2 -i \"$netif\" -o ppp+ -s 10.1.0.3 -j ACCEPT\n   iptables -I FORWARD 2 -i \"$netif\" -d 192.168.43.0/24 -s 10.1.0.3 -j ACCEPT\n   ```\n2. Add routing rules on the device you want to access VPN clients. For example:\n   ```\n   # Replace eth0 with the network interface name of the device's local subnet\n   route add -net 192.168.42.0 netmask 255.255.255.0 gw 10.1.0.2 dev eth0\n   route add -net 192.168.43.0 netmask 255.255.255.0 gw 10.1.0.2 dev eth0\n   ```\n\nLearn more about internal VPN IPs in [Internal VPN IPs and traffic](#internal-vpn-ips-and-traffic).\n\n## Modify IPTables rules\n\nIf you want to modify IPTables rules after install, edit `/etc/iptables.rules` and/or `/etc/iptables/rules.v4` (Ubuntu/Debian), or `/etc/sysconfig/iptables` (CentOS/RHEL). Then reboot your server.\n\nIf [IPv6 support](#ipv6-support) is enabled, the corresponding ip6tables rules are saved in `/etc/ip6tables.rules` and `/etc/iptables/rules.v6` (Ubuntu/Debian), or `/etc/sysconfig/ip6tables` (CentOS/RHEL).\n\n**Note:** If your server runs CentOS Linux (or similar), and firewalld was active during VPN setup, nftables may be configured. In this case, edit `/etc/sysconfig/nftables.conf` instead of `/etc/sysconfig/iptables`.\n\n## Deploy Google BBR congestion control\n\nAfter the VPN server is set up, the performance can be improved by deploying the Google BBR congestion control algorithm.\n\nThis is usually done by modifying the configuration file `/etc/sysctl.conf`. However, some Linux distributions may additionally require updates to the Linux kernel.\n\nFor detailed deployment methods, please refer to [this document](bbr.md).\n\n## License\n\nCopyright (C) 2021-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nThis work is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nAttribution required: please include my name in any derivative and let me know how you have improved it!\n"
  },
  {
    "path": "docs/bbr-zh.md",
    "content": "[English](bbr.md) | [中文](bbr-zh.md)\n\n# 高级用法：部署 Google BBR 拥塞控制算法\n\nGoogle BBR是一种拥塞控制算法，它能够显著提升服务器吞吐率并降低延迟。\n\nGoogle BBR已经被内置于Linux内核4.9及更高版本中，但是需要手动开启。\n\n关于Google BBR算法，可以在这篇[官方博客](https://cloud.google.com/blog/products/networking/tcp-bbr-congestion-control-comes-to-gcp-your-internet-just-got-faster)或者这个[官方库](https://github.com/google/bbr)中找到更多信息。\n\n## 准备\n\n可以通过命令 `uname -r` 来查看当前Linux内核版本。版本大于等于4.9时，可以直接参照[下方的说明](#部署-google-bbr)部署BBR。\n\n通常而言，Ubuntu 18.04+, Debian 10+，CentOS 8+及RHEL 8+的内核版本都大于4.9。但是对于Amazon Linux 2，需要通过以下的方式更新内核之后才能部署Google BBR。\n\n### Amazon Linux 2\n\nAmazon Linux 2提供过经过验证的新版Linux内核，并可以通过启用预置的Extras库安装。\n\n1. 从Extras库安装 `kernel-ng`\n   ```bash\n   sudo amazon-linux-extras install kernel-ng\n   ```\n2. 更新包\n   ```bash\n   sudo yum update\n   ```\n3. 重启系统\n   ```bash\n   sudo reboot\n   ```\n4. 检查Linux内核版本\n   ```bash\n   uname -r\n   ```\n\n## 部署 Google BBR\n\n在这个部分，我们将通过修改配置文件启动Google BBR。\n\n1. 备份 `/etc/sysctl.conf`\n   ```bash\n   sudo cp /etc/sysctl.conf /etc/sysctl.conf.backup\n   ```\n2. 修改 `/etc/sysctl.conf`\n   ```bash\n   sudo vim /etc/sysctl.conf\n   ```\n   在文件中增加以下行\n   ```\n   net.core.default_qdisc = fq\n   net.ipv4.tcp_congestion_control = bbr\n   ```\n3. 启用Google BBR   \n   首先使用 `uname -r` 检查你的服务器的内核版本。   \n   对于内核版本 >= 4.20，应用 `sysctl` 设置：\n   ```bash\n   sudo sysctl -p\n   ```\n   对于内核版本 < 4.20，你必须重启服务器：\n   ```bash\n   sudo reboot\n   ```\n4. 检查Google BBR状态\n   ```bash\n   sudo sysctl net.ipv4.tcp_available_congestion_control\n   # net.ipv4.tcp_available_congestion_control = reno cubic bbr\n   sudo sysctl -n net.ipv4.tcp_congestion_control\n   # bbr\n   lsmod | grep bbr\n   # tcp_bbr  16384  0\n   ```\n\n## 文档作者\n\n版权所有 (C) 2022 [Leo Liu](https://github.com/optimusleobear)\n"
  },
  {
    "path": "docs/bbr.md",
    "content": "[English](bbr.md) | [中文](bbr-zh.md)\n\n# Advanced usage: Deploy Google BBR congestion control algorithm\n\nGoogle BBR is a congestion control algorithm that could significantly increase server throughput and reduce latency.\n\nGoogle BBR has been built into Linux kernel 4.9 and higher, but needs to be manually turned on.\n\nTo learn more about the Google BBR algorithm, see this [official blog](https://cloud.google.com/blog/products/networking/tcp-bbr-congestion-control-comes-to-gcp-your-internet-just-got-faster) or this [official repository](https://github.com/google/bbr).\n\n## Prepare\n\nYou can check the current Linux kernel version with the command `uname -r`. When the version is greater than or equal to 4.9, you can deploy BBR directly by referring to the [instructions below](#deploy-google-bbr).\n\nGenerally speaking, the kernel versions of Ubuntu 18.04+, Debian 10+, CentOS 8+ and RHEL 8+ are greater than 4.9. But for Amazon Linux 2, you need to update the kernel in the following ways before deploying Google BBR.\n\n### Amazon Linux 2\n\nAmazon Linux 2 provides newer versions of the verified Linux kernel, which can be installed from the Extras repository.\n\n1. Install `kernel-ng` from the Extras repository\n   ```bash\n   sudo amazon-linux-extras install kernel-ng\n   ```\n2. Update packages\n   ```bash\n   sudo yum update\n   ```\n3. Restart the system\n   ```bash\n   sudo reboot\n   ```\n4. Check the Linux kernel version\n   ```bash\n   uname -r\n   ```\n\n## Deploy Google BBR\n\nIn this section, we will start Google BBR by modifying the configuration file.\n\n1. Backup `/etc/sysctl.conf`\n   ```bash\n   sudo cp /etc/sysctl.conf /etc/sysctl.conf.backup\n   ```\n2. Modify `/etc/sysctl.conf`\n   ```bash\n   sudo vim /etc/sysctl.conf\n   ```\n   Add the following lines to the file\n   ```\n   net.core.default_qdisc = fq\n   net.ipv4.tcp_congestion_control = bbr\n   ```\n3. Enable Google BBR   \n   First, check your server's kernel version using `uname -r`.   \n   For kernel versions >= 4.20, apply `sysctl` settings:\n   ```bash\n   sudo sysctl -p\n   ```\n   For kernel versions < 4.20, you must reboot the server:\n   ```bash\n   sudo reboot\n   ```\n4. Check Google BBR status\n   ```bash\n   sudo sysctl net.ipv4.tcp_available_congestion_control\n   # net.ipv4.tcp_available_congestion_control = reno cubic bbr\n   sudo sysctl -n net.ipv4.tcp_congestion_control\n   # bbr\n   lsmod | grep bbr\n   # tcp_bbr  16384  0\n   ```\n\n## Document author\n\nCopyright (C) 2022 [Leo Liu](https://github.com/optimusleobear)   \nTranslated by [Lin Song](https://github.com/hwdsl2)\n"
  },
  {
    "path": "docs/clients-xauth-zh.md",
    "content": "[English](clients-xauth.md) | [中文](clients-xauth-zh.md)\n\n# 配置 IPsec/XAuth VPN 客户端\n\n在成功[搭建自己的 VPN 服务器](../README-zh.md)之后，按照下面的步骤来配置你的设备。IPsec/XAuth (\"Cisco IPsec\") 在 Android, iOS 和 OS X 上均受支持，无需安装额外的软件。Windows 用户可以使用免费的 [Shrew Soft 客户端](https://www.shrew.net/download/vpn)。如果无法连接,请首先检查是否输入了正确的 VPN 登录凭证。\n\nIPsec/XAuth 模式也称为 \"Cisco IPsec\"。该模式通常能够比 IPsec/L2TP **更高效**地传输数据（较低的额外开销）。\n\n---\n* 平台名称\n  * [Windows](#windows)\n  * [OS X (macOS)](#os-x-macos)\n  * [Android](#android)\n  * [iOS (iPhone/iPad)](#ios)\n  * [Linux](#linux)\n\n## Windows\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/L2TP](clients-zh.md) 模式连接。无需安装额外的软件。\n\n1. 下载并安装免费的 [Shrew Soft VPN 客户端](https://www.shrew.net/download/vpn)。在安装时请选择 **Standard Edition**。   \n   **注：** 该 VPN 客户端 **不支持** Windows 10/11。\n1. 单击开始菜单 -> 所有程序 -> ShrewSoft VPN Client -> VPN Access Manager\n1. 单击工具栏中的 **Add (+)** 按钮。\n1. 在 **Host Name or IP Address** 字段中输入`你的 VPN 服务器 IP`。\n1. 单击 **Authentication** 选项卡，从 **Authentication Method** 下拉菜单中选择 **Mutual PSK + XAuth**。\n1. 在 **Local Identity** 子选项卡中，从 **Identification Type** 下拉菜单中选择 **IP Address**。\n1. 单击 **Credentials** 子选项卡，并在 **Pre Shared Key** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **Phase 1** 选项卡，从 **Exchange Type** 下拉菜单中选择 **main**。\n1. 单击 **Phase 2** 选项卡，从 **HMAC Algorithm** 下拉菜单中选择 **sha1**。\n1. 单击 **Save** 保存 VPN 连接的详细信息。\n1. 选择新添加的 VPN 连接。单击工具栏中的 **Connect** 按钮。\n1. 在 **Username** 字段中输入`你的 VPN 用户名`。\n1. 在 **Password** 字段中输入`你的 VPN 密码`。\n1. 单击 **Connect**。\n\n连接成功后，你会在 VPN Connect 状态窗口中看到 **tunnel enabled** 字样。单击 \"Network\" 选项卡，并确认 **Established - 1** 显示在 \"Security Associations\" 下面。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](clients-zh.md#ikev1-故障排除)。\n\n## OS X (macOS)\n\n### macOS 13 (Ventura) 及以上\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/L2TP](clients-zh.md) 模式连接。\n\n1. 打开系统设置并转到网络部分。\n1. 在窗口右方单击 **VPN**。\n1. 从 **添加VPN配置** 下拉菜单选择 **Cisco IPSec**。\n1. 在打开的窗口中的 **显示名称** 字段中输入任意内容。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户名称** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 从 **类型** 下拉菜单选择 **共享密钥**。\n1. 在 **共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 保持 **群组名称** 字段空白。\n1. 单击 **创建** 保存 VPN 连接信息。\n1. 如果要在菜单栏显示 VPN 状态并快速访问相关设置，你可以转到系统设置的控制中心部分，滚动到页面底部并在 **VPN** 下拉菜单选择 **在菜单栏中显示**。\n\n要连接到 VPN：使用菜单栏中的图标，或者打开系统设置的 **VPN** 部分并启用 VPN 连接。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](clients-zh.md#ikev1-故障排除)。\n\n### macOS 12 (Monterey) 及以下\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/L2TP](clients-zh.md) 模式连接。\n\n1. 打开系统偏好设置并转到网络部分。\n1. 在窗口左下角单击 **+** 按钮。\n1. 从 **接口** 下拉菜单选择 **VPN**。\n1. 从 **VPN类型** 下拉菜单选择 **Cisco IPSec**。\n1. 在 **服务名称** 字段中输入任意内容。\n1. 单击 **创建**。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户名称** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 单击 **认证设置** 按钮。\n1. 在 **机器认证** 部分，选择 **共享的密钥** 单选按钮，然后输入`你的 VPN IPsec PSK`。\n1. 保持 **群组名称** 字段空白。\n1. 单击 **好**。\n1. 选中 **在菜单栏中显示 VPN 状态** 复选框。\n1. 单击 **应用** 保存 VPN 连接信息。\n\n要连接到 VPN：使用菜单栏中的图标，或者打开系统偏好设置的网络部分，选择 VPN 并单击 **连接**。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](clients-zh.md#ikev1-故障排除)。\n\n## Android\n\n**重要：** Android 用户应该使用更安全的 [IKEv2 模式](ikev2-howto-zh.md)连接（推荐）。Android 12+ 仅支持 IKEv2 模式。Android 系统自带的 VPN 客户端对 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式使用安全性较低的 `modp1024` (DH group 2)。\n\n如果你仍然想用 IPsec/XAuth 模式连接，你必须首先编辑 VPN 服务器上的 `/etc/ipsec.conf` 并在 `ike=...` 一行的末尾加上 `,aes256-sha2;modp1024,aes128-sha1;modp1024` 字样。保存文件并运行 `service ipsec restart`。\n\nDocker 用户：在[你的 env 文件](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#如何使用本镜像)中添加 `VPN_ENABLE_MODP1024=yes`，然后重新创建 Docker 容器。\n\n然后在你的 Android 设备上进行以下步骤：\n\n1. 启动 **设置** 应用程序。\n1. 单击 **网络和互联网**。或者，如果你使用 Android 7 或更早版本，在 **无线和网络** 部分单击 **更多...**。\n1. 单击 **VPN**。\n1. 单击 **添加VPN配置文件** 或窗口右上角的 **+**。\n1. 在 **名称** 字段中输入任意内容。\n1. 在 **类型** 下拉菜单选择 **IPSec Xauth PSK**。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 保持 **IPSec 标识符** 字段空白。\n1. 在 **IPSec 预共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **保存**。\n1. 单击新的VPN连接。\n1. 在 **用户名** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 选中 **保存帐户信息** 复选框。\n1. 单击 **连接**。\n\n连接成功后，会在通知栏显示图标。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](clients-zh.md#ikev1-故障排除)。\n\n## iOS\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/L2TP](clients-zh.md) 模式连接。\n\n1. 进入设置 -> 通用 -> VPN。\n1. 单击 **添加VPN配置...**。\n1. 单击 **类型** 。选择 **IPSec** 并返回。\n1. 在 **描述** 字段中输入任意内容。\n1. 在 **服务器** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 保持 **群组名称** 字段空白。\n1. 在 **密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击右上角的 **完成**。\n1. 启用 **VPN** 连接。\n\n连接成功后，会在通知栏显示图标。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](clients-zh.md#ikev1-故障排除)。\n\n## Linux\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐）。\n\n### Fedora 和 CentOS\n\nFedora 28 （和更新版本）和 CentOS 8/7 用户可以使用 `yum` 安装 `NetworkManager-libreswan-gnome` 软件包，然后通过 GUI 配置 IPsec/XAuth VPN 客户端。\n\n1. 进入 Settings -> Network -> VPN。单击 **+** 按钮。\n1. 选择 **IPsec based VPN**。\n1. 在 **Name** 字段中输入任意内容。\n1. 在 **Gateway** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **Type** 下拉菜单选择 **IKEv1 (XAUTH)**。\n1. 在 **User name** 字段中输入`你的 VPN 用户名`。\n1. 右键单击 **User password** 字段中的 **?**，选择 **Store the password only for this user**。\n1. 在 **User password** 字段中输入`你的 VPN 密码`。\n1. 保持 **Group name** 字段空白。\n1. 右键单击 **Secret** 字段中的 **?**，选择 **Store the password only for this user**。\n1. 在 **Secret** 字段中输入`你的 VPN IPsec PSK`。\n1. 保持 **Remote ID** 字段空白。\n1. 单击 **Add** 保存 VPN 连接信息。\n1. 启用 **VPN** 连接。\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n### 其它 Linux\n\n其它 Linux 版本用户可以使用 [IPsec/L2TP](clients-zh.md#linux) 模式连接。\n\n## 授权协议\n\n注： 这个协议仅适用于本文档。\n\n版权所有 (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n受到 [Joshua Lund 的工作](https://github.com/StreisandEffect/streisand/blob/6aa6b6b2735dd829ca8c417d72eb2768a89b6639/playbooks/roles/l2tp-ipsec/templates/instructions.md.j2)的启发\n\n本程序为自由软件，在自由软件联盟发布的[ GNU 通用公共许可协议](https://www.gnu.org/licenses/gpl.html)的约束下，你可以对其进行再发布及修改。协议版本为第三版或（随你）更新的版本。\n\n我们希望发布的这款程序有用，但不保证，甚至不保证它有经济价值和适合特定用途。详情参见GNU通用公共许可协议。\n"
  },
  {
    "path": "docs/clients-xauth.md",
    "content": "[English](clients-xauth.md) | [中文](clients-xauth-zh.md)\n\n# Configure IPsec/XAuth VPN Clients\n\nAfter [setting up your own VPN server](https://github.com/hwdsl2/setup-ipsec-vpn), follow these steps to configure your devices. IPsec/XAuth (\"Cisco IPsec\") is natively supported by Android, iOS and OS X. There is no additional software to install. Windows users can use the free [Shrew Soft client](https://www.shrew.net/download/vpn). In case you are unable to connect, first check to make sure the VPN credentials were entered correctly.\n\nIPsec/XAuth mode is also called \"Cisco IPsec\". This mode is generally **faster than** IPsec/L2TP with less overhead.\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [OS X (macOS)](#os-x-macos)\n  * [Android](#android)\n  * [iOS (iPhone/iPad)](#ios)\n  * [Linux](#linux)\n\n## Windows\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/L2TP](clients.md) mode. No additional software is required.\n\n1. Download and install the free [Shrew Soft VPN client](https://www.shrew.net/download/vpn). When prompted during install, select **Standard Edition**.   \n   **Note:** This VPN client does NOT support Windows 10/11.\n1. Click Start Menu -> All Programs -> ShrewSoft VPN Client -> VPN Access Manager\n1. Click the **Add (+)** button on toolbar.\n1. Enter `Your VPN Server IP` in the **Host Name or IP Address** field.\n1. Click the **Authentication** tab. Select **Mutual PSK + XAuth** from the **Authentication Method** drop-down menu.\n1. Under the **Local Identity** sub-tab, select **IP Address** from the **Identification Type** drop-down menu.\n1. Click the **Credentials** sub-tab. Enter `Your VPN IPsec PSK` in the **Pre Shared Key** field.\n1. Click the **Phase 1** tab. Select **main** from the **Exchange Type** drop-down menu.\n1. Click the **Phase 2** tab. Select **sha1** from the **HMAC Algorithm** drop-down menu.\n1. Click **Save** to save the VPN connection details.\n1. Select the new VPN connection. Click the **Connect** button on toolbar.\n1. Enter `Your VPN Username` in the **Username** field.\n1. Enter `Your VPN Password` in the **Password** field.\n1. Click **Connect**.\n\nOnce connected, you will see **tunnel enabled** in the VPN Connect status window. Click the \"Network\" tab, and confirm that **Established - 1** is displayed under \"Security Associations\". You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](clients.md#ikev1-troubleshooting).\n\n## OS X (macOS)\n\n### macOS 13 (Ventura) and newer\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/L2TP](clients.md) mode.\n\n1. Open **System Settings** and go to the **Network** section.\n1. Click **VPN** on the right hand side of the window.\n1. Click the **Add VPN Configuration** drop-down menu and select **Cisco IPSec**.\n1. In the window that opens, enter anything you like for the **Display name**.\n1. Enter `Your VPN Server IP` for the **Server address**.\n1. Enter `Your VPN Username` for the **Account name**.\n1. Enter `Your VPN Password` for the **Password**.\n1. Select **Shared secret** from the **Type** drop-down menu.\n1. Enter `Your VPN IPsec PSK` for the **Shared secret**.\n1. Leave the **Group name** field blank.\n1. Click **Create** to save the VPN configuration.\n1. To show VPN status in your menu bar and for shortcut access, go to the **Control Center** section of **System Settings**. Scroll to the bottom and select `Show in Menu Bar` from the **VPN** drop-down menu.\n\nTo connect to the VPN: Use the menu bar icon, or go to the **VPN** section of **System Settings** and toggle the switch for your VPN configuration. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](clients.md#ikev1-troubleshooting).\n\n### macOS 12 (Monterey) and older\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/L2TP](clients.md) mode.\n\n1. Open System Preferences and go to the Network section.\n1. Click the **+** button in the lower-left corner of the window.\n1. Select **VPN** from the **Interface** drop-down menu.\n1. Select **Cisco IPSec** from the **VPN Type** drop-down menu.\n1. Enter anything you like for the **Service Name**.\n1. Click **Create**.\n1. Enter `Your VPN Server IP` for the **Server Address**.\n1. Enter `Your VPN Username` for the **Account Name**.\n1. Enter `Your VPN Password` for the **Password**.\n1. Click the **Authentication Settings** button.\n1. In the **Machine Authentication** section, select the **Shared Secret** radio button and enter `Your VPN IPsec PSK`.\n1. Leave the **Group Name** field blank.\n1. Click **OK**.\n1. Check the **Show VPN status in menu bar** checkbox.\n1. Click **Apply** to save the VPN connection information.\n\nTo connect to the VPN: Use the menu bar icon, or go to the Network section of System Preferences, select the VPN and choose **Connect**. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](clients.md#ikev1-troubleshooting).\n\n## Android\n\n**Important:** Android users should instead connect using [IKEv2 mode](ikev2-howto.md) (recommended), which is more secure. Android 12+ only supports IKEv2 mode. The native VPN client in Android uses the less secure `modp1024` (DH group 2) for the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nIf you still want to connect using IPsec/XAuth mode, you must first edit `/etc/ipsec.conf` on the VPN server. Find the line `ike=...` and append `,aes256-sha2;modp1024,aes128-sha1;modp1024` at the end. Save the file and run `service ipsec restart`.\n\nDocker users: Add `VPN_ENABLE_MODP1024=yes` to [your env file](https://github.com/hwdsl2/docker-ipsec-vpn-server#how-to-use-this-image), then re-create the Docker container.\n\nAfter that, follow the steps below on your Android device:\n\n1. Launch the **Settings** application.\n1. Tap \"Network & internet\". Or, if using Android 7 or earlier, tap **More...** in the **Wireless & networks** section.\n1. Tap **VPN**.\n1. Tap **Add VPN Profile** or the **+** icon at top-right of screen.\n1. Enter anything you like in the **Name** field.\n1. Select **IPSec Xauth PSK** in the **Type** drop-down menu.\n1. Enter `Your VPN Server IP` in the **Server address** field.\n1. Leave the **IPSec identifier** field blank.\n1. Enter `Your VPN IPsec PSK` in the **IPSec pre-shared key** field.\n1. Tap **Save**.\n1. Tap the new VPN connection.\n1. Enter `Your VPN Username` in the **Username** field.\n1. Enter `Your VPN Password` in the **Password** field.\n1. Check the **Save account information** checkbox.\n1. Tap **Connect**.\n\nOnce connected, you will see a VPN icon in the notification bar. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](clients.md#ikev1-troubleshooting).\n\n## iOS\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/L2TP](clients.md) mode.\n\n1. Go to Settings -> General -> VPN.\n1. Tap **Add VPN Configuration...**.\n1. Tap **Type**. Select **IPSec** and go back.\n1. Tap **Description** and enter anything you like.\n1. Tap **Server** and enter `Your VPN Server IP`.\n1. Tap **Account** and enter `Your VPN Username`.\n1. Tap **Password** and enter `Your VPN Password`.\n1. Leave the **Group Name** field blank.\n1. Tap **Secret** and enter `Your VPN IPsec PSK`.\n1. Tap **Done**.\n1. Slide the **VPN** switch ON.\n\nOnce connected, you will see a VPN icon in the status bar. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](clients.md#ikev1-troubleshooting).\n\n## Linux\n\n> You may also connect using [IKEv2](ikev2-howto.md) mode (recommended).\n\n### Fedora and CentOS\n\nFedora 28 (and newer) and CentOS 8/7 users can install the `NetworkManager-libreswan-gnome` package using `yum`, then configure the IPsec/XAuth VPN client using the GUI.\n\n1. Go to Settings -> Network -> VPN. Click the **+** button.\n1. Select **IPsec based VPN**.\n1. Enter anything you like in the **Name** field.\n1. Enter `Your VPN Server IP` for the **Gateway**.\n1. Select **IKEv1 (XAUTH)** in the **Type** drop-down menu.\n1. Enter `Your VPN Username` for the **User name**.\n1. Right-click the **?** in the **User password** field, select **Store the password only for this user**.\n1. Enter `Your VPN Password` for the **User password**.\n1. Leave the **Group name** field blank.\n1. Right-click the **?** in the **Secret** field, select **Store the password only for this user**.\n1. Enter `Your VPN IPsec PSK` for the **Secret**.\n1. Leave the **Remote ID** field blank.\n1. Click **Add** to save the VPN connection information.\n1. Turn the **VPN** switch ON.\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\n### Other Linux\n\nOther Linux users can connect using [IPsec/L2TP](clients.md#linux) mode.\n\n## License\n\nNote: This license applies to this document only.\n\nCopyright (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \nInspired by [the work of Joshua Lund](https://github.com/StreisandEffect/streisand/blob/6aa6b6b2735dd829ca8c417d72eb2768a89b6639/playbooks/roles/l2tp-ipsec/templates/instructions.md.j2)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the [GNU General Public License](https://www.gnu.org/licenses/gpl.html) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n"
  },
  {
    "path": "docs/clients-zh.md",
    "content": "[English](clients.md) | [中文](clients-zh.md)\n\n# 配置 IPsec/L2TP VPN 客户端\n\n在成功[搭建自己的 VPN 服务器](../README-zh.md)之后，按照下面的步骤来配置你的设备。IPsec/L2TP 在 Android, iOS, OS X 和 Windows 上均受支持，无需安装额外的软件。设置过程通常只需要几分钟。如果无法连接,请首先检查是否输入了正确的 VPN 登录凭证。\n\n---\n* 平台名称\n  * [Windows](#windows)\n  * [OS X (macOS)](#os-x-macos)\n  * [Android](#android)\n  * [iOS (iPhone/iPad)](#ios)\n  * [Chrome OS (Chromebook)](#chrome-os)\n  * [Linux](#linux)\n* [IKEv1 故障排除](#ikev1-故障排除)\n\n## Windows\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐）。\n\n### Windows 11\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. 选择 **网络和 Internet 设置**，然后在打开的页面中单击 **VPN**。\n1. 单击 **添加 VPN** 按钮。\n1. 从 **VPN 提供商** 下拉菜单选择 **Windows (内置)**。\n1. 在 **连接名称** 字段中输入任意内容。\n1. 在 **服务器名称或地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 从 **VPN 类型** 下拉菜单选择 **使用预共享密钥的 L2TP/IPsec**。\n1. 在 **预共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 在 **用户名** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 选中 **记住我的登录信息** 复选框。\n1. 单击 **保存** 保存 VPN 连接的详细信息。\n\n**注：** 在首次连接之前需要[修改一次注册表](#windows-错误-809)，以解决 VPN 服务器 和/或 客户端与 NAT （比如家用路由器）的兼容问题。\n\n要连接到 VPN：单击 **连接** 按钮，或者单击系统托盘中的无线/网络图标，单击 **VPN**，然后选择新的 VPN 连接并单击 **连接**。如果出现提示，在登录窗口中输入 `你的 VPN 用户名` 和 `密码` ，并单击 **确定**。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n### Windows 10 and 8\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. 选择 **打开\"网络和 Internet\"设置**，然后在打开的页面中单击 **网络和共享中心**。\n1. 单击 **设置新的连接或网络**。\n1. 选择 **连接到工作区**，然后单击 **下一步**。\n1. 单击 **使用我的Internet连接 (VPN)**。\n1. 在 **Internet地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **目标名称** 字段中输入任意内容。单击 **创建**。\n1. 返回 **网络和共享中心**。单击左侧的 **更改适配器设置**。\n1. 右键单击新创建的 VPN 连接，并选择 **属性**。\n1. 单击 **安全** 选项卡，从 **VPN 类型** 下拉菜单中选择 \"使用 IPsec 的第 2 层隧道协议 (L2TP/IPSec)\"。\n1. 单击 **允许使用这些协议**。选中 \"质询握手身份验证协议 (CHAP)\" 和 \"Microsoft CHAP 版本 2 (MS-CHAP v2)\" 复选框。\n1. 单击 **高级设置** 按钮。\n1. 单击 **使用预共享密钥作身份验证** 并在 **密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **确定** 关闭 **高级设置**。\n1. 单击 **确定** 保存 VPN 连接的详细信息。\n\n**注：** 在首次连接之前需要[修改一次注册表](#windows-错误-809)，以解决 VPN 服务器 和/或 客户端与 NAT （比如家用路由器）的兼容问题。\n\n要连接到 VPN：单击系统托盘中的无线/网络图标，选择新的 VPN 连接，然后单击 **连接**。如果出现提示，在登录窗口中输入 `你的 VPN 用户名` 和 `密码` ，并单击 **确定**。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n另外，除了按照以上步骤操作，你也可以运行下面的 Windows PowerShell 命令来创建 VPN 连接。将 `你的 VPN 服务器 IP` 和 `你的 VPN IPsec PSK` 换成你自己的值，用单引号括起来：\n\n```console\n# 不保存命令行历史记录\nSet-PSReadlineOption –HistorySaveStyle SaveNothing\n# 创建 VPN 连接\nAdd-VpnConnection -Name 'My IPsec VPN' -ServerAddress '你的 VPN 服务器 IP' `\n  -L2tpPsk '你的 VPN IPsec PSK' -TunnelType L2tp -EncryptionLevel Required `\n  -AuthenticationMethod Chap,MSChapv2 -Force -RememberCredential -PassThru\n# 忽略 data encryption 警告（数据在 IPsec 隧道中已被加密）\n```\n\n### Windows 7, Vista and XP\n\n1. 单击开始菜单，选择控制面板。\n1. 进入 **网络和Internet** 部分。\n1. 单击 **网络和共享中心**。\n1. 单击 **设置新的连接或网络**。\n1. 选择 **连接到工作区**，然后单击 **下一步**。\n1. 单击 **使用我的Internet连接 (VPN)**。\n1. 在 **Internet地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **目标名称** 字段中输入任意内容。\n1. 选中 **现在不连接；仅进行设置以便稍后连接** 复选框。\n1. 单击 **下一步**。\n1. 在 **用户名** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 选中 **记住此密码** 复选框。\n1. 单击 **创建**，然后单击 **关闭** 按钮。\n1. 返回 **网络和共享中心**。单击左侧的 **更改适配器设置**。\n1. 右键单击新创建的 VPN 连接，并选择 **属性**。\n1. 单击 **选项** 选项卡，取消选中 **包括Windows登录域** 复选框。\n1. 单击 **安全** 选项卡，从 **VPN 类型** 下拉菜单中选择 \"使用 IPsec 的第 2 层隧道协议 (L2TP/IPSec)\"。\n1. 单击 **允许使用这些协议**。选中 \"质询握手身份验证协议 (CHAP)\" 和 \"Microsoft CHAP 版本 2 (MS-CHAP v2)\" 复选框。\n1. 单击 **高级设置** 按钮。\n1. 单击 **使用预共享密钥作身份验证** 并在 **密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **确定** 关闭 **高级设置**。\n1. 单击 **确定** 保存 VPN 连接的详细信息。\n\n**注：** 在首次连接之前需要[修改一次注册表](#windows-错误-809)，以解决 VPN 服务器 和/或 客户端与 NAT （比如家用路由器）的兼容问题。\n\n要连接到 VPN：单击系统托盘中的无线/网络图标，选择新的 VPN 连接，然后单击 **连接**。如果出现提示，在登录窗口中输入 `你的 VPN 用户名` 和 `密码` ，并单击 **确定**。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n## OS X (macOS)\n\n### macOS 13 (Ventura) 及以上\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/XAuth](clients-xauth-zh.md) 模式连接。\n\n1. 打开系统设置并转到网络部分。\n1. 在窗口右方单击 **VPN**。\n1. 从 **添加VPN配置** 下拉菜单选择 **L2TP/IPSec**。\n1. 在打开的窗口中的 **显示名称** 字段中输入任意内容。\n1. 保持 **配置** 为 **默认**。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户名称** 字段中输入`你的 VPN 用户名`。\n1. 从 **用户认证** 下拉菜单选择 **密码**。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 从 **机器认证** 下拉菜单选择 **共享密钥**。\n1. 在 **共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 保持 **群组名称** 字段空白。\n1. **（重要）** 单击 **选项** 选项卡，并启用 **通过VPN连接发送所有流量**。\n1. **（重要）** 单击 **TCP/IP** 选项卡，然后在 **配置IPv6** 下拉菜单选择 **仅本地链接**。\n1. 单击 **创建** 保存 VPN 连接信息。\n1. 如果要在菜单栏显示 VPN 状态并快速访问相关设置，你可以转到系统设置的控制中心部分，滚动到页面底部并在 **VPN** 下拉菜单选择 **在菜单栏中显示**。\n\n要连接到 VPN：使用菜单栏中的图标，或者打开系统设置的 **VPN** 部分并启用 VPN 连接。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n### macOS 12 (Monterey) 及以下\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/XAuth](clients-xauth-zh.md) 模式连接。\n\n1. 打开系统偏好设置并转到网络部分。\n1. 在窗口左下角单击 **+** 按钮。\n1. 从 **接口** 下拉菜单选择 **VPN**。\n1. 从 **VPN类型** 下拉菜单选择 **IPSec 上的 L2TP**。\n1. 在 **服务名称** 字段中输入任意内容。\n1. 单击 **创建**。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户名称** 字段中输入`你的 VPN 用户名`。\n1. 单击 **认证设置** 按钮。\n1. 在 **用户认证** 部分，选择 **密码** 单选按钮，然后输入`你的 VPN 密码`。\n1. 在 **机器认证** 部分，选择 **共享的密钥** 单选按钮，然后输入`你的 VPN IPsec PSK`。\n1. 保持 **群组名称** 字段空白。\n1. 单击 **好**。\n1. 选中 **在菜单栏中显示 VPN 状态** 复选框。\n1. **（重要）** 单击 **高级** 按钮，并选中 **通过VPN连接发送所有通信** 复选框。\n1. **（重要）** 单击 **TCP/IP** 选项卡，并在 **配置IPv6** 部分中选择 **仅本地链接**。\n1. 单击 **好** 关闭高级设置，然后单击 **应用** 保存 VPN 连接信息。\n\n要连接到 VPN：使用菜单栏中的图标，或者打开系统偏好设置的网络部分，选择 VPN 并单击 **连接**。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n## Android\n\n**重要：** Android 用户应该使用更安全的 [IKEv2 模式](ikev2-howto-zh.md)连接（推荐）。Android 12+ 仅支持 IKEv2 模式。Android 系统自带的 VPN 客户端对 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式使用安全性较低的 `modp1024` (DH group 2)。\n\n如果你仍然想用 IPsec/L2TP 模式连接，你必须首先编辑 VPN 服务器上的 `/etc/ipsec.conf` 并在 `ike=...` 一行的末尾加上 `,aes256-sha2;modp1024,aes128-sha1;modp1024` 字样。保存文件并运行 `service ipsec restart`。\n\nDocker 用户：在[你的 env 文件](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#如何使用本镜像)中添加 `VPN_ENABLE_MODP1024=yes`，然后重新创建 Docker 容器。\n\n然后在你的 Android 设备上进行以下步骤：\n\n1. 启动 **设置** 应用程序。\n1. 单击 **网络和互联网**。或者，如果你使用 Android 7 或更早版本，在 **无线和网络** 部分单击 **更多...**。\n1. 单击 **VPN**。\n1. 单击 **添加VPN配置文件** 或窗口右上角的 **+**。\n1. 在 **名称** 字段中输入任意内容。\n1. 在 **类型** 下拉菜单选择 **L2TP/IPSec PSK**。\n1. 在 **服务器地址** 字段中输入`你的 VPN 服务器 IP`。\n1. 保持 **L2TP 密钥** 字段空白。\n1. 保持 **IPSec 标识符** 字段空白。\n1. 在 **IPSec 预共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **保存**。\n1. 单击新的VPN连接。\n1. 在 **用户名** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 选中 **保存帐户信息** 复选框。\n1. 单击 **连接**。\n\n连接成功后，会在通知栏显示图标。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n## iOS\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md)（推荐）或者 [IPsec/XAuth](clients-xauth-zh.md) 模式连接。\n\n1. 进入设置 -> 通用 -> VPN。\n1. 单击 **添加VPN配置...**。\n1. 单击 **类型** 。选择 **L2TP** 并返回。\n1. 在 **描述** 字段中输入任意内容。\n1. 在 **服务器** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **帐户** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 在 **密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 启用 **发送所有流量** 选项。\n1. 单击右上角的 **完成**。\n1. 启用 **VPN** 连接。\n\n连接成功后，会在通知栏显示图标。最后你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n## Chrome OS\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐）。\n\n1. 进入设置 -> 网络。\n1. 单击 **添加连接**，然后单击 **添加内置 VPN**。\n1. 在 **服务名称** 字段中输入任意内容。\n1. 在 **提供商类型** 下拉菜单选择 **L2TP/IPsec**。\n1. 在 **服务器主机名** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **身份验证类型** 下拉菜单选择 **预共享密钥**。\n1. 在 **用户名** 字段中输入`你的 VPN 用户名`。\n1. 在 **密码** 字段中输入`你的 VPN 密码`。\n1. 在 **预共享密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 保持其他字段空白。\n1. 启用 **保存身份信息和密码**。\n1. 单击 **连接**。\n\n连接成功后，网络状态图标上会出现 VPN 指示。你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev1-故障排除)。\n\n## Linux\n\n> 你也可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐）。\n\n### Ubuntu Linux\n\nUbuntu 18.04 和更新版本用户可以使用 `apt` 安装 [network-manager-l2tp-gnome](https://packages.ubuntu.com/search?keywords=network-manager-l2tp-gnome) 软件包，然后通过 GUI 配置 IPsec/L2TP VPN 客户端。\n\n1. 进入 Settings -> Network -> VPN。单击 **+** 按钮。\n1. 选择 **Layer 2 Tunneling Protocol (L2TP)**。\n1. 在 **Name** 字段中输入任意内容。\n1. 在 **Gateway** 字段中输入`你的 VPN 服务器 IP`。\n1. 在 **User name** 字段中输入`你的 VPN 用户名`。\n1. 右键单击 **Password** 字段中的 **?**，选择 **Store the password only for this user**。\n1. 在 **Password** 字段中输入`你的 VPN 密码`。\n1. 保持 **NT Domain** 字段空白。\n1. 单击 **IPsec Settings...** 按钮。\n1. 选中 **Enable IPsec tunnel to L2TP host** 复选框。\n1. 保持 **Gateway ID** 字段空白。\n1. 在 **Pre-shared key** 字段中输入`你的 VPN IPsec PSK`。\n1. 展开 **Advanced** 部分。\n1. 在 **Phase1 Algorithms** 字段中输入 `aes128-sha1-modp2048`。\n1. 在 **Phase2 Algorithms** 字段中输入 `aes128-sha1`。\n1. 单击 **OK**，然后单击 **Add** 保存 VPN 连接信息。\n1. 启用 **VPN** 连接。\n\n如果在连接过程中遇到错误，请尝试[这个解决方案](https://github.com/nm-l2tp/NetworkManager-l2tp/blob/2926ea0239fe970ff08cb8a7863f8cb519ece032/README.md#unable-to-establish-l2tp-connection-without-udp-source-port-1701)。\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n### Fedora 和 CentOS\n\nFedora 28（和更新版本）和 CentOS 8/7 用户可以使用 [IPsec/XAuth](clients-xauth-zh.md) 模式连接。\n\n### 其它 Linux\n\n首先看[这里](https://github.com/nm-l2tp/NetworkManager-l2tp/wiki/Prebuilt-Packages)以确认 `network-manager-l2tp` 和 `network-manager-l2tp-gnome` 软件包是否在你的 Linux 版本上可用。如果可用，安装它们（选择使用 strongSwan）并参见上面的说明。另外，你也可以使用命令行配置 Linux VPN 客户端。\n\n### 使用命令行配置 Linux VPN 客户端\n\n高级用户可以使用命令行配置 Linux VPN 客户端。另外，你也可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐），或者[使用图形界面配置](#linux)。以下说明受到 [Peter Sanford 的工作](https://gist.github.com/psanford/42c550a1a6ad3cb70b13e4aaa94ddb1c)的启发。这些命令必须在你的 VPN 客户端上使用 `root` 账户运行。\n\n要配置 VPN 客户端，首先安装以下软件包：\n\n```bash\n# Ubuntu and Debian\napt-get update\napt-get install strongswan xl2tpd net-tools\n\n# Fedora\nyum install strongswan xl2tpd net-tools\n\n# CentOS\nyum install epel-release\nyum --enablerepo=epel install strongswan xl2tpd net-tools\n```\n\n创建 VPN 变量（替换为你自己的值）：\n\n```bash\nVPN_SERVER_IP='你的VPN服务器IP'\nVPN_IPSEC_PSK='你的IPsec预共享密钥'\nVPN_USER='你的VPN用户名'\nVPN_PASSWORD='你的VPN密码'\n```\n\n配置 strongSwan：\n\n```bash\ncat > /etc/ipsec.conf <<EOF\n# ipsec.conf - strongSwan IPsec configuration file\n\nconn myvpn\n  auto=add\n  keyexchange=ikev1\n  authby=secret\n  type=transport\n  left=%defaultroute\n  leftprotoport=17/1701\n  rightprotoport=17/1701\n  right=$VPN_SERVER_IP\n  ike=aes128-sha1-modp2048\n  esp=aes128-sha1\nEOF\n\ncat > /etc/ipsec.secrets <<EOF\n: PSK \"$VPN_IPSEC_PSK\"\nEOF\n\nchmod 600 /etc/ipsec.secrets\n\n# For CentOS and Fedora ONLY\nmv /etc/strongswan/ipsec.conf /etc/strongswan/ipsec.conf.old 2>/dev/null\nmv /etc/strongswan/ipsec.secrets /etc/strongswan/ipsec.secrets.old 2>/dev/null\nln -s /etc/ipsec.conf /etc/strongswan/ipsec.conf\nln -s /etc/ipsec.secrets /etc/strongswan/ipsec.secrets\n```\n\n配置 xl2tpd：\n\n```bash\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[lac myvpn]\nlns = $VPN_SERVER_IP\nppp debug = yes\npppoptfile = /etc/ppp/options.l2tpd.client\nlength bit = yes\nEOF\n\ncat > /etc/ppp/options.l2tpd.client <<EOF\nipcp-accept-local\nipcp-accept-remote\nrefuse-eap\nrequire-chap\nnoccp\nnoauth\nmtu 1280\nmru 1280\nnoipdefault\ndefaultroute\nusepeerdns\nconnect-delay 5000\nname \"$VPN_USER\"\npassword \"$VPN_PASSWORD\"\nEOF\n\nchmod 600 /etc/ppp/options.l2tpd.client\n```\n\n至此 VPN 客户端配置已完成。按照下面的步骤进行连接。\n\n**注：** 当你每次尝试连接到 VPN 时，必须重复下面的所有步骤。\n\n创建 xl2tpd 控制文件：\n\n```bash\nmkdir -p /var/run/xl2tpd\ntouch /var/run/xl2tpd/l2tp-control\n```\n\n重启服务：\n\n```bash\nservice strongswan restart\n\n# 适用于 Ubuntu，如果 strongswan 服务不存在\nipsec restart\n\nservice xl2tpd restart\n```\n\n开始 IPsec 连接：\n\n```bash\n# Ubuntu and Debian\nipsec up myvpn\n\n# CentOS and Fedora\nstrongswan up myvpn\n```\n\n开始 L2TP 连接：\n\n```bash\necho \"c myvpn\" > /var/run/xl2tpd/l2tp-control\n```\n\n运行 `ifconfig` 并且检查输出。现在你应该看到一个新的网络接口 `ppp0`。\n\n检查你现有的默认路由：\n\n```bash\nip route\n```\n\n在输出中查找以下行： `default via X.X.X.X ...`。记下这个网关 IP，并且在下面的两个命令中使用。\n\n从新的默认路由中排除你的 VPN 服务器的公有 IP（替换为你自己的值）：\n\n```bash\nroute add 你的VPN服务器的公有IP gw X.X.X.X\n```\n\n如果你的 VPN 客户端是一个远程服务器，则必须从新的默认路由中排除你的本地电脑的公有 IP，以避免 SSH 会话被断开（替换为[实际值](https://www.ipchicken.com)）：\n\n```bash\nroute add 你的本地电脑的公有IP gw X.X.X.X\n```\n\n添加一个新的默认路由，并且开始通过 VPN 服务器发送数据：\n\n```bash\nroute add default dev ppp0\n```\n\n至此 VPN 连接已成功完成。检查 VPN 是否正常工作：\n\n```bash\nwget -qO- http://ipv4.icanhazip.com; echo\n```\n\n以上命令应该返回 `你的 VPN 服务器 IP`。\n\n\n要停止通过 VPN 服务器发送数据：\n\n```bash\nroute del default dev ppp0\n```\n\n要断开连接：\n\n```bash\n# Ubuntu and Debian\necho \"d myvpn\" > /var/run/xl2tpd/l2tp-control\nipsec down myvpn\n\n# CentOS and Fedora\necho \"d myvpn\" > /var/run/xl2tpd/l2tp-control\nstrongswan down myvpn\n```\n\n## IKEv1 故障排除\n\n*其他语言版本: [English](clients.md#ikev1-troubleshooting), [中文](clients-zh.md#ikev1-故障排除)。*\n\n**另见：** [IKEv2 故障排除](ikev2-howto-zh.md#ikev2-故障排除)和[高级用法](advanced-usage-zh.md)。\n\n* [检查日志及 VPN 状态](#检查日志及-vpn-状态)\n* [Windows 错误 809](#windows-错误-809)\n* [Windows 错误 789 或 691](#windows-错误-789-或-691)\n* [Windows 错误 628 或 766](#windows-错误-628-或-766)\n* [Windows 10 正在连接](#windows-10-正在连接)\n* [Windows 10/11 升级](#windows-1011-升级)\n* [Windows DNS 泄漏和 IPv6](#windows-dns-泄漏和-ipv6)\n* [Android/Linux MTU/MSS 问题](#androidlinux-mtumss-问题)\n* [macOS 通过 VPN 发送通信](#macos-通过-vpn-发送通信)\n* [iOS/Android 睡眠模式](#iosandroid-睡眠模式)\n* [Debian 内核](#debian-内核)\n\n### 检查日志及 VPN 状态\n\n以下命令需要使用 `root` 账户（或者 `sudo`）运行。\n\n首先，重启 VPN 服务器上的相关服务：\n\n```bash\nservice ipsec restart\nservice xl2tpd restart\n```\n\n**Docker 用户：** 运行 `docker restart ipsec-vpn-server`。\n\n然后重启你的 VPN 客户端设备，并重试连接。如果仍然无法连接，可以尝试删除并重新创建 VPN 连接。请确保输入了正确的 VPN 服务器地址和 VPN 登录凭证。\n\n对于有外部防火墙的服务器（比如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），请为 VPN 打开 UDP 端口 500 和 4500。\n\n检查 Libreswan (IPsec) 和 xl2tpd 日志是否有错误：\n\n```bash\n# Ubuntu & Debian\ngrep pluto /var/log/auth.log\ngrep xl2tpd /var/log/syslog\n\n# CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\ngrep pluto /var/log/secure\ngrep xl2tpd /var/log/messages\n\n# Alpine Linux\ngrep pluto /var/log/messages\ngrep xl2tpd /var/log/messages\n```\n\n检查 IPsec VPN 服务器状态：\n\n```bash\nipsec status\n```\n\n查看当前已建立的 VPN 连接：\n\n```bash\nipsec trafficstatus\n```\n\n### Windows 错误 809\n\n> 错误 809：无法建立计算机与 VPN 服务器之间的网络连接，因为远程服务器未响应。这可能是因为未将计算机与远程服务器之间的某种网络设备(如防火墙、NAT、路由器等)配置为允许 VPN 连接。请与管理员或服务提供商联系以确定哪种设备可能产生此问题。\n\n**注：** 仅当你使用 IPsec/L2TP 模式连接到 VPN 时，才需要进行下面的注册表更改。对于 [IKEv2](ikev2-howto-zh.md) 和 [IPsec/XAuth](clients-xauth-zh.md) 模式，**不需要** 进行此更改。\n\n要解决此错误，在首次连接之前需要修改一次注册表，以解决 VPN 服务器 和/或 客户端与 NAT （比如家用路由器）的兼容问题。请下载并导入下面的 `.reg` 文件，或者打开[提升权限命令提示符](http://www.cnblogs.com/xxcanghai/p/4610054.html)并运行以下命令。**完成后必须重启计算机。**\n\n- 适用于 Windows Vista, 7, 8, 10 和 11 ([下载 .reg 文件](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Windows_Vista_7_8_10_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\PolicyAgent /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f\n  ```\n\n- 仅适用于 Windows XP ([下载 .reg 文件](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Windows_XP_ONLY_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\IPSec /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f\n  ```\n\n另外，某些个别的 Windows 系统配置禁用了 IPsec 加密，此时也会导致连接失败。要重新启用它，可以运行以下命令并重启。\n\n- 适用于 Windows XP, Vista, 7, 8, 10 和 11 ([下载 .reg 文件](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Allow_IPsec_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f\n  ```\n\n### Windows 错误 789 或 691\n\n> 错误 789：L2TP 连接尝试失败，因为安全层在初始化与远程计算机的协商时遇到一个处理错误。\n\n> 错误 691：由于指定的用户名和/或密码无效而拒绝连接。下列条件可能会导致此情况：用户名和/或密码键入错误...\n\n对于错误 789，点击[这里](https://documentation.meraki.com/MX/Client_VPN/Guided_Client_VPN_Troubleshooting/Unable_to_Connect_to_Client_VPN_from_Some_Devices)查看故障排除信息。对于错误 691，你可以尝试删除并重新创建 VPN 连接，按照本文档中的步骤操作。请确保输入了正确的 VPN 登录凭证。\n\n### Windows 错误 628 或 766\n\n> 错误 628：在连接完成前，连接被远程计算机终止。\n\n> 错误 766：找不到证书。使用通过 IPSec 的 L2TP 协议的连接要求安装一个机器证书。它也叫做计算机证书。\n\n要解决这些错误，请按以下步骤操作：\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. **Windows 11:** 选择 **网络和 Internet 设置**，然后在打开的页面中单击 **高级网络设置**。单击 **更多网络适配器选项**。   \n   **Windows 10:** 选择 **打开\"网络和 Internet\"设置**，然后在打开的页面中单击 **网络和共享中心**。单击左侧的 **更改适配器设置**。   \n   **Windows 8/7:** 选择 **打开网络和共享中心**。单击左侧的 **更改适配器设置**。\n1. 右键单击新的 VPN 连接，并选择 **属性**。\n1. 单击 **安全** 选项卡，从 **VPN 类型** 下拉菜单中选择 \"使用 IPsec 的第 2 层隧道协议 (L2TP/IPSec)\"。\n1. 单击 **允许使用这些协议**。选中 \"质询握手身份验证协议 (CHAP)\" 和 \"Microsoft CHAP 版本 2 (MS-CHAP v2)\" 复选框。\n1. 单击 **高级设置** 按钮。\n1. 单击 **使用预共享密钥作身份验证** 并在 **密钥** 字段中输入`你的 VPN IPsec PSK`。\n1. 单击 **确定** 关闭 **高级设置**。\n1. 单击 **确定** 保存 VPN 连接的详细信息。\n\n### Windows 10 正在连接\n\n如果你使用 Windows 10 并且 VPN 卡在 \"正在连接\" 状态超过几分钟，尝试以下步骤：\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. 选择 **打开\"网络和 Internet\"设置**，然后在打开的页面中单击左侧的 **VPN**。\n1. 选择新的 VPN 连接，然后单击 **连接**。如果出现提示，在登录窗口中输入 `你的 VPN 用户名` 和 `密码` ，并单击 **确定**。\n\n### Windows 10/11 升级\n\n在升级 Windows 10/11 版本之后（比如从 21H2 到 22H2），你可能需要重新按照 [Windows 错误 809](#windows-错误-809) 中的步骤修改注册表并重启。\n\n### Windows DNS 泄漏和 IPv6\n\nWindows 8, 10 和 11 默认使用 \"smart multi-homed name resolution\" （智能多宿主名称解析）。如果你的因特网适配器的 DNS 服务器在本地网段上，在使用 Windows 自带的 IPsec VPN 客户端时可能会导致 \"DNS 泄漏\"。要解决这个问题，你可以[禁用智能多宿主名称解析](https://www.neowin.net/news/guide-prevent-dns-leakage-while-using-a-vpn-on-windows-10-and-windows-8/)，或者配置你的因特网适配器以使用在你的本地网段之外的 DNS 服务器（比如 8.8.8.8 和 8.8.4.4）。在完成后重启计算机。\n\n另外，如果你的计算机启用了 IPv6，所有的 IPv6 流量（包括 DNS 请求）都将绕过 VPN。要在 Windows 上禁用 IPv6，请看[这里](https://support.microsoft.com/zh-cn/help/929852/guidance-for-configuring-ipv6-in-windows-for-advanced-users)。\n\n如果你需要支持 IPv6 的 VPN，请尝试 [IKEv2 模式](ikev2-howto-zh.md)（参见 [IPv6 支持](advanced-usage-zh.md#ipv6-支持)，需要具有公共 IPv6 地址的 VPN 服务器），或者尝试 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh.md) 或 [WireGuard](https://github.com/hwdsl2/wireguard-install/blob/master/README-zh.md)。\n\n### Android/Linux MTU/MSS 问题\n\n某些 Android 设备和 Linux 系统有 MTU/MSS 问题，表现为使用 IPsec/XAuth (\"Cisco IPsec\") 或者 IKEv2 模式可以连接到 VPN 但是无法打开网站。如果你遇到该问题，尝试在 VPN 服务器上运行以下命令。如果成功解决，你可以将这些命令添加到 `/etc/rc.local` 以使它们重启后继续有效。\n\n```\niptables -t mangle -A FORWARD -m policy --pol ipsec --dir in \\\n  -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \\\n  -j TCPMSS --set-mss 1360\niptables -t mangle -A FORWARD -m policy --pol ipsec --dir out \\\n  -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \\\n  -j TCPMSS --set-mss 1360\n\necho 1 > /proc/sys/net/ipv4/ip_no_pmtu_disc\n```\n\n**Docker 用户：** 要修复这个问题，不需要运行以上命令。你可以在[你的 env 文件](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#如何使用本镜像)中添加 `VPN_ANDROID_MTU_FIX=yes`，然后重新创建 Docker 容器。\n\n参考链接：[[1]](https://www.zeitgeist.se/2013/11/26/mtu-woes-in-ipsec-tunnels-how-to-fix/)。\n\n### macOS 通过 VPN 发送通信\n\nOS X (macOS) 用户：如果可以成功地使用 IPsec/L2TP 模式连接，但是你的公有 IP 没有显示为 `你的 VPN 服务器 IP`，请阅读上面的 [macOS](#os-x-macos) 部分并完成以下步骤。保存 VPN 配置然后重新连接。\n\n对于 macOS 13 (Ventura) 及以上：\n\n1. 单击 **选项** 选项卡，并启用 **通过VPN连接发送所有流量**。\n1. 单击 **TCP/IP** 选项卡，然后在 **配置IPv6** 下拉菜单选择 **仅本地链接**。\n\n对于 macOS 12 (Monterey) 及以下：\n\n1. 单击 **高级** 按钮，并选中 **通过VPN连接发送所有通信** 复选框。\n1. 单击 **TCP/IP** 选项卡，并在 **配置IPv6** 部分中选择 **仅本地链接**。\n\n如果在尝试上面步骤之后，你的计算机仍然不能通过 VPN 连接发送通信，检查一下服务顺序。进入系统偏好设置中的网络部分，单击左侧连接列表下方的齿轮按钮，选择 \"设定服务顺序\"。然后将 VPN 连接拖动到顶端。\n\n### iOS/Android 睡眠模式\n\n为了节约电池，iOS 设备 (iPhone/iPad) 在屏幕变黑（睡眠模式）之后会自动断开 Wi-Fi 连接。这会导致 IPsec VPN 断开。该行为是被[故意设计的](https://discussions.apple.com/thread/2333948)并且不能被配置。\n\n如果需要 VPN 在设备唤醒后自动重连，你可以使用 [IKEv2](ikev2-howto-zh.md) 模式连接（推荐）并启用 \"VPN On Demand\" 功能。或者你也可以另外尝试使用 [OpenVPN](https://github.com/hwdsl2/openvpn-install/blob/master/README-zh.md)，它支持[一些选项](https://openvpn.net/vpn-server-resources/faq-regarding-openvpn-connect-ios/)比如 \"Reconnect on Wakeup\" 和 \"Seamless Tunnel\"。\n\n<a name=\"debian-10-内核\"></a>\nAndroid 设备在进入睡眠模式后也会断开 Wi-Fi 连接。你可以尝试打开 \"始终开启 VPN\" 选项以保持连接。详情请看[这里](https://support.google.com/android/answer/9089766?hl=zh-Hans)。\n\n### Debian 内核\n\nDebian 用户：运行 `uname -r` 检查你的服务器的 Linux 内核版本。如果它包含 `cloud` 字样，并且 `/dev/ppp` 不存在，则该内核缺少 `ppp` 支持从而不能使用 IPsec/L2TP 模式。VPN 安装脚本会尝试检测此情形并显示警告。在这种情况下，你可以另外使用 [IKEv2](ikev2-howto-zh.md) 或者 [IPsec/XAuth](clients-xauth-zh.md) 模式连接到 VPN。\n\n要解决 IPsec/L2TP 模式的问题，你可以换用标准的 Linux 内核，通过安装比如 `linux-image-amd64` 软件包来实现。然后更新 GRUB 的内核默认值并重启服务器。\n\n## 授权协议\n\n注： 这个协议仅适用于本文档。\n\n版权所有 (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n受到 [Joshua Lund 的工作](https://github.com/StreisandEffect/streisand/blob/6aa6b6b2735dd829ca8c417d72eb2768a89b6639/playbooks/roles/l2tp-ipsec/templates/instructions.md.j2)的启发\n\n本程序为自由软件，在自由软件联盟发布的[ GNU 通用公共许可协议](https://www.gnu.org/licenses/gpl.html)的约束下，你可以对其进行再发布及修改。协议版本为第三版或（随你）更新的版本。\n\n我们希望发布的这款程序有用，但不保证，甚至不保证它有经济价值和适合特定用途。详情参见GNU通用公共许可协议。\n"
  },
  {
    "path": "docs/clients.md",
    "content": "[English](clients.md) | [中文](clients-zh.md)\n\n# Configure IPsec/L2TP VPN Clients\n\nAfter [setting up your own VPN server](https://github.com/hwdsl2/setup-ipsec-vpn), follow these steps to configure your devices. IPsec/L2TP is natively supported by Android, iOS, OS X, and Windows. There is no additional software to install. Setup should only take a few minutes. In case you are unable to connect, first check to make sure the VPN credentials were entered correctly.\n\n---\n* Platforms\n  * [Windows](#windows)\n  * [OS X (macOS)](#os-x-macos)\n  * [Android](#android)\n  * [iOS (iPhone/iPad)](#ios)\n  * [Chrome OS (Chromebook)](#chrome-os)\n  * [Linux](#linux)\n* [IKEv1 troubleshooting](#ikev1-troubleshooting)\n\n## Windows\n\n> You may also connect using [IKEv2](ikev2-howto.md) mode (recommended).\n\n### Windows 11\n\n1. Right-click on the wireless/network icon in your system tray.\n1. Select **Network and Internet settings**, then on the page that opens, click **VPN**.\n1. Click the **Add VPN** button.\n1. Select **Windows (built-in)** in the **VPN provider** drop-down menu.\n1. Enter anything you like in the **Connection name** field.\n1. Enter `Your VPN Server IP` in the **Server name or address** field.\n1. Select **L2TP/IPsec with pre-shared key** in the **VPN type** drop-down menu.\n1. Enter `Your VPN IPsec PSK` in the **Pre-shared key** field.\n1. Enter `Your VPN Username` in the **User name** field.\n1. Enter `Your VPN Password` in the **Password** field.\n1. Check the **Remember my sign-in info** checkbox.\n1. Click **Save** to save the VPN connection details.\n\n**Note:** This [one-time registry change](#windows-error-809) is required if the VPN server and/or client is behind NAT (e.g. home router).\n\nTo connect to the VPN: Click the **Connect** button, or click on the wireless/network icon in your system tray, click **VPN**, then select the new VPN entry and click **Connect**. If prompted, enter `Your VPN Username` and `Password`, then click **OK**. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n### Windows 10 and 8\n\n1. Right-click on the wireless/network icon in your system tray.\n1. Select **Open Network & Internet settings**, then on the page that opens, click **Network and Sharing Center**.\n1. Click **Set up a new connection or network**.\n1. Select **Connect to a workplace** and click **Next**.\n1. Click **Use my Internet connection (VPN)**.\n1. Enter `Your VPN Server IP` in the **Internet address** field.\n1. Enter anything you like in the **Destination name** field, and then click **Create**.\n1. Return to **Network and Sharing Center**. On the left, click **Change adapter settings**.\n1. Right-click on the new VPN entry and choose **Properties**.\n1. Click the **Security** tab. Select \"Layer 2 Tunneling Protocol with IPsec (L2TP/IPSec)\" for the **Type of VPN**.\n1. Click **Allow these protocols**. Check the \"Challenge Handshake Authentication Protocol (CHAP)\" and \"Microsoft CHAP Version 2 (MS-CHAP v2)\" checkboxes.\n1. Click the **Advanced settings** button.\n1. Select **Use preshared key for authentication** and enter `Your VPN IPsec PSK` for the **Key**.\n1. Click **OK** to close the **Advanced settings**.\n1. Click **OK** to save the VPN connection details.\n\n**Note:** This [one-time registry change](#windows-error-809) is required if the VPN server and/or client is behind NAT (e.g. home router).\n\nTo connect to the VPN: Click on the wireless/network icon in your system tray, select the new VPN entry, and click **Connect**. If prompted, enter `Your VPN Username` and `Password`, then click **OK**. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\nAlternatively, instead of following the steps above, you may create the VPN connection using these Windows PowerShell commands. Replace `Your VPN Server IP` and `Your VPN IPsec PSK` with your own values, enclosed in single quotes:\n\n```console\n# Disable persistent command history\nSet-PSReadlineOption –HistorySaveStyle SaveNothing\n# Create VPN connection\nAdd-VpnConnection -Name 'My IPsec VPN' -ServerAddress 'Your VPN Server IP' `\n  -L2tpPsk 'Your VPN IPsec PSK' -TunnelType L2tp -EncryptionLevel Required `\n  -AuthenticationMethod Chap,MSChapv2 -Force -RememberCredential -PassThru\n# Ignore the data encryption warning (data is encrypted in the IPsec tunnel)\n```\n\n### Windows 7, Vista and XP\n\n1. Click on the Start Menu and go to the Control Panel.\n1. Go to the **Network and Internet** section.\n1. Click **Network and Sharing Center**.\n1. Click **Set up a new connection or network**.\n1. Select **Connect to a workplace** and click **Next**.\n1. Click **Use my Internet connection (VPN)**.\n1. Enter `Your VPN Server IP` in the **Internet address** field.\n1. Enter anything you like in the **Destination name** field.\n1. Check the **Don't connect now; just set it up so I can connect later** checkbox.\n1. Click **Next**.\n1. Enter `Your VPN Username` in the **User name** field.\n1. Enter `Your VPN Password` in the **Password** field.\n1. Check the **Remember this password** checkbox.\n1. Click **Create**, and then **Close**.\n1. Return to **Network and Sharing Center**. On the left, click **Change adapter settings**.\n1. Right-click on the new VPN entry and choose **Properties**.\n1. Click the **Options** tab and uncheck **Include Windows logon domain**.\n1. Click the **Security** tab. Select \"Layer 2 Tunneling Protocol with IPsec (L2TP/IPSec)\" for the **Type of VPN**.\n1. Click **Allow these protocols**. Check the \"Challenge Handshake Authentication Protocol (CHAP)\" and \"Microsoft CHAP Version 2 (MS-CHAP v2)\" checkboxes.\n1. Click the **Advanced settings** button.\n1. Select **Use preshared key for authentication** and enter `Your VPN IPsec PSK` for the **Key**.\n1. Click **OK** to close the **Advanced settings**.\n1. Click **OK** to save the VPN connection details.\n\n**Note:** This [one-time registry change](#windows-error-809) is required if the VPN server and/or client is behind NAT (e.g. home router).\n\nTo connect to the VPN: Click on the wireless/network icon in your system tray, select the new VPN entry, and click **Connect**. If prompted, enter `Your VPN Username` and `Password`, then click **OK**. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n## OS X (macOS)\n\n### macOS 13 (Ventura) and newer\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/XAuth](clients-xauth.md) mode.\n\n1. Open **System Settings** and go to the **Network** section.\n1. Click **VPN** on the right hand side of the window.\n1. Click the **Add VPN Configuration** drop-down menu and select **L2TP over IPSec**.\n1. In the window that opens, enter anything you like for the **Display name**.\n1. Leave **Configuration** as **Default**.\n1. Enter `Your VPN Server IP` for the **Server address**.\n1. Enter `Your VPN Username` for the **Account name**.\n1. Select **Password** from the **User authentication** drop-down menu.\n1. Enter `Your VPN Password` for the **Password**.\n1. Select **Shared secret** from the **Machine authentication** drop-down menu.\n1. Enter `Your VPN IPsec PSK` for the **Shared secret**.\n1. Leave the **Group name** field blank. \n1. **(Important before you click create)** Click the **Options** tab, and make sure the **Send all traffic over VPN connection** toggle is ON.\n1. **(Important before you click create)** Click the **TCP/IP** tab, and select **Link-local only** from the **Configure IPv6** drop-down menu.\n1. Click **Create** to save the VPN configuration.\n1. To show VPN status in your menu bar and for shortcut access, go to the **Control Center** section of **System Settings**. Scroll to the bottom and select `Show in Menu Bar` from the **VPN** drop-down menu.\n\nTo connect to the VPN: Use the menu bar icon, or go to the **VPN** section of **System Settings** and toggle the switch for your VPN configuration. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n### macOS 12 (Monterey) and older\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/XAuth](clients-xauth.md) mode.\n\n1. Open System Preferences and go to the Network section.\n1. Click the **+** button in the lower-left corner of the window.\n1. Select **VPN** from the **Interface** drop-down menu.\n1. Select **L2TP over IPSec** from the **VPN Type** drop-down menu.\n1. Enter anything you like for the **Service Name**.\n1. Click **Create**.\n1. Enter `Your VPN Server IP` for the **Server Address**.\n1. Enter `Your VPN Username` for the **Account Name**.\n1. Click the **Authentication Settings** button.\n1. In the **User Authentication** section, select the **Password** radio button and enter `Your VPN Password`.\n1. In the **Machine Authentication** section, select the **Shared Secret** radio button and enter `Your VPN IPsec PSK`.\n1. Click **OK**.\n1. Check the **Show VPN status in menu bar** checkbox.\n1. **(Important)** Click the **Advanced** button and make sure the **Send all traffic over VPN connection** checkbox is checked.\n1. **(Important)** Click the **TCP/IP** tab, and make sure **Link-local only** is selected in the **Configure IPv6** section.\n1. Click **OK** to close the Advanced settings, and then click **Apply** to save the VPN connection information.\n\nTo connect to the VPN: Use the menu bar icon, or go to the Network section of System Preferences, select the VPN and choose **Connect**. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n## Android\n\n**Important:** Android users should instead connect using [IKEv2 mode](ikev2-howto.md) (recommended), which is more secure. Android 12+ only supports IKEv2 mode. The native VPN client in Android uses the less secure `modp1024` (DH group 2) for the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nIf you still want to connect using IPsec/L2TP mode, you must first edit `/etc/ipsec.conf` on the VPN server. Find the line `ike=...` and append `,aes256-sha2;modp1024,aes128-sha1;modp1024` at the end. Save the file and run `service ipsec restart`.\n\nDocker users: Add `VPN_ENABLE_MODP1024=yes` to [your env file](https://github.com/hwdsl2/docker-ipsec-vpn-server#how-to-use-this-image), then re-create the Docker container.\n\nAfter that, follow the steps below on your Android device:\n\n1. Launch the **Settings** application.\n1. Tap \"Network & internet\". Or, if using Android 7 or earlier, tap **More...** in the **Wireless & networks** section.\n1. Tap **VPN**.\n1. Tap **Add VPN Profile** or the **+** icon at top-right of screen.\n1. Enter anything you like in the **Name** field.\n1. Select **L2TP/IPSec PSK** in the **Type** drop-down menu.\n1. Enter `Your VPN Server IP` in the **Server address** field.\n1. Leave the **L2TP secret** field blank.\n1. Leave the **IPSec identifier** field blank.\n1. Enter `Your VPN IPsec PSK` in the **IPSec pre-shared key** field.\n1. Tap **Save**.\n1. Tap the new VPN connection.\n1. Enter `Your VPN Username` in the **Username** field.\n1. Enter `Your VPN Password` in the **Password** field.\n1. Check the **Save account information** checkbox.\n1. Tap **Connect**.\n\nOnce connected, you will see a VPN icon in the notification bar. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n## iOS\n\n> You may also connect using [IKEv2](ikev2-howto.md) (recommended) or [IPsec/XAuth](clients-xauth.md) mode.\n\n1. Go to Settings -> General -> VPN.\n1. Tap **Add VPN Configuration...**.\n1. Tap **Type**. Select **L2TP** and go back.\n1. Tap **Description** and enter anything you like.\n1. Tap **Server** and enter `Your VPN Server IP`.\n1. Tap **Account** and enter `Your VPN Username`.\n1. Tap **Password** and enter `Your VPN Password`.\n1. Tap **Secret** and enter `Your VPN IPsec PSK`.\n1. Make sure the **Send All Traffic** switch is ON.\n1. Tap **Done**.\n1. Slide the **VPN** switch ON.\n\nOnce connected, you will see a VPN icon in the status bar. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n## Chrome OS\n\n> You may also connect using [IKEv2](ikev2-howto.md) mode (recommended).\n\n1. Go to Settings -> Network.\n1. Click **Add connection**, then click **Add built-in VPN**.\n1. Enter anything you like for the **Service name**.\n1. Select **L2TP/IPsec** in the **Provider type** drop-down menu.\n1. Enter `Your VPN Server IP` for the **Server hostname**.\n1. Select **Pre-shared key** in the **Authentication type** drop-down menu.\n1. Enter `Your VPN Username` for the **Username**.\n1. Enter `Your VPN Password` for the **Password**.\n1. Enter `Your VPN IPsec PSK` for the **Pre-shared key**.\n1. Leave other fields blank.\n1. Enable **Save identity and password**.\n1. Click **Connect**.\n\nOnce connected, you will see a VPN icon overlay on the network status icon. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev1-troubleshooting).\n\n## Linux\n\n> You may also connect using [IKEv2](ikev2-howto.md) mode (recommended).\n\n### Ubuntu Linux\n\nUbuntu 18.04 (and newer) users can install the [network-manager-l2tp-gnome](https://packages.ubuntu.com/search?keywords=network-manager-l2tp-gnome) package using `apt`, then configure the IPsec/L2TP VPN client using the GUI.\n\n1. Go to Settings -> Network -> VPN. Click the **+** button.\n1. Select **Layer 2 Tunneling Protocol (L2TP)**.\n1. Enter anything you like in the **Name** field.\n1. Enter `Your VPN Server IP` for the **Gateway**.\n1. Enter `Your VPN Username` for the **User name**.\n1. Right-click the **?** in the **Password** field, select **Store the password only for this user**.\n1. Enter `Your VPN Password` for the **Password**.\n1. Leave the **NT Domain** field blank.\n1. Click the **IPsec Settings...** button.\n1. Check the **Enable IPsec tunnel to L2TP host** checkbox.\n1. Leave the **Gateway ID** field blank.\n1. Enter `Your VPN IPsec PSK` for the **Pre-shared key**.\n1. Expand the **Advanced** section.\n1. Enter `aes128-sha1-modp2048` for the **Phase1 Algorithms**.\n1. Enter `aes128-sha1` for the **Phase2 Algorithms**.\n1. Click **OK**, then click **Add** to save the VPN connection information.\n1. Turn the **VPN** switch ON.\n\nIf you get an error when trying to connect, try [this fix](https://github.com/nm-l2tp/NetworkManager-l2tp/blob/2926ea0239fe970ff08cb8a7863f8cb519ece032/README.md#unable-to-establish-l2tp-connection-without-udp-source-port-1701).\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\n### Fedora and CentOS\n\nFedora 28 (and newer) and CentOS 8/7 users can connect using [IPsec/XAuth](clients-xauth.md) mode.\n\n### Other Linux\n\nFirst check [here](https://github.com/nm-l2tp/NetworkManager-l2tp/wiki/Prebuilt-Packages) to see if the `network-manager-l2tp` and `network-manager-l2tp-gnome` packages are available for your Linux distribution. If yes, install them (select strongSwan) and follow the instructions above. Alternatively, you may configure Linux VPN clients using the command line.\n\n### Configure Linux VPN clients using the command line\n\nAdvanced users can configure Linux VPN clients using the command line. Alternatively, you may connect using [IKEv2](ikev2-howto.md) mode (recommended), or [configure using the GUI](#linux). Instructions below are inspired by [the work of Peter Sanford](https://gist.github.com/psanford/42c550a1a6ad3cb70b13e4aaa94ddb1c). Commands must be run as `root` on your VPN client.\n\nTo set up the VPN client, first install the following packages:\n\n```bash\n# Ubuntu and Debian\napt-get update\napt-get install strongswan xl2tpd net-tools\n\n# Fedora\nyum install strongswan xl2tpd net-tools\n\n# CentOS\nyum install epel-release\nyum --enablerepo=epel install strongswan xl2tpd net-tools\n```\n\nCreate VPN variables (replace with actual values):\n\n```bash\nVPN_SERVER_IP='your_vpn_server_ip'\nVPN_IPSEC_PSK='your_ipsec_pre_shared_key'\nVPN_USER='your_vpn_username'\nVPN_PASSWORD='your_vpn_password'\n```\n\nConfigure strongSwan:\n\n```bash\ncat > /etc/ipsec.conf <<EOF\n# ipsec.conf - strongSwan IPsec configuration file\n\nconn myvpn\n  auto=add\n  keyexchange=ikev1\n  authby=secret\n  type=transport\n  left=%defaultroute\n  leftprotoport=17/1701\n  rightprotoport=17/1701\n  right=$VPN_SERVER_IP\n  ike=aes128-sha1-modp2048\n  esp=aes128-sha1\nEOF\n\ncat > /etc/ipsec.secrets <<EOF\n: PSK \"$VPN_IPSEC_PSK\"\nEOF\n\nchmod 600 /etc/ipsec.secrets\n\n# For CentOS and Fedora ONLY\nmv /etc/strongswan/ipsec.conf /etc/strongswan/ipsec.conf.old 2>/dev/null\nmv /etc/strongswan/ipsec.secrets /etc/strongswan/ipsec.secrets.old 2>/dev/null\nln -s /etc/ipsec.conf /etc/strongswan/ipsec.conf\nln -s /etc/ipsec.secrets /etc/strongswan/ipsec.secrets\n```\n\nConfigure xl2tpd:\n\n```bash\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[lac myvpn]\nlns = $VPN_SERVER_IP\nppp debug = yes\npppoptfile = /etc/ppp/options.l2tpd.client\nlength bit = yes\nEOF\n\ncat > /etc/ppp/options.l2tpd.client <<EOF\nipcp-accept-local\nipcp-accept-remote\nrefuse-eap\nrequire-chap\nnoccp\nnoauth\nmtu 1280\nmru 1280\nnoipdefault\ndefaultroute\nusepeerdns\nconnect-delay 5000\nname \"$VPN_USER\"\npassword \"$VPN_PASSWORD\"\nEOF\n\nchmod 600 /etc/ppp/options.l2tpd.client\n```\n\nThe VPN client setup is now complete. Follow the steps below to connect.\n\n**Note:** You must repeat all steps below every time you try to connect to the VPN.\n\nCreate xl2tpd control file:\n\n```bash\nmkdir -p /var/run/xl2tpd\ntouch /var/run/xl2tpd/l2tp-control\n```\n\nRestart services:\n\n```bash\nservice strongswan restart\n\n# For Ubuntu, if strongswan service not found\nipsec restart\n\nservice xl2tpd restart\n```\n\nStart the IPsec connection:\n\n```bash\n# Ubuntu and Debian\nipsec up myvpn\n\n# CentOS and Fedora\nstrongswan up myvpn\n```\n\nStart the L2TP connection:\n\n```bash\necho \"c myvpn\" > /var/run/xl2tpd/l2tp-control\n```\n\nRun `ifconfig` and check the output. You should now see a new interface `ppp0`.\n\nCheck your existing default route:\n\n```bash\nip route\n```\n\nFind this line in the output: `default via X.X.X.X ...`. Write down this gateway IP for use in the two commands below.\n\nExclude your VPN server's public IP from the new default route (replace with actual value):\n\n```bash\nroute add YOUR_VPN_SERVER_PUBLIC_IP gw X.X.X.X\n```\n\nIf your VPN client is a remote server, you must also exclude your Local PC's public IP from the new default route, to prevent your SSH session from being disconnected (replace with [actual value](https://www.google.com/search?q=my+ip)):\n\n```bash\nroute add YOUR_LOCAL_PC_PUBLIC_IP gw X.X.X.X\n```\n\nAdd a new default route to start routing traffic via the VPN server：\n\n```bash\nroute add default dev ppp0\n```\n\nThe VPN connection is now complete. Verify that your traffic is being routed properly:\n\n```bash\nwget -qO- http://ipv4.icanhazip.com; echo\n```\n\nThe above command should return `Your VPN Server IP`.\n\nTo stop routing traffic via the VPN server:\n\n```bash\nroute del default dev ppp0\n```\n\nTo disconnect:\n\n```bash\n# Ubuntu and Debian\necho \"d myvpn\" > /var/run/xl2tpd/l2tp-control\nipsec down myvpn\n\n# CentOS and Fedora\necho \"d myvpn\" > /var/run/xl2tpd/l2tp-control\nstrongswan down myvpn\n```\n\n## IKEv1 troubleshooting\n\n*Read this in other languages: [English](clients.md#ikev1-troubleshooting), [中文](clients-zh.md#ikev1-故障排除).*\n\n**See also:** [IKEv2 troubleshooting](ikev2-howto.md#ikev2-troubleshooting) and [Advanced usage](advanced-usage.md).\n\n* [Check logs and VPN status](#check-logs-and-vpn-status)\n* [Windows error 809](#windows-error-809)\n* [Windows error 789 or 691](#windows-error-789-or-691)\n* [Windows error 628 or 766](#windows-error-628-or-766)\n* [Windows 10 connecting](#windows-10-connecting)\n* [Windows 10/11 upgrades](#windows-1011-upgrades)\n* [Windows DNS leaks and IPv6](#windows-dns-leaks-and-ipv6)\n* [Android/Linux MTU/MSS issues](#androidlinux-mtumss-issues)\n* [macOS send traffic over VPN](#macos-send-traffic-over-vpn)\n* [iOS/Android sleep mode](#iosandroid-sleep-mode)\n* [Debian kernel](#debian-kernel)\n\n### Check logs and VPN status\n\nCommands below must be run as `root` (or using `sudo`).\n\nFirst, restart services on the VPN server:\n\n```bash\nservice ipsec restart\nservice xl2tpd restart\n```\n\n**Docker users:** Run `docker restart ipsec-vpn-server`.\n\nThen reboot your VPN client device, and retry the connection. If still unable to connect, try removing and recreating the VPN connection. Make sure that the VPN server address and VPN credentials are entered correctly.\n\nFor servers with an external firewall (e.g. [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)), open UDP ports 500 and 4500 for the VPN.\n\nCheck the Libreswan (IPsec) and xl2tpd logs for errors:\n\n```bash\n# Ubuntu & Debian\ngrep pluto /var/log/auth.log\ngrep xl2tpd /var/log/syslog\n\n# CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\ngrep pluto /var/log/secure\ngrep xl2tpd /var/log/messages\n\n# Alpine Linux\ngrep pluto /var/log/messages\ngrep xl2tpd /var/log/messages\n```\n\nCheck the status of the IPsec VPN server:\n\n```bash\nipsec status\n```\n\nShow currently established VPN connections:\n\n```bash\nipsec trafficstatus\n```\n\n### Windows error 809\n\n> Error 809: The network connection between your computer and the VPN server could not be established because the remote server is not responding. This could be because one of the network devices (e.g, firewalls, NAT, routers, etc) between your computer and the remote server is not configured to allow VPN connections. Please contact your Administrator or your service provider to determine which device may be causing the problem.\n\n**Note:** The registry change below is only required if you use IPsec/L2TP mode to connect to the VPN. It is NOT required for the [IKEv2](ikev2-howto.md) and [IPsec/XAuth](clients-xauth.md) modes.\n\nTo fix this error, a one-time registry change is required because the VPN server and/or client is behind NAT (e.g. home router). Download and import the `.reg` file below, or run the following from an [elevated command prompt](http://www.winhelponline.com/blog/open-elevated-command-prompt-windows/). **You must reboot your PC when finished.**\n\n- For Windows Vista, 7, 8, 10 and 11 ([download .reg file](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Windows_Vista_7_8_10_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\PolicyAgent /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f\n  ```\n\n- For Windows XP ONLY ([download .reg file](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Windows_XP_ONLY_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\IPSec /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f\n  ```\n\nAlthough uncommon, some Windows systems disable IPsec encryption, causing the connection to fail. To re-enable it, run the following command and reboot your PC.\n\n- For Windows XP, Vista, 7, 8, 10 and 11 ([download .reg file](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Fix_VPN_Error_809_Allow_IPsec_Reboot_Required.reg))\n\n  ```console\n  REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f\n  ```\n\n### Windows error 789 or 691\n\n> Error 789: The L2TP connection attempt failed because the security layer encountered a processing error during initial negotiations with the remote computer.\n\n> Error 691: The remote connection was denied because the user name and password combination you provided is not recognized, or the selected authentication protocol is not permitted on the remote access server.\n\nFor error 789, click [here](https://documentation.meraki.com/MX/Client_VPN/Guided_Client_VPN_Troubleshooting/Unable_to_Connect_to_Client_VPN_from_Some_Devices) for troubleshooting information. For error 691, you may try removing and recreating the VPN connection, by following the instructions in this document. Make sure that the VPN credentials are entered correctly.\n\n### Windows error 628 or 766\n\n> Error 628: The connection was terminated by the remote computer before it could be completed.\n\n> Error 766: A certificate could not be found. Connections that use the L2TP protocol over IPSec require the installation of a machine certificate, also known as a computer certificate.\n\nTo fix these errors, please follow these steps:\n\n1. Right-click on the wireless/network icon in your system tray.\n1. **Windows 11:** Select **Network and Internet settings**, then on the page that opens, click **Advanced network settings**. Click **More network adapter options**.   \n   **Windows 10:** Select **Open Network & Internet settings**, then on the page that opens, click **Network and Sharing Center**. On the left, click **Change adapter settings**.   \n   **Windows 8/7:** Select **Open Network and Sharing Center**. On the left, click **Change adapter settings**.\n1. Right-click on the new VPN connection, and choose **Properties**.\n1. Click the **Security** tab. Select \"Layer 2 Tunneling Protocol with IPsec (L2TP/IPSec)\" for **Type of VPN**.\n1. Click **Allow these protocols**. Check the \"Challenge Handshake Authentication Protocol (CHAP)\" and \"Microsoft CHAP Version 2 (MS-CHAP v2)\" checkboxes.\n1. Click the **Advanced settings** button.\n1. Select **Use preshared key for authentication** and enter `Your VPN IPsec PSK` for the **Key**.\n1. Click **OK** to close the **Advanced settings**.\n1. Click **OK** to save the VPN connection details.\n\n### Windows 10 connecting\n\nIf using Windows 10 and the VPN is stuck on \"connecting\" for more than a few minutes, try these steps:\n\n1. Right-click on the wireless/network icon in your system tray.\n1. Select **Open Network & Internet settings**, then on the page that opens, click **VPN** on the left.\n1. Select the new VPN entry, then click **Connect**. If prompted, enter `Your VPN Username` and `Password`, then click **OK**.\n\n### Windows 10/11 upgrades\n\nAfter upgrading Windows 10/11 version (e.g. from 21H2 to 22H2), you may need to re-apply the fix above for [Windows Error 809](#windows-error-809) and reboot.\n\n### Windows DNS leaks and IPv6\n\nWindows 8, 10 and 11 use \"smart multi-homed name resolution\" by default, which may cause \"DNS leaks\" when using the native IPsec VPN client if your DNS servers on the Internet adapter are from the local network segment. To fix, you may either [disable smart multi-homed name resolution](https://www.neowin.net/news/guide-prevent-dns-leakage-while-using-a-vpn-on-windows-10-and-windows-8/), or configure your Internet adapter to use DNS servers outside your local network (e.g. 8.8.8.8 and 8.8.4.4). When finished, reboot your PC.\n\nIn addition, if your computer has IPv6 enabled, all IPv6 traffic (including DNS queries) will bypass the VPN. Learn how to [disable IPv6](https://support.microsoft.com/en-us/help/929852/guidance-for-configuring-ipv6-in-windows-for-advanced-users) in Windows.\n\nIf you need IPv6 support through the VPN, try [IKEv2 mode](ikev2-howto.md) (see [IPv6 support](advanced-usage.md#ipv6-support), requires a VPN server with a public IPv6 address), or try [OpenVPN](https://github.com/hwdsl2/openvpn-install) or [WireGuard](https://github.com/hwdsl2/wireguard-install).\n\n### Android/Linux MTU/MSS issues\n\nSome Android devices and Linux systems have MTU/MSS issues, that they are able to connect to the VPN using IPsec/XAuth (\"Cisco IPsec\") or IKEv2 mode, but cannot open websites. If you encounter this problem, try running the following commands on the VPN server. If successful, you may add these commands to `/etc/rc.local` to persist after reboot.\n\n```\niptables -t mangle -A FORWARD -m policy --pol ipsec --dir in \\\n  -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \\\n  -j TCPMSS --set-mss 1360\niptables -t mangle -A FORWARD -m policy --pol ipsec --dir out \\\n  -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 \\\n  -j TCPMSS --set-mss 1360\n\necho 1 > /proc/sys/net/ipv4/ip_no_pmtu_disc\n```\n\n**Docker users:** Instead of running the commands above, you may apply this fix by adding `VPN_ANDROID_MTU_FIX=yes` to [your env file](https://github.com/hwdsl2/docker-ipsec-vpn-server#how-to-use-this-image), then re-create the Docker container.\n\nReference: [[1]](https://www.zeitgeist.se/2013/11/26/mtu-woes-in-ipsec-tunnels-how-to-fix/).\n\n### macOS send traffic over VPN\n\nOS X (macOS) users: If you can successfully connect using IPsec/L2TP mode, but your public IP does not show `Your VPN Server IP`, read the [macOS](#os-x-macos) section above and complete these steps. Save VPN configuration and re-connect.\n\nFor macOS 13 (Ventura) and newer:\n\n1. Click the **Options** tab, and make sure the **Send all traffic over VPN connection** toggle is ON.\n1. Click the **TCP/IP** tab, and select **Link-local only** from the **Configure IPv6** drop-down menu.\n\nFor macOS 12 (Monterey) and older:\n\n1. Click the **Advanced** button and make sure the **Send all traffic over VPN connection** checkbox is checked.\n1. Click the **TCP/IP** tab, and make sure **Link-local only** is selected in the **Configure IPv6** section.\n\nAfter trying the steps above, if your computer is still not sending traffic over the VPN, check the service order. From the main network preferences screen, select \"set service order\" in the cog drop down under the list of connections. Drag the VPN connection to the top.\n\n### iOS/Android sleep mode\n\nTo save battery, iOS devices (iPhone/iPad) will automatically disconnect Wi-Fi shortly after the screen turns off (sleep mode). As a result, the IPsec VPN disconnects. This behavior is [by design](https://discussions.apple.com/thread/2333948) and cannot be configured.\n\nIf you need the VPN to auto-reconnect when the device wakes up, you may connect using [IKEv2](ikev2-howto.md) mode (recommended) and enable the \"VPN On Demand\" feature. Alternatively, you may try [OpenVPN](https://github.com/hwdsl2/openvpn-install) instead, which [has support for options](https://openvpn.net/vpn-server-resources/faq-regarding-openvpn-connect-ios/) such as \"Reconnect on Wakeup\" and \"Seamless Tunnel\".\n\n<a name=\"debian-10-kernel\"></a>\nAndroid devices may also disconnect Wi-Fi after entering sleep mode. You may try enabling the \"Always-on VPN\" option to stay connected. Learn more [here](https://support.google.com/android/answer/9089766).\n\n### Debian kernel\n\nDebian users: Run `uname -r` to check your server's Linux kernel version. If it contains the word \"cloud\", and `/dev/ppp` is missing, then the kernel lacks `ppp` support and cannot use IPsec/L2TP mode. The VPN setup scripts try to detect this and show a warning. In this case, you may instead use [IKEv2](ikev2-howto.md) or [IPsec/XAuth](clients-xauth.md) mode to connect to the VPN.\n\nTo fix the issue with IPsec/L2TP mode, you may switch to the standard Linux kernel by installing e.g. the `linux-image-amd64` package. Then update the default kernel in GRUB and reboot your server.\n\n## License\n\nNote: This license applies to this document only.\n\nCopyright (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \nInspired by [the work of Joshua Lund](https://github.com/StreisandEffect/streisand/blob/6aa6b6b2735dd829ca8c417d72eb2768a89b6639/playbooks/roles/l2tp-ipsec/templates/instructions.md.j2)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the [GNU General Public License](https://www.gnu.org/licenses/gpl.html) as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n"
  },
  {
    "path": "docs/ikev2-howto-zh.md",
    "content": "[English](ikev2-howto.md) | [中文](ikev2-howto-zh.md)\n\n# IKEv2 VPN 配置和使用指南\n\n* [导言](#导言)\n* [配置 IKEv2 VPN 客户端](#配置-ikev2-vpn-客户端)\n* [IKEv2 故障排除](#ikev2-故障排除)\n* [管理 IKEv2 客户端](#管理-ikev2-客户端)\n* [更改 IKEv2 服务器地址](#更改-ikev2-服务器地址)\n* [更新 IKEv2 辅助脚本](#更新-ikev2-辅助脚本)\n* [使用辅助脚本配置 IKEv2](#使用辅助脚本配置-ikev2)\n* [手动配置 IKEv2](#手动配置-ikev2)\n* [移除 IKEv2](#移除-ikev2)\n\n## 导言\n\n现代操作系统支持 IKEv2 协议标准。因特网密钥交换（英语：Internet Key Exchange，简称 IKE 或 IKEv2）是一种网络协议，归属于 IPsec 协议族之下，用以创建安全关联 (Security Association, SA)。与 IKE 版本 1 相比较，IKEv2 的[功能改进](https://en.wikipedia.org/wiki/Internet_Key_Exchange#Improvements_with_IKEv2)包括比如通过 MOBIKE 实现 Standard Mobility 支持，以及更高的可靠性。\n\nLibreswan 支持通过使用 RSA 签名算法的 X.509 Machine Certificates 来对 IKEv2 客户端进行身份验证。该方法无需 IPsec PSK, 用户名或密码。它可以用于 Windows, macOS, iOS, Android, Chrome OS, Linux 和 RouterOS。\n\n默认情况下，运行 VPN 安装脚本时会自动配置 IKEv2。如果你想了解有关配置 IKEv2 的更多信息，请参见[使用辅助脚本配置 IKEv2](#使用辅助脚本配置-ikev2)。Docker 用户请看[配置并使用 IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#配置并使用-ikev2-vpn)。\n\n## 配置 IKEv2 VPN 客户端\n\n**注：** 如果要添加或者导出 IKEv2 客户端，运行 `sudo ikev2.sh`。使用 `-h` 显示使用信息。客户端配置文件可以在导入后安全删除。\n\n* [Windows 7, 8, 10 和 11](#windows-7-8-10-和-11)\n* [OS X (macOS)](#os-x-macos)\n* [iOS (iPhone/iPad)](#ios)\n* [Android](#android)\n* [Chrome OS (Chromebook)](#chrome-os)\n* [Linux](#linux)\n* [MikroTik RouterOS](#routeros)\n\n<details>\n<summary>\n了解如何更改 IKEv2 服务器地址。\n</summary>\n\n在某些情况下，你可能需要更改 IKEv2 服务器地址，例如切换为使用域名，或者在服务器的 IP 更改之后。要了解更多信息，参见[这一小节](#更改-ikev2-服务器地址)。\n</details>\n\n### Windows 7, 8, 10 和 11\n\n#### 自动导入配置\n\n[**屏幕录影：** 在 Windows 上自动导入 IKEv2 配置](https://ko-fi.com/post/IKEv2-Auto-Import-Configuration-on-Windows-8-10-a-K3K1DQCHW)\n\n**Windows 8, 10 和 11+** 用户可以自动导入 IKEv2 配置：\n\n1. 将生成的 `.p12` 文件安全地传送到你的计算机。\n1. 右键单击 [ikev2_config_import.cmd](https://github.com/hwdsl2/vpn-extras/releases/latest/download/ikev2_config_import.cmd) 并保存这个辅助脚本到与 `.p12` 文件 **相同的文件夹**。\n1. 右键单击保存的脚本，选择 **属性**。单击对话框下方的 **解除锁定**，然后单击 **确定**。\n1. 右键单击保存的脚本，选择 **以管理员身份运行** 并按提示操作。\n\n要连接到 VPN：单击系统托盘中的无线/网络图标，选择新的 VPN 连接，然后单击 **连接**。连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n**注：** 如果你重新安装了 VPN 服务器，你可能需要先删除现有的 IKEv2 客户端和 CA 证书，然后按照上述步骤导入新的 `.p12` 文件。这有助于确保 Windows 在连接到 VPN 时使用正确的客户端证书。有关详细信息，请参阅下面的 \"删除 IKEv2 VPN 连接\"。\n\n#### 手动导入配置\n\n[[支持者] **屏幕录影：** 在 Windows 上手动导入 IKEv2 配置](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)\n\n或者，**Windows 7, 8, 10 和 11+** 用户可以手动导入 IKEv2 配置：\n\n1. 将生成的 `.p12` 文件安全地传送到你的计算机，然后导入到证书存储。\n\n   要导入 `.p12` 文件，打开[提升权限命令提示符](http://www.cnblogs.com/xxcanghai/p/4610054.html)并运行以下命令：\n\n   ```console\n   # 导入 .p12 文件（换成你自己的值）\n   certutil -f -importpfx \"\\path\\to\\your\\file.p12\" NoExport\n   ```\n\n   **注：** 如果客户端配置文件没有密码，请按回车键继续，或者在手动导入 `.p12` 文件时保持密码字段空白。\n\n   或者，你也可以[手动导入 .p12 文件](https://wiki.strongswan.org/projects/strongswan/wiki/Win7Certs/9)。在导入证书后，确保将客户端证书放在 \"个人 -> 证书\" 目录中，并且将 CA 证书放在 \"受信任的根证书颁发机构 -> 证书\" 目录中。\n\n1. 在 Windows 计算机上添加一个新的 IKEv2 VPN 连接。\n\n   对于 **Windows 8, 10 和 11+**，推荐从命令提示符运行以下命令创建 VPN 连接，以达到更佳的安全性和性能。\n\n   ```console\n   # 创建 VPN 连接（将服务器地址换成你自己的值）\n   powershell -command ^\"Add-VpnConnection -ServerAddress '你的 VPN 服务器 IP（或者域名）' ^\n     -Name 'My IKEv2 VPN' -TunnelType IKEv2 -AuthenticationMethod MachineCertificate ^\n     -EncryptionLevel Required -PassThru^\"\n   # 设置 IPsec 参数\n   powershell -command ^\"Set-VpnConnectionIPsecConfiguration -ConnectionName 'My IKEv2 VPN' ^\n     -AuthenticationTransformConstants GCMAES128 -CipherTransformConstants GCMAES128 ^\n     -EncryptionMethod AES256 -IntegrityCheckMethod SHA256 -PfsGroup None ^\n     -DHGroup Group14 -PassThru -Force^\"\n   ```\n\n   **Windows 7** 不支持这些命令，你可以[手动创建 VPN 连接](https://wiki.strongswan.org/projects/strongswan/wiki/Win7Config/8)。\n\n   **注：** 你输入的服务器地址必须与 IKEv2 辅助脚本输出中的服务器地址 **完全一致**。例如，如果你在配置 IKEv2 时指定了服务器的域名，则必须在 **Internet地址** 字段中输入该域名。\n\n1. **此步骤为必须，如果你手动创建了 VPN 连接。**\n\n   为 IKEv2 启用更强的加密算法，通过修改一次注册表来实现。请下载并导入下面的 `.reg` 文件，或者打开提升权限命令提示符并运行以下命令。更多信息请看[这里](https://docs.strongswan.org/docs/5.9/interop/windowsClients.html)。\n\n   - 适用于 Windows 7, 8, 10 和 11 ([下载 .reg 文件](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Enable_Stronger_Ciphers_for_IKEv2_on_Windows.reg))\n\n     ```console\n     REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v NegotiateDH2048_AES256 /t REG_DWORD /d 0x1 /f\n     ```\n\n要连接到 VPN：单击系统托盘中的无线/网络图标，选择新的 VPN 连接，然后单击 **连接**。连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n<details>\n<summary>\n删除 IKEv2 VPN 连接。\n</summary>\n\n通过以下的步骤，可以删除添加的 VPN 连接，并将计算机恢复到导入 IKEv2 配置之前的状态（可选）。\n\n1. 在系统设置 -> 网络 -> VPN 中删除添加的 VPN 连接。Windows 7 用户可以在网络和共享中心 -> 更改适配器设置中删除 VPN 连接。\n\n1. （可选）删除 IKEv2 证书。\n\n   1. **Windows 8, 10 和 11:** 按 Win+R 然后输入 `certlm.msc`，或在开始菜单中搜索 `certlm.msc`。打开 *证书 - 本地计算机*。   \n      **Windows 7:** 按 Win+R 然后输入 `mmc`，或在开始菜单中搜索 `mmc`。打开 *管理控制台*。在 `文件 - 添加/删除管理单元` 的窗口中，选择添加 `证书` 并在弹出的窗口中选择 `计算机帐户 -> 本地计算机`。点击 `完成 -> 确定` 以保存设置。\n\n   1. 在 证书 -> 个人 -> 证书 中删除 IKEv2 客户端证书。该证书的名称与你指定的 IKEv2 客户端名称一致，默认为 `vpnclient`，该证书由 `IKEv2 VPN CA` 颁发。\n\n   1. 在 证书 -> 受信任的根证书颁发机构 -> 证书 中删除 IKEv2 VPN CA 证书。该证书是由 `IKEv2 VPN CA` 颁发的，颁发给 `IKEv2 VPN CA` 的证书。需要注意，删除这一步的证书时，证书 -> 个人 -> 证书 中应不存在其他由 `IKEv2 VPN CA` 颁发的证书。\n\n1. （可选，适用于手动创建了 VPN 连接的用户）还原注册表配置。注意，在编辑注册表前应备份。\n\n   1. 按 Win+R 或在开始菜单中搜索 `regedit` 打开 *注册表编辑器*。\n\n   1. 在 `HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\Rasman\\Parameters` 中删除名为 `NegotiateDH2048_AES256` 的项目，如果它存在。\n</details>\n\n### OS X (macOS)\n\n[[支持者] **屏幕录影：** 在 macOS 上导入 IKEv2 配置并连接](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)\n\n首先，将生成的 `.mobileconfig` 文件安全地传送到你的 Mac，然后双击并按提示操作，以导入为 macOS 配置描述文件。如果你的 Mac 运行 macOS Big Sur 或更新版本，打开系统偏好设置并转到描述文件部分以完成导入。对于 macOS Ventura 和更新版本，打开系统设置并搜索描述文件。在完成之后，检查并确保 \"IKEv2 VPN\" 显示在系统偏好设置 -> 描述文件中。\n\n要连接到 VPN：\n\n1. 打开系统偏好设置并转到网络部分。\n1. 选择与 `你的 VPN 服务器 IP`（或者域名）对应的 VPN 连接。\n1. 选中 **在菜单栏中显示 VPN 状态** 复选框。对于 macOS Ventura 和更新版本，你可以到系统设置 -> 控制中心 -> 仅菜单栏部分配置该选项。\n1. 单击 **连接**，或启用 VPN 连接。\n\n（可选功能）启用 **VPN On Demand（按需连接）** 以在你的 Mac 连接到 Wi-Fi 时自动启动 VPN 连接。要启用它，选中 VPN 连接的 **按需连接** 复选框，然后单击 **应用**。对于 macOS Ventura 和更新版本，首先单击 VPN 连接右边的 \"i\" 图标，然后配置该选项。\n\n你可以自定义按需连接规则，以排除某些 Wi-Fi 网络（例如你的家庭网络）。有关更多详细信息，请参阅 [:book: Book: 搭建自己的 VPN 服务器](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)中的 \"指南：为 macOS 和 iOS 自定义 IKEv2 VPN On Demand 规则\" 一章。\n\n<details>\n<summary>\n如果你手动配置 IKEv2 而不是使用辅助脚本，点这里查看步骤。\n</summary>\n\n首先，将生成的 `.p12` 文件安全地传送到你的 Mac，然后双击以导入到 **钥匙串访问** 中的 **登录** 钥匙串。下一步，双击导入的 `IKEv2 VPN CA` 证书，展开 **信任** 并从 **IP 安全 (IPsec)** 下拉菜单中选择 **始终信任**。单击左上角的红色 \"X\" 关闭窗口。根据提示使用触控 ID，或者输入密码并单击 \"更新设置\"。\n\n在完成之后，检查并确保新的客户端证书和 `IKEv2 VPN CA` 都显示在 **登录** 钥匙串 的 **证书** 类别中。\n\n1. 打开系统偏好设置并转到网络部分。\n1. 在窗口左下角单击 **+** 按钮。\n1. 从 **接口** 下拉菜单选择 **VPN**。\n1. 从 **VPN 类型** 下拉菜单选择 **IKEv2**。\n1. 在 **服务名称** 字段中输入任意内容。\n1. 单击 **创建**。\n1. 在 **服务器地址** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。   \n   **注：** 如果你在配置 IKEv2 时指定了服务器的域名（而不是 IP 地址），则必须在 **服务器地址** 和 **远程 ID** 字段中输入该域名。\n1. 在 **远程 ID** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。\n1. 在 **本地 ID** 字段中输入 `你的 VPN 客户端名称`。   \n   **注：** 该名称必须和你在 IKEv2 配置过程中指定的客户端名称一致。它与你的 `.p12` 文件名的第一部分相同。\n1. 单击 **认证设置** 按钮。\n1. 从 **认证设置** 下拉菜单中选择 **无**。\n1. 选择 **证书** 单选按钮，然后选择新的客户端证书。\n1. 单击 **好**。\n1. 选中 **在菜单栏中显示 VPN 状态** 复选框。\n1. 单击 **应用** 保存 VPN 连接信息。\n1. 单击 **连接**。\n</details>\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n**注：** macOS 14 (Sonoma) 存在一个小问题，可能会导致 IKEv2 VPN 每 24-48 分钟断开并重新连接一次。其他 macOS 版本不受影响。有关详细信息和解决方法，请参阅 [macOS Sonoma 客户端重新连接](#macos-sonoma-客户端重新连接)。\n\n<details>\n<summary>\n删除 IKEv2 VPN 连接。\n</summary>\n\n要删除 IKEv2 VPN 连接，打开系统偏好设置 -> 描述文件并移除你添加的 IKEv2 VPN 描述文件。\n</details>\n\n### iOS\n\n[[支持者] **屏幕录影：** 在 iOS (iPhone & iPad) 上导入 IKEv2 配置并连接](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)\n\n首先，将生成的 `.mobileconfig` 文件安全地传送到你的 iOS 设备，并且导入为 iOS 配置描述文件。要传送文件，你可以使用：\n\n1. AirDrop（隔空投送），或者\n1. 使用[文件共享](https://support.apple.com/zh-cn/HT210598)功能上传到设备（任何 App 目录），然后打开 iOS 设备上的 \"文件\" App，将上传的文件移动到 \"On My iPhone\" 目录下。然后单击它并到 \"设置\" App 中导入，或者\n1. 将文件放在一个你的安全的托管网站上，然后在 Mobile Safari 中下载并导入它们。\n\n在完成之后，检查并确保 \"IKEv2 VPN\" 显示在设置 -> 通用 -> VPN 与设备管理（或者描述文件）中。\n\n要连接到 VPN：\n\n1. 进入设置 -> VPN。选择与 `你的 VPN 服务器 IP`（或者域名）对应的 VPN 连接。\n1. 启用 **VPN** 连接。\n\n（可选功能）启用 **VPN On Demand（按需连接）** 以在你的 iOS 设备连接到 Wi-Fi 时自动启动 VPN 连接。要启用它，单击 VPN 连接右边的 \"i\" 图标，然后启用 **按需连接**。\n\n你可以自定义按需连接规则，以排除某些 Wi-Fi 网络（例如你的家庭网络）。有关更多详细信息，请参阅 [:book: Book: 搭建自己的 VPN 服务器](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)中的 \"指南：为 macOS 和 iOS 自定义 IKEv2 VPN On Demand 规则\" 一章。\n\n<details>\n<summary>\n自定义按需连接规则：在 Wi-Fi 和蜂窝网络上连接。\n</summary>\n\n默认的 VPN On Demand 配置仅在 Wi-Fi 网络上启动 VPN 连接，而不会在蜂窝网络上启动 VPN 连接。如果你希望 VPN 在 Wi-Fi 和蜂窝网络上都启动连接：\n\n1. 编辑 VPN 服务器上的 `/opt/src/ikev2.sh`。找到以下行：\n   ```\n     <dict>\n       <key>InterfaceTypeMatch</key>\n       <string>Cellular</string>\n       <key>Action</key>\n       <string>Disconnect</string>\n     </dict>\n   ```\n   并将 \"Disconnect\" 替换为 \"Connect\"：\n   ```\n     <dict>\n       <key>InterfaceTypeMatch</key>\n       <string>Cellular</string>\n       <key>Action</key>\n       <string>Connect</string>\n     </dict>\n   ```\n2. 保存文件，然后运行 `sudo ikev2.sh` 为你的 iOS 设备导出更新后的客户端配置文件。\n3. 从你的 iOS 设备中移除之前导入的 VPN 配置文件，然后导入步骤 2 中生成的新 `.mobileconfig` 文件。\n</details>\n<details>\n<summary>\n如果你手动配置 IKEv2 而不是使用辅助脚本，点这里查看步骤。\n</summary>\n\n首先，将生成的 `ca.cer` 和 `.p12` 文件安全地传送到你的 iOS 设备，并且逐个导入为 iOS 配置描述文件。要传送文件，你可以使用：\n\n1. AirDrop（隔空投送），或者\n1. 使用[文件共享](https://support.apple.com/zh-cn/HT210598)功能上传到设备（任何 App 目录），然后打开 iOS 设备上的 \"文件\" App，将上传的文件移动到 \"On My iPhone\" 目录下。然后逐个单击它们并到 \"设置\" App 中导入，或者\n1. 将文件放在一个你的安全的托管网站上，然后在 Mobile Safari 中下载并导入它们。\n\n在完成之后，检查并确保新的客户端证书和 `IKEv2 VPN CA` 都显示在设置 -> 通用 -> VPN 与设备管理（或者描述文件）中。\n\n1. 进入设置 -> 通用 -> VPN 与设备管理 -> VPN。\n1. 单击 **添加VPN配置...**。\n1. 单击 **类型** 。选择 **IKEv2** 并返回。\n1. 在 **描述** 字段中输入任意内容。\n1. 在 **服务器** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。   \n   **注：** 如果你在配置 IKEv2 时指定了服务器的域名（而不是 IP 地址），则必须在 **服务器** 和 **远程 ID** 字段中输入该域名。\n1. 在 **远程 ID** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。\n1. 在 **本地 ID** 字段中输入 `你的 VPN 客户端名称`。   \n   **注：** 该名称必须和你在 IKEv2 配置过程中指定的客户端名称一致。它与你的 `.p12` 文件名的第一部分相同。\n1. 单击 **用户鉴定** 。选择 **无** 并返回。\n1. 启用 **使用证书** 选项。\n1. 单击 **证书** 。选择新的客户端证书并返回。\n1. 单击右上角的 **完成**。\n1. 启用 **VPN** 连接。\n</details>\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n<details>\n<summary>\n删除 IKEv2 VPN 连接。\n</summary>\n\n要删除 IKEv2 VPN 连接，打开设置 -> 通用 -> VPN 与设备管理（或者描述文件）并移除你添加的 IKEv2 VPN 描述文件。\n</details>\n\n### Android\n\n#### 使用 strongSwan VPN 客户端\n\n[[支持者] **屏幕录影：** 使用 Android strongSwan VPN 客户端连接](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)\n\nAndroid 用户可以使用 strongSwan VPN 客户端连接（推荐）。\n\n1. 将生成的 `.sswan` 文件安全地传送到你的 Android 设备。\n1. 从 [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android)，[**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) 或 [**strongSwan 下载网站**](https://download.strongswan.org/Android/)下载并安装 strongSwan VPN 客户端。\n1. 启动 strongSwan VPN 客户端。\n1. 单击右上角的 \"更多选项\" 菜单，然后单击 **导入VPN配置**。\n1. 选择你从服务器传送过来的 `.sswan` 文件。   \n   **注：** 要查找 `.sswan` 文件，单击左上角的抽拉式菜单，然后浏览到你保存文件的目录。\n1. 在 \"导入VPN配置\" 屏幕上，单击 **从VPN配置导入证书**，并按提示操作。\n1. 在 \"选择证书\" 屏幕上，选择新的客户端证书并单击 **选择**。\n1. 单击 **导入**。\n1. 单击新的 VPN 配置文件以开始连接。\n\n（可选功能）你可以选择启用 Android 上的 \"始终开启的 VPN\" 功能。启动 **设置** App，进入 网络和互联网 -> 高级 -> VPN，单击 \"strongSwan VPN 客户端\" 右边的设置图标，然后启用 **始终开启的 VPN** 以及 **屏蔽未使用 VPN 的所有连接** 选项。\n\n<details>\n<summary>\n如果你的设备运行 Android 6.0 或更早版本，点这里查看额外的步骤。\n</summary>\n\n如果你的设备运行 Android 6.0 (Marshmallow) 或更早版本，要使用 strongSwan VPN 客户端连接，你必须更改 VPN 服务器上的以下设置：编辑服务器上的 `/etc/ipsec.d/ikev2.conf`。在 `conn ikev2-cp` 小节的末尾添加 `authby=rsa-sha1`，开头必须空两格。保存文件并运行 `service ipsec restart`。\n</details>\n<details>\n<summary>\n如果你手动配置 IKEv2 而不是使用辅助脚本，点这里查看步骤。\n</summary>\n\n**Android 10 和更新版本:**\n\n1. 将生成的 `.p12` 文件安全地传送到你的 Android 设备。\n1. 从 [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android)，[**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) 或 [**strongSwan 下载网站**](https://download.strongswan.org/Android/)下载并安装 strongSwan VPN 客户端。\n1. 启动 **设置** App。\n1. 进入 安全 -> 高级 -> 加密与凭据。\n1. 单击 **安装证书**。\n1. 单击 **VPN 和应用用户证书**。\n1. 选择你从服务器传送过来的 `.p12` 文件，并按提示操作。   \n   **注：** 要查找 `.p12` 文件，单击左上角的抽拉式菜单，然后浏览到你保存文件的目录。\n1. 启动 strongSwan VPN 客户端，然后单击 **添加VPN配置**。\n1. 在 **服务器地址** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。   \n   **注：** 如果你在配置 IKEv2 时指定了服务器的域名（而不是 IP 地址），则必须在 **服务器地址** 字段中输入该域名。\n1. 在 **VPN 类型** 下拉菜单选择 **IKEv2 证书**。\n1. 单击 **选择用户证书**，选择新的客户端证书并单击 **选择**。\n1. **（重要）** 单击 **显示高级设置**。向下滚动，找到并启用 **Use RSA/PSS signatures** 选项。\n1. 保存新的 VPN 连接，然后单击它以开始连接。\n\n**Android 4 to 9:**\n\n1. 将生成的 `.p12` 文件安全地传送到你的 Android 设备。\n1. 从 [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android)，[**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) 或 [**strongSwan 下载网站**](https://download.strongswan.org/Android/)下载并安装 strongSwan VPN 客户端。\n1. 启动 strongSwan VPN 客户端，然后单击 **添加VPN配置**。\n1. 在 **服务器地址** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。   \n   **注：** 如果你在配置 IKEv2 时指定了服务器的域名（而不是 IP 地址），则必须在 **服务器地址** 字段中输入该域名。\n1. 在 **VPN 类型** 下拉菜单选择 **IKEv2 证书**。\n1. 单击 **选择用户证书**，然后单击 **安装证书**。\n1. 选择你从服务器传送过来的 `.p12` 文件，并按提示操作。   \n   **注：** 要查找 `.p12` 文件，单击左上角的抽拉式菜单，然后浏览到你保存文件的目录。\n1. **（重要）** 单击 **显示高级设置**。向下滚动，找到并启用 **Use RSA/PSS signatures** 选项。\n1. 保存新的 VPN 连接，然后单击它以开始连接。\n</details>\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n#### 使用系统自带的 IKEv2 客户端\n\n[[支持者] **屏幕录影：** 使用 Android 11+ 系统自带的 VPN 客户端连接](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-X8X5FVFZC)\n\nAndroid 11+ 用户也可以使用系统自带的 IKEv2 客户端连接。\n\n1. 将生成的 `.p12` 文件安全地传送到你的 Android 设备。\n1. 启动 **设置** App。\n1. 进入 安全 -> 高级 -> 加密与凭据。\n1. 单击 **安装证书**。\n1. 单击 **VPN 和应用用户证书**。\n1. 选择你从服务器传送过来的 `.p12` 文件。   \n   **注：** 要查找 `.p12` 文件，单击左上角的抽拉式菜单，然后浏览到你保存文件的目录。\n1. 为证书输入名称，然后单击 **确定**。\n1. 进入 设置 -> 网络和互联网 -> VPN，然后单击 \"+\" 按钮。\n1. 为 VPN 配置文件输入名称。\n1. 在 **类型** 下拉菜单选择 **IKEv2/IPSec RSA**。\n1. 在 **服务器地址** 字段中输入 `你的 VPN 服务器 IP` （或者域名）。   \n   **注：** 它必须与 IKEv2 辅助脚本输出中的服务器地址 **完全一致**。\n1. 在 **IPSec 标识符** 字段中输入任意内容。   \n   **注：** 该字段不应该为必填项。它是 Android 的一个 bug。\n1. 在 **IPSec 用户证书** 下拉菜单选择你导入的证书。\n1. 在 **IPSec CA 证书** 下拉菜单选择你导入的证书。\n1. 在 **IPSec 服务器证书** 下拉菜单选择 **(来自服务器)**。\n1. 单击 **保存**。然后单击新的 VPN 连接并单击 **连接**。\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n### Chrome OS\n\n首先，在 VPN 服务器上导出 CA 证书到 `ca.cer`：\n\n```bash\nsudo certutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -a -o ca.cer\n```\n\n将生成的 `.p12` 文件和 `ca.cer` 文件安全地传送到你的 Chrome OS 设备。\n\n安装用户证书和 CA 证书：\n\n1. 在 Google Chrome 中打开新标签页。\n1. 在地址栏中输入 **chrome://settings/certificates**\n1. **（重要）** 单击 **导入并绑定** 而不是 **导入**。\n1. 在对话框中选择你从服务器传送过来的 `.p12` 文件并选择 **打开**。\n1. 如果证书没有密码，单击 **确定**。否则输入该证书的密码。\n1. 单击上面的 **授权机构** 选项卡，然后单击 **导入**。\n1. 在对话框中左下角的下拉菜单选择 **所有文件**。\n1. 选择你从服务器传送过来的 `ca.cer` 文件并选择 **打开**。\n1. 保持默认选项并单击 **确定**。\n\n添加 VPN 连接：\n\n1. 进入设置 -> 网络。\n1. 单击 **添加连接**，然后单击 **添加内置 VPN**。\n1. 在 **服务名称** 字段中输入任意内容。\n1. 在 **提供商类型** 下拉菜单选择 **IPsec (IKEv2)**。\n1. 在 **服务器主机名** 字段中输入 `你的 VPN 服务器 IP`（或者域名）。\n1. 在 **身份验证类型** 下拉菜单选择 **用户证书**。\n1. 在 **服务器 CA 证书** 下拉菜单选择 **IKEv2 VPN CA [IKEv2 VPN CA]**。\n1. 在 **用户证书** 下拉菜单选择 **IKEv2 VPN CA [客户端名称]**。\n1. 保持其他字段空白。\n1. 启用 **保存身份信息和密码**。\n1. 单击 **连接**。\n\n连接成功后，网络状态图标上会出现 VPN 指示。你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n（可选功能）你可以选择启用 Chrome OS 上的 \"始终开启的 VPN\" 功能。要管理该设置，进入设置 -> 网络，然后单击 **VPN**。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n### Linux\n\n在配置 Linux 客户端之前，你必须更改 VPN 服务器上的以下设置：编辑服务器上的 `/etc/ipsec.d/ikev2.conf`。在 `conn ikev2-cp` 小节的末尾添加 `authby=rsa-sha1`，开头必须空两格。保存文件并运行 `service ipsec restart`。\n\n要配置你的 Linux 计算机以作为客户端连接到 IKEv2，首先安装 NetworkManager 的 strongSwan 插件：\n\n```bash\n# Ubuntu and Debian\nsudo apt-get update\nsudo apt-get install network-manager-strongswan\n\n# Arch Linux\nsudo pacman -Syu  # 升级所有软件包\nsudo pacman -S networkmanager-strongswan\n\n# Fedora\nsudo yum install NetworkManager-strongswan-gnome\n\n# CentOS\nsudo yum install epel-release\nsudo yum --enablerepo=epel install NetworkManager-strongswan-gnome\n```\n\n下一步，将生成的 `.p12` 文件安全地从 VPN 服务器传送到你的 Linux 计算机。然后提取 CA 证书，客户端证书和私钥。将下面示例中的 `vpnclient.p12` 换成你的 `.p12` 文件名。\n\n```bash\n# 示例：提取 CA 证书，客户端证书和私钥。在完成后可以删除 .p12 文件。\n# 注：你可能需要输入 import password，它可以在 IKEv2 辅助脚本的输出中找到。\n#    如果在脚本的输出中没有 import password，请按回车键继续。\n# 注：如果使用 OpenSSL 3.x (运行 \"openssl version\" 进行检查)，\n#    请将 \"-legacy\" 附加到下面的 3 个命令。\nopenssl pkcs12 -in vpnclient.p12 -cacerts -nokeys -out ca.cer\nopenssl pkcs12 -in vpnclient.p12 -clcerts -nokeys -out client.cer\nopenssl pkcs12 -in vpnclient.p12 -nocerts -nodes  -out client.key\nrm vpnclient.p12\n\n# （重要）保护证书和私钥文件\n# 注：这一步是可选的，但强烈推荐。\nsudo chown root:root ca.cer client.cer client.key\nsudo chmod 600 ca.cer client.cer client.key\n```\n\n然后你可以创建并启用 VPN 连接：\n\n1. 进入 Settings -> Network -> VPN。单击 **+** 按钮。\n1. 选择 **IPsec/IKEv2 (strongswan)**。\n1. 在 **Name** 字段中输入任意内容。\n1. 在 **Gateway (Server)** 部分的 **Address** 字段中输入 `你的 VPN 服务器 IP`（或者域名）。\n1. 为 **Certificate** 字段选择 `ca.cer` 文件。\n1. 在 **Client** 部分的 **Authentication** 下拉菜单选择 **Certificate(/private key)**。\n1. 在 **Certificate** 下拉菜单（如果存在）选择 **Certificate/private key**。\n1. 为 **Certificate (file)** 字段选择 `client.cer` 文件。\n1. 为 **Private key** 字段选择 `client.key` 文件。\n1. 在 **Options** 部分，选中 **Request an inner IP address** 复选框。\n1. 在 **Cipher proposals (Algorithms)** 部分，选中 **Enable custom proposals** 复选框。\n1. 保持 **IKE** 字段空白。\n1. 在 **ESP** 字段中输入 `aes128gcm16`.\n1. 单击 **Add** 保存 VPN 连接信息。\n1. 启用 **VPN** 连接。\n\n另外，你也可以使用命令行连接。示例步骤请参见 [#1399](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1399)、[#1007](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1007) 和 [#1789](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1789)。如果你遇到错误 `Could not find source connection`，编辑 `/etc/netplan/01-netcfg.yaml` 并将 `renderer: networkd` 替换为 `renderer: NetworkManager`，然后运行 `sudo netplan apply`。如果使用 `nmcli` 连接到 VPN，运行 `sudo nmcli c up VPN`。要断开连接：`sudo nmcli c down VPN`。\n\n连接成功后，你可以到[这里](https://www.ipchicken.com)检测你的 IP 地址，应该显示为`你的 VPN 服务器 IP`。\n\n如果在连接过程中遇到错误，请参见[故障排除](#ikev2-故障排除)。\n\n### RouterOS\n\n**注：** 这些步骤由 [@Unix-User](https://github.com/Unix-User) 提供。建议通过 SSH 连接运行终端命令，例如通过 Putty。\n\n1. 将生成的 `.p12` 文件安全地传送到你的计算机。\n\n   <details>\n   <summary>\n   单击查看屏幕录影。\n   </summary>\n\n   ![routeros get certificate](images/routeros-get-cert.gif)\n   </details>\n\n2. 在 WinBox 中，转到 System > certificates > import. 将 `.p12` 证书文件导入两次（是的，导入同一个文件两次）。检查你的 certificates panel。你应该看到 2 个文件，其中标注 KT 的是密钥。\n\n   <details>\n   <summary>\n   单击查看屏幕录影。\n   </summary>\n\n   ![routeros import certificate](images/routeros-import-cert.gif)\n   </details>\n\n   或者，你也可以使用终端命令 (empty passphrase):\n\n   ```bash\n   [admin@MikroTik] > /certificate/import file-name=mikrotik.p12\n   passphrase:\n\n     certificates-imported: 2\n     private-keys-imported: 0\n            files-imported: 1\n       decryption-failures: 0\n     keys-with-no-certificate: 0\n\n   [admin@MikroTik] > /certificate/import file-name=mikrotik.p12\n   passphrase:\n\n        certificates-imported: 0\n        private-keys-imported: 1\n               files-imported: 1\n          decryption-failures: 0\n     keys-with-no-certificate: 0\n\n   ```\n\n3. 在 terminal 中运行以下命令。将以下内容替换为你自己的值。\n`YOUR_VPN_SERVER_IP_OR_DNS_NAME` 是你的 VPN 服务器 IP 或域名。\n`IMPORTED_CERTIFICATE` 是上面第 2 步中的证书名称，例如 `vpnclient.p12_0`\n（标记为 KT 的行 - Priv. Key Trusted - 如果未标记为 KT，请再次导入证书）。\n`THESE_ADDRESSES_GO_THROUGH_VPN` 是你想要通过 VPN 浏览因特网的本地网络地址。\n假设 RouterOS 后面的本地网络是 `192.168.0.0/24`，你可以使用 `192.168.0.0/24`\n来指定整个网络，或者使用 `192.168.0.10` 来指定仅用于一个设备，依此类推。\n\n   ```bash\n   /ip firewall address-list add address=THESE_ADDRESSES_GO_THROUGH_VPN list=local\n   /ip ipsec mode-config add name=ike2-rw responder=no src-address-list=local\n   /ip ipsec policy group add name=ike2-rw\n   /ip ipsec profile add name=ike2-rw\n   /ip ipsec peer add address=YOUR_VPN_SERVER_IP_OR_DNS_NAME exchange-mode=ike2 \\\n       name=ike2-rw-client profile=ike2-rw\n   /ip ipsec proposal add name=ike2-rw pfs-group=none\n   /ip ipsec identity add auth-method=digital-signature certificate=IMPORTED_CERTIFICATE \\\n       generate-policy=port-strict mode-config=ike2-rw \\\n       peer=ike2-rw-client policy-template-group=ike2-rw\n   /ip ipsec policy add group=ike2-rw proposal=ike2-rw template=yes\n   ```\n4. 更多信息请参见 [#1112](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1112#issuecomment-1059628623)。\n\n> 已在以下系统测试   \n> mar/02/2022 12:52:57 by RouterOS 6.48   \n> RouterBOARD 941-2nD\n\n## IKEv2 故障排除\n\n*其他语言版本: [English](ikev2-howto.md#ikev2-troubleshooting), [中文](ikev2-howto-zh.md#ikev2-故障排除)。*\n\n**另见：** [检查日志及 VPN 状态](clients-zh.md#检查日志及-vpn-状态)，[IKEv1 故障排除](clients-zh.md#ikev1-故障排除)和[高级用法](advanced-usage-zh.md)。\n\n* [无法连接到 VPN 服务器](#无法连接到-vpn-服务器)\n* [Ubuntu 20.04 无法导入客户端配置](#ubuntu-2004-无法导入客户端配置)\n* [macOS Sonoma 客户端重新连接](#macos-sonoma-客户端重新连接)\n* [无法连接多个 IKEv2 客户端](#无法连接多个-ikev2-客户端)\n* [IKE 身份验证凭证不可接受](#ike-身份验证凭证不可接受)\n* [参数错误 policy match error](#参数错误-policy-match-error)\n* [参数错误 parameter is incorrect](#参数错误-parameter-is-incorrect)\n* [连接 IKEv2 后不能打开网站](#连接-ikev2-后不能打开网站)\n* [Windows 10 正在连接](#windows-10-正在连接)\n* [其它已知问题](#其它已知问题)\n\n### 无法连接到 VPN 服务器\n\n首先，请确保你的 VPN 客户端设备上指定的 VPN 服务器地址与 IKEv2 辅助脚本输出中的服务器地址**完全一致**。例如，如果在配置 IKEv2 时未指定域名，则不可以使用域名进行连接。要更改 IKEv2 服务器地址，参见[这一小节](#更改-ikev2-服务器地址)。\n\n对于有外部防火墙的服务器（比如 [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)），请为 VPN 打开 UDP 端口 500 和 4500。阿里云用户请参见 [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433)。\n\n[检查日志及 VPN 状态](clients-zh.md#检查日志及-vpn-状态)是否有错误。如果你遇到 retransmission 相关错误并且无法连接，说明 VPN 客户端和服务器之间的网络可能有问题。如果你从中国大陆进行连接，请考虑改用 IPsec VPN 以外的其他解决方案。\n\n### Ubuntu 20.04 无法导入客户端配置\n\n如果你在 2024-04-10 之前安装了 IPsec VPN，并且你的 VPN 服务器运行的是 Ubuntu Linux 版本 20.04，那么你可能会遇到无法在 iOS 或 macOS 设备上导入新生成的客户端配置文件 (`.mobileconfig`) 的问题，例如提示密码不正确。这可能是由 Ubuntu 20.04 上 libnss3 相关软件包的更新引起的，需要对 IKEv2 脚本进行一些更改 ([25670f3](https://github.com/hwdsl2/setup-ipsec-vpn/commit/25670f3))。\n\n要解决此问题，请首先按照[这些步骤](#更新-ikev2-辅助脚本)将服务器上的 IKEv2 脚本更新到最新版本。然后运行 `sudo ikev2.sh` 并选择 \"export\" 以重新创建客户端配置文件。\n\n### macOS Sonoma 客户端重新连接\n\nmacOS 14 (Sonoma) 存在[一个小问题](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1486)，可能会导致 IKEv2 VPN 每 24-48 分钟断开并重新连接一次。其他 macOS 版本不受影响。首先[检查你的 macOS 版本](https://support.apple.com/zh-cn/HT201260)。要解决此问题，请按以下步骤操作。\n\n**注：** 如果你在 2023 年 12 月 10 日之后安装了 IPsec VPN，则无需执行任何操作，因为已经包含以下修复。\n\n1. 编辑 VPN 服务器上的 `/etc/ipsec.d/ikev2.conf`。找到这一行：\n   ```\n     ike=aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n   ```\n   并将它替换为以下内容：\n   ```\n     ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n   ```\n   **注：** Docker 用户需要首先[在容器中运行 Bash shell](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage-zh.md#在容器中运行-bash-shell)。\n1. 保存文件并运行 `service ipsec restart`。Docker 用户：在下面的第 4 步之后退出 (`exit`) 容器并运行 `docker restart ipsec-vpn-server`。\n1. 编辑 VPN 服务器上的 `/opt/src/ikev2.sh`。找到以下部分并将其替换为这些新值：\n   ```\n     <key>ChildSecurityAssociationParameters</key>\n     <dict>\n       <key>DiffieHellmanGroup</key>\n       <integer>19</integer>\n       <key>EncryptionAlgorithm</key>\n       <string>AES-256-GCM</string>\n       <key>LifeTimeInMinutes</key>\n       <integer>1410</integer>\n     </dict>\n   ```\n   ```\n     <key>IKESecurityAssociationParameters</key>\n     <dict>\n       <key>DiffieHellmanGroup</key>\n       <integer>19</integer>\n       <key>EncryptionAlgorithm</key>\n       <string>AES-256-GCM</string>\n       <key>IntegrityAlgorithm</key>\n       <string>SHA2-256</string>\n       <key>LifeTimeInMinutes</key>\n       <integer>1410</integer>\n     </dict>\n   ```\n1. 运行 `sudo ikev2.sh` 为你的每个 macOS 设备导出（或添加）更新后的客户端配置文件。\n1. 从你的 macOS 设备中移除之前导入的 IKEv2 配置文件（如果有），然后导入更新后的 `.mobileconfig` 文件。请参阅[配置 IKEv2 VPN 客户端](#配置-ikev2-vpn-客户端)。Docker 用户请看[配置并使用 IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#配置并使用-ikev2-vpn)。\n\n### 无法连接多个 IKEv2 客户端\n\n如果要同时连接在同一个 NAT（比如家用路由器）后面的多个 IKEv2 客户端，你需要为每个客户端生成唯一的证书。否则，你可能会遇到稍后连接的客户端影响现有客户端的 VPN 连接，从而导致无法访问 Internet 的问题。\n\n要为其它的 IKEv2 客户端生成证书，运行辅助脚本并添加 `--addclient` 选项。要自定义客户端选项，可以在不添加参数的情况下运行脚本。\n\n```bash\nsudo ikev2.sh --addclient [client name]\n```\n\n### IKE 身份验证凭证不可接受\n\n如果遇到此错误，请确保你的 VPN 客户端设备上指定的 VPN 服务器地址与 IKEv2 辅助脚本输出中的服务器地址**完全一致**。例如，如果在配置 IKEv2 时未指定域名，则不可以使用域名进行连接。要更改 IKEv2 服务器地址，参见[这一小节](#更改-ikev2-服务器地址)。\n\n### 参数错误 policy match error\n\n要解决此错误，你需要为 IKEv2 启用更强的加密算法，通过修改一次注册表来实现。请下载并导入下面的 `.reg` 文件，或者打开提升权限命令提示符并运行以下命令。\n\n- 适用于 Windows 7, 8, 10 和 11 ([下载 .reg 文件](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Enable_Stronger_Ciphers_for_IKEv2_on_Windows.reg))\n\n```console\nREG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v NegotiateDH2048_AES256 /t REG_DWORD /d 0x1 /f\n```\n\n### 参数错误 parameter is incorrect\n\n如果你在尝试使用 IKEv2 模式连接时遇到 \"错误 87：参数错误 The parameter is incorrect\"，请尝试[这个 Issue](https://github.com/trailofbits/algo/issues/1051) 中的解决方案，更具体地说，第 2 步 \"reset device manager adapters\"。\n\n### 连接 IKEv2 后不能打开网站\n\n如果你的 VPN 客户端设备在成功连接到 IKEv2 后无法打开网站，请尝试以下解决方案：\n\n1. 某些云服务提供商，比如 [Google Cloud](https://cloud.google.com)，[默认设置较低的 MTU](https://cloud.google.com/network-connectivity/docs/vpn/concepts/mtu-considerations)。这可能会导致 IKEv2 VPN 客户端的网络问题。要解决此问题，尝试在 VPN 服务器上将 MTU 设置为 1500：\n\n   ```bash\n   # 将 ens4 替换为你的服务器上的网络接口名称\n   sudo ifconfig ens4 mtu 1500\n   ```\n\n   此设置 **不会** 在重启后保持。要永久更改 MTU 大小，请参阅网络上的相关文章。\n\n1. 如果你的 Android 或 Linux VPN 客户端可以连接到 IKEv2 但是无法打开网站，请尝试 [Android/Linux MTU/MSS 问题](clients-zh.md#androidlinux-mtumss-问题)中的解决方案。\n\n1. Windows VPN 客户端在连接后可能不使用 IKEv2 指定的 DNS 服务器，如果该客户端的因特网适配器的 DNS 服务器在本地网段上。要解决此问题，可以在网络连接属性 -> TCP/IPv4 中手动输入 DNS 服务器，例如 Google Public DNS (8.8.8.8, 8.8.4.4)。更多信息请参见 [Windows DNS 泄漏和 IPv6](clients-zh.md#windows-dns-泄漏和-ipv6)。\n\n### Windows 10 正在连接\n\n如果你使用 Windows 10 并且 VPN 卡在 \"正在连接\" 状态超过几分钟，尝试以下步骤：\n\n1. 右键单击系统托盘中的无线/网络图标。\n1. 选择 **打开\"网络和 Internet\"设置**，然后在打开的页面中单击左侧的 **VPN**。\n1. 选择新的 VPN 连接，然后单击 **连接**。\n\n### 其它已知问题\n\nWindows 自带的 VPN 客户端可能不支持 IKEv2 fragmentation（该功能[需要](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ikee/74df968a-7125-431d-9c98-4ea929e548dc) Windows 10 v1803 或更新版本）。在有些网络上，这可能会导致连接错误或其它连接问题。你可以尝试换用 [IPsec/L2TP](clients-zh.md) 或 [IPsec/XAuth](clients-xauth-zh.md) 模式。\n\n## 管理 IKEv2 客户端\n\n* [列出已有的客户端](#列出已有的客户端)\n* [添加客户端证书](#添加客户端证书)\n* [导出已有的客户端的配置](#导出已有的客户端的配置)\n* [删除客户端证书](#删除客户端证书)\n* [吊销客户端证书](#吊销客户端证书)\n\n### 列出已有的客户端\n\n要列出已有的 IKEv2 客户端的名称，运行辅助脚本并添加 `--listclients` 选项。使用参数 `-h` 显示使用信息。\n\n```bash\nsudo ikev2.sh --listclients\n```\n\n### 添加客户端证书\n\n要为其它的 IKEv2 客户端生成证书，运行辅助脚本并添加 `--addclient` 选项。要自定义客户端选项，可以在不添加参数的情况下运行脚本。\n\n```bash\nsudo ikev2.sh --addclient [client name]\n```\n\n另外，你也可以手动添加客户端证书。参见[这一小节](#手动配置-ikev2)的第 4 步。\n\n### 导出已有的客户端的配置\n\n在默认情况下，IKEv2 辅助脚本在运行后会导出客户端配置。如果之后你想要导出一个已有的客户端，可以运行：\n\n```bash\nsudo ikev2.sh --exportclient [client name]\n```\n\n### 删除客户端证书\n\n**重要：** 从 IPsec 数据库中删除一个客户端证书 **并不能** 阻止 VPN 客户端使用该证书连接！对于此用例，你 **必须** [吊销该客户端证书](#吊销客户端证书)，而不是删除证书。\n\n<details>\n<summary>\n首先，请阅读上面的重要说明。然后点这里查看详情。\n</summary>\n\n**警告：** 这将**永久删除**客户端证书和私钥。此操作**不可撤销**！\n\n如果要删除一个现有的客户端：\n\n```bash\nsudo ikev2.sh --deleteclient [client name]\n```\n\n<details>\n<summary>\n或者，你也可以手动删除一个客户端证书。\n</summary>\n\n1. 列出 IPsec 证书数据库中的证书：\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   示例输出：\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n1. 删除客户端证书和私钥。将下面的 \"Nickname\" 替换为你想要删除的客户端证书的昵称，例如 `vpnclient`。\n\n   ```bash\n   certutil -F -d sql:/etc/ipsec.d -n \"Nickname\"\n   certutil -D -d sql:/etc/ipsec.d -n \"Nickname\" 2>/dev/null\n   ```\n\n1. （可选步骤）删除之前为该客户端生成的配置文件（`.p12`, `.mobileconfig` 和 `.sswan` 文件），如果存在。\n</details>\n</details>\n\n### 吊销客户端证书\n\n在某些情况下，你可能需要吊销一个之前生成的 VPN 客户端证书。\n\n如果要吊销一个现有的客户端：\n\n```bash\nsudo ikev2.sh --revokeclient [client name]\n```\n\n<details>\n<summary>\n另外，你也可以手动吊销客户端证书。\n</summary>\n\n另外，你也可以手动吊销客户端证书。这可以通过 `crlutil` 实现。下面举例说明，这些命令必须用 `root` 账户运行。\n\n1. 检查证书数据库，并且找到想要吊销的客户端证书的昵称。\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient-to-revoke                                u,u,u\n   ```\n\n   在这个例子中，我们将要吊销昵称为 `vpnclient-to-revoke` 的客户端证书。它是由 `IKEv2 VPN CA` 签发的。\n\n1. 找到该客户端证书的序列号。\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d -n \"vpnclient-to-revoke\"\n   ```\n\n   ```\n   Certificate:\n       Data:\n           Version: 3 (0x2)\n           Serial Number:\n               00:cd:69:ff:74\n   ... ...\n   ```\n\n   根据上面的输出，我们知道该序列号为十六进制的 `CD69FF74`，也就是十进制的 `3446275956`。它将在以下步骤中使用。\n\n1. 创建一个新的证书吊销列表 (CRL)。该步骤对于每个 CA 只需运行一次。\n\n   ```bash\n   if ! crlutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" 2>/dev/null; then\n     crlutil -G -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -c /dev/null\n   fi\n   ```\n\n   ```\n   CRL Info:\n   :\n       Version: 2 (0x1)\n       Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption\n       Issuer: \"O=IKEv2 VPN,CN=IKEv2 VPN CA\"\n       This Update: Sat Jun 06 22:00:00 2020\n       CRL Extensions:\n   ```\n\n1. 将你想要吊销的客户端证书添加到 CRL。在这里我们指定该证书的（十进制）序列号，以及吊销时间（UTC时间，格式：GeneralizedTime (YYYYMMDDhhmmssZ)）。\n\n   ```bash\n   crlutil -M -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" <<EOF\n   addcert 3446275956 20200606220100Z\n   EOF\n   ```\n\n   ```\n   CRL Info:\n   :\n       Version: 2 (0x1)\n       Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption\n       Issuer: \"O=IKEv2 VPN,CN=IKEv2 VPN CA\"\n       This Update: Sat Jun 06 22:02:00 2020\n       Entry 1 (0x1):\n           Serial Number:\n               00:cd:69:ff:74\n           Revocation Date: Sat Jun 06 22:01:00 2020\n       CRL Extensions:\n   ```\n\n   **注：** 如果需要从 CRL 删除一个证书，可以将上面的 `addcert 3446275956 20200606220100Z` 替换为 `rmcert 3446275956`。关于 `crlutil` 的其它用法参见[这里](https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_crlutil/index.html)。\n\n1. 最后，让 Libreswan 重新读取已更新的 CRL。\n\n   ```bash\n   ipsec crls\n   ```\n</details>\n\n## 更改 IKEv2 服务器地址\n\n在某些情况下，你可能需要在配置之后更改 IKEv2 服务器地址。例如切换为使用域名，或者在服务器的 IP 更改之后。请注意，你在 VPN 客户端指定的服务器地址必须与 IKEv2 辅助脚本输出中的服务器地址 **完全一致**，否则客户端可能无法连接。\n\n要更改服务器地址，运行[辅助脚本](../extras/ikev2changeaddr.sh)并按提示操作。\n\n```bash\nwget https://get.vpnsetup.net/ikev2addr -O ikev2addr.sh\nsudo bash ikev2addr.sh\n```\n\n**重要：** 运行此脚本后，你必须手动更新任何现有 IKEv2 客户端设备上的服务器地址以及 Remote ID（如果适用）。对于 iOS 客户端，你需要运行 `sudo ikev2.sh` 以导出更新后的客户端配置文件并导入 iOS 设备。\n\n## 更新 IKEv2 辅助脚本\n\nIKEv2 辅助脚本会不时更新，以进行错误修复和改进（[更新日志](https://github.com/hwdsl2/setup-ipsec-vpn/commits/master/extras/ikev2setup.sh)）。 当有新版本可用时，你可以更新服务器上的 IKEv2 辅助脚本。这是可选的。请注意，这些命令将覆盖任何现有的 `ikev2.sh`。\n\n```bash\nwget https://get.vpnsetup.net/ikev2 -O /opt/src/ikev2.sh\nchmod +x /opt/src/ikev2.sh && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n```\n\n## 使用辅助脚本配置 IKEv2\n\n**注：** 默认情况下，运行 VPN 安装脚本时会自动配置 IKEv2。你可以跳过此部分并转到[配置 IKEv2 VPN 客户端](#配置-ikev2-vpn-客户端)。\n\n**重要：** 在继续之前，你应该已经成功地[搭建自己的 VPN 服务器](../README-zh.md)。Docker 用户请看[配置并使用 IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#配置并使用-ikev2-vpn)。\n\n使用这个[辅助脚本](../extras/ikev2setup.sh)来自动地在 VPN 服务器上配置 IKEv2：\n\n```bash\n# 使用默认选项配置 IKEv2\nsudo ikev2.sh --auto\n# 或者你也可以自定义 IKEv2 选项\nsudo ikev2.sh\n```\n\n**注：** 如果已配置 IKEv2，但是你想要自定义 IKEv2 选项，首先[移除 IKEv2](#移除-ikev2)，然后运行 `sudo ikev2.sh` 重新配置。\n\n在完成之后，请转到[配置 IKEv2 VPN 客户端](#配置-ikev2-vpn-客户端)。高级用户可以启用[仅限 IKEv2 模式](advanced-usage-zh.md#仅限-ikev2-的-vpn)。这是可选的。\n\n<details>\n<summary>\n错误：\"sudo: ikev2.sh: command not found\".\n</summary>\n\n如果你使用了较早版本的 VPN 安装脚本，这是正常的。首先下载 IKEv2 辅助脚本：\n\n```bash\nwget https://get.vpnsetup.net/ikev2 -O /opt/src/ikev2.sh\nchmod +x /opt/src/ikev2.sh && ln -s /opt/src/ikev2.sh /usr/bin\n```\n\n然后按照上面的说明运行脚本。\n</details>\n<details>\n<summary>\n你可以指定一个域名，客户端名称和/或另外的 DNS 服务器。这是可选的。\n</summary>\n\n在使用自动模式安装 IKEv2 时，高级用户可以指定一个域名作为 IKEv2 服务器地址。这是可选的。该域名必须是一个全称域名(FQDN)。示例如下：\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' ikev2.sh --auto\n```\n\n类似地，你可以指定第一个 IKEv2 客户端的名称。如果未指定，则使用默认值 `vpnclient`。\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' ikev2.sh --auto\n```\n\n在 VPN 已连接时，IKEv2 客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。你可以为 IKEv2 指定另外的 DNS 服务器。示例如下：\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 ikev2.sh --auto\n```\n\n默认情况下，导入 IKEv2 客户端配置时不需要密码。你可以选择使用随机密码保护客户端配置文件。\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes ikev2.sh --auto\n```\n</details>\n<details>\n<summary>\n查看 IKEv2 脚本的使用信息。\n</summary>\n\n```\nUsage: bash ikev2.sh [options]\n\nOptions:\n  --auto                        run IKEv2 setup in auto mode using default options (for initial setup only)\n  --addclient [client name]     add a new client using default options\n  --exportclient [client name]  export configuration for an existing client\n  --listclients                 list the names of existing clients\n  --revokeclient [client name]  revoke an existing client\n  --deleteclient [client name]  delete an existing client\n  --removeikev2                 remove IKEv2 and delete all certificates and keys from the IPsec database\n  -y, --yes                     assume \"yes\" as answer to prompts when revoking/deleting a client or removing IKEv2\n  -h, --help                    show this help message and exit\n\nTo customize IKEv2 or client options, run this script without arguments.\n```\n</details>\n\n## 手动配置 IKEv2\n\n除了使用[辅助脚本](#使用辅助脚本配置-ikev2)之外，高级用户也可以手动在 VPN 服务器上配置 IKEv2。在继续之前，推荐[升级 Libreswan](../README-zh.md#升级libreswan) 到最新版本。\n\n下面举例说明如何手动在 Libreswan 上配置 IKEv2。以下命令必须用 `root` 账户运行。\n\n<details>\n<summary>\n查看手动在 Libreswan 上配置 IKEv2 的示例步骤。\n</summary>\n\n1. 获取 VPN 服务器的公共 IP 地址，将它保存到变量并检查。\n\n   ```bash\n   PUBLIC_IP=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n   [ -z \"$PUBLIC_IP\" ] && PUBLIC_IP=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n   printf '%s\\n' \"$PUBLIC_IP\"\n   ```\n\n   检查并确保以上命令的输出与服务器的公共 IP 一致。该变量将在以下步骤中使用。\n\n   **注：** 另外，在这里你也可以指定 VPN 服务器的域名。例如： `PUBLIC_IP=myvpn.example.com`。\n\n1. 添加一个新的 IKEv2 连接：\n\n   ```bash\n   if ! grep -qs '^include /etc/ipsec\\.d/\\*\\.conf$' /etc/ipsec.conf; then\n     echo >> /etc/ipsec.conf\n     echo 'include /etc/ipsec.d/*.conf' >> /etc/ipsec.conf\n   fi\n   ```\n\n   **注：** 如果你在上面的第一步指定了服务器的域名（而不是 IP 地址），则必须将以下命令中的 `leftid=$PUBLIC_IP` 换成 `leftid=@$PUBLIC_IP`。\n\n   ```bash\n   cat > /etc/ipsec.d/ikev2.conf <<EOF\n\n   conn ikev2-cp\n     left=%defaultroute\n     leftcert=$PUBLIC_IP\n     leftid=$PUBLIC_IP\n     leftsendcert=always\n     leftsubnet=0.0.0.0/0\n     leftrsasigkey=%cert\n     right=%any\n     rightid=%fromcert\n     rightaddresspool=192.168.43.10-192.168.43.250\n     rightca=%same\n     rightrsasigkey=%cert\n     narrowing=yes\n     dpddelay=30\n     retransmit-timeout=300s\n     auto=add\n     ikev2=insist\n     rekey=no\n     pfs=no\n     ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n     phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2\n     ikelifetime=24h\n     salifetime=24h\n   EOF\n   ```\n\n   还需要在该文件中添加一些行。首先查看你的 Libreswan 版本，然后运行以下命令之一：\n\n   ```bash\n   ipsec --version\n   ```\n\n   如果是 Libreswan 3.23 或更新版本：\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns=\"8.8.8.8 8.8.4.4\"\n     encapsulation=yes\n     mobike=no\n   EOF\n   ```\n\n   **注：** MOBIKE IKEv2 协议扩展允许 VPN 客户端更改网络连接点，例如在移动数据和 Wi-Fi 之间切换，并使 VPN 保持连接。如果你的服务器（或者 Docker 主机）的操作系统 **不是** Ubuntu Linux，并且你想要启用 MOBIKE 支持，可以将上面命令中的 `mobike=no` 换成 `mobike=yes`。**不要** 在 Ubuntu 系统或者 Raspberry Pi 上启用该选项。\n\n   如果是 Libreswan 3.19-3.22：\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns1=8.8.8.8\n     modecfgdns2=8.8.4.4\n     encapsulation=yes\n   EOF\n   ```\n\n   如果是 Libreswan 3.18 或更早版本：\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns1=8.8.8.8\n     modecfgdns2=8.8.4.4\n     forceencaps=yes\n   EOF\n   ```\n\n1. 生成 Certificate Authority (CA) 和 VPN 服务器证书。\n\n   **注：** 使用 \"-v\" 参数指定证书的有效期（单位：月），例如 \"-v 120\"。\n\n   生成 CA 证书：\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -x -n \"IKEv2 VPN CA\" \\\n     -s \"O=IKEv2 VPN,CN=IKEv2 VPN CA\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \"CT,,\" -2\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n\n   Is this a CA certificate [y/N]?\n   y\n   Enter the path length constraint, enter to skip [<0 for unlimited path]: >\n   Is this a critical extension [y/N]?\n   N\n   ```\n\n   生成 VPN 服务器证书：\n\n   **注：** 如果你在上面的第一步指定了服务器的域名（而不是 IP 地址），则必须将以下命令中的 `--extSAN \"ip:$PUBLIC_IP,dns:$PUBLIC_IP\"` 换成 `--extSAN \"dns:$PUBLIC_IP\"`。\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -c \"IKEv2 VPN CA\" -n \"$PUBLIC_IP\" \\\n     -s \"O=IKEv2 VPN,CN=$PUBLIC_IP\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \",,\" \\\n     --keyUsage digitalSignature,keyEncipherment \\\n     --extKeyUsage serverAuth \\\n     --extSAN \"ip:$PUBLIC_IP,dns:$PUBLIC_IP\"\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n   ```\n\n1. 生成客户端证书，然后导出 `.p12` 文件，该文件包含客户端证书，私钥以及 CA 证书。\n\n   **注：** 你可以重复本步骤来为其它的客户端生成证书，但必须将所有的 `vpnclient` 换成比如 `vpnclient2`，等等。如果要同时连接在同一个 NAT（比如家用路由器）后面的多个 IKEv2 客户端，你需要为每个客户端生成唯一的证书。\n\n   生成客户端证书：\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -c \"IKEv2 VPN CA\" -n \"vpnclient\" \\\n     -s \"O=IKEv2 VPN,CN=vpnclient\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \",,\" \\\n     --keyUsage digitalSignature,keyEncipherment \\\n     --extKeyUsage serverAuth,clientAuth -8 \"vpnclient\"\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n   ```\n\n   导出 `.p12` 文件：\n\n   ```bash\n   pk12util -d sql:/etc/ipsec.d -n \"vpnclient\" -o vpnclient.p12\n   ```\n\n   ```\n   Enter password for PKCS12 file:\n   Re-enter password:\n   pk12util: PKCS12 EXPORT SUCCESSFUL\n   ```\n\n   指定一个安全的密码以保护导出的 `.p12` 文件（在导入到 iOS 或 macOS 设备时，该密码不能为空）。\n\n1. （适用于 iOS 客户端） 导出 CA 证书到 `ca.cer`：\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -a -o ca.cer\n   ```\n\n1. 证书数据库现在应该包含以下内容：\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n   **注：** 如需显示证书内容，可使用 `certutil -L -d sql:/etc/ipsec.d -n \"Nickname\"`。要吊销客户端证书，请转到[这一节](#吊销客户端证书)。关于 `certutil` 的其它用法参见[这里](https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_certutil/index.html)。\n\n1. **（重要）重启 IPsec 服务**：\n\n   ```bash\n   service ipsec restart\n   ```\n\n在继续之前，你**必须**重启 IPsec 服务。VPN 服务器上的 IKEv2 配置到此已完成。下一步：[配置 VPN 客户端](#配置-ikev2-vpn-客户端)。\n</details>\n\n## 移除 IKEv2\n\n如果你想要从 VPN 服务器移除 IKEv2，但是保留 [IPsec/L2TP](clients-zh.md) 和 [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth-zh.md) 模式（如果已安装），可以运行辅助脚本。**警告：** 这将**永久删除**所有的 IKEv2 配置（包括证书和密钥），并且**不可撤销**！\n\n```bash\nsudo ikev2.sh --removeikev2\n```\n\n在移除 IKEv2 之后，如果你想要重新配置 IKEv2，参见[这一小节](#使用辅助脚本配置-ikev2)。\n\n<details>\n<summary>\n另外，你也可以手动移除 IKEv2。\n</summary>\n\n要手动从 VPN 服务器移除 IKEv2，但是保留 [IPsec/L2TP](clients-zh.md) 和 [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth-zh.md) 模式，按照以下步骤操作。这些命令必须用 `root` 账户运行。\n\n**警告：** 这将**永久删除**所有的 IKEv2 配置（包括证书和密钥），并且**不可撤销**！\n\n1. 重命名（或者删除）IKEv2 配置文件：\n\n   ```bash\n   mv /etc/ipsec.d/ikev2.conf /etc/ipsec.d/ikev2.conf.bak\n   ```\n\n   **注：** 如果你使用了较旧版本（2020-05-31 之前）的 IKEv2 辅助脚本或者配置说明，文件 `/etc/ipsec.d/ikev2.conf` 可能不存在。在该情况下，请移除文件 `/etc/ipsec.conf` 中的 `conn ikev2-cp` 部分。\n\n1. **（重要）重启 IPsec 服务**：\n\n   ```bash\n   service ipsec restart\n   ```\n\n1. 列出 IPsec 证书数据库中的证书：\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   示例输出：\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n1. 删除证书吊销列表 (CRL)，如果存在：\n\n   ```bash\n   crlutil -D -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" 2>/dev/null\n   ```\n\n1. 删除证书和密钥。将下面的 \"Nickname\" 替换为每个证书的昵称。为每个证书重复这些命令。在完成后，再次列出 IPsec 证书数据库中的证书，并确认列表为空。\n\n   ```bash\n   certutil -F -d sql:/etc/ipsec.d -n \"Nickname\"\n   certutil -D -d sql:/etc/ipsec.d -n \"Nickname\" 2>/dev/null\n   ```\n</details>\n\n## 参考链接\n\n* https://libreswan.org/wiki/VPN_server_for_remote_clients_using_IKEv2\n* https://libreswan.org/wiki/HOWTO:_Using_NSS_with_libreswan\n* https://libreswan.org/man/ipsec.conf.5.html\n* https://docs.strongswan.org/docs/5.9/interop/windowsClients.html\n* https://docs.strongswan.org/docs/5.9/os/androidVpnClient.html\n* https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_certutil/index.html\n* https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_crlutil/index.html\n\n## 授权协议\n\n版权所有 (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n这个项目是以[知识共享署名-相同方式共享3.0](http://creativecommons.org/licenses/by-sa/3.0/) 许可协议授权。   \n必须署名： 请包括我的名字在任何衍生产品，并且让我知道你是如何改善它的！\n"
  },
  {
    "path": "docs/ikev2-howto.md",
    "content": "[English](ikev2-howto.md) | [中文](ikev2-howto-zh.md)\n\n# Guide: How to Set Up and Use IKEv2 VPN\n\n* [Introduction](#introduction)\n* [Configure IKEv2 VPN clients](#configure-ikev2-vpn-clients)\n* [IKEv2 troubleshooting](#ikev2-troubleshooting)\n* [Manage IKEv2 clients](#manage-ikev2-clients)\n* [Change IKEv2 server address](#change-ikev2-server-address)\n* [Update IKEv2 helper script](#update-ikev2-helper-script)\n* [Set up IKEv2 using helper script](#set-up-ikev2-using-helper-script)\n* [Manually set up IKEv2](#manually-set-up-ikev2)\n* [Remove IKEv2](#remove-ikev2)\n\n## Introduction\n\nModern operating systems support the IKEv2 standard. Internet Key Exchange (IKE or IKEv2) is the protocol used to set up a Security Association (SA) in the IPsec protocol suite. Compared to IKE version 1, IKEv2 contains [improvements](https://en.wikipedia.org/wiki/Internet_Key_Exchange#Improvements_with_IKEv2) such as Standard Mobility support through MOBIKE, and improved reliability.\n\nLibreswan can authenticate IKEv2 clients on the basis of X.509 Machine Certificates using RSA signatures. This method does not require an IPsec PSK, username or password. It can be used with Windows, macOS, iOS, Android, Chrome OS, Linux and RouterOS.\n\nBy default, IKEv2 is automatically set up when running the VPN setup script. If you want to learn more about setting up IKEv2, see [Set up IKEv2 using helper script](#set-up-ikev2-using-helper-script). Docker users, see [Configure and use IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md#configure-and-use-ikev2-vpn).\n\n## Configure IKEv2 VPN clients\n\n**Note:** To add or export IKEv2 clients, run `sudo ikev2.sh`. Use `-h` to show usage. Client config files can be safely deleted after import.\n\n* [Windows 7, 8, 10 and 11](#windows-7-8-10-and-11)\n* [OS X (macOS)](#os-x-macos)\n* [iOS (iPhone/iPad)](#ios)\n* [Android](#android)\n* [Chrome OS (Chromebook)](#chrome-os)\n* [Linux](#linux)\n* [MikroTik RouterOS](#routeros)\n\n<details>\n<summary>\nLearn how to change the IKEv2 server address.\n</summary>\n\nIn certain circumstances, you may need to change the IKEv2 server address. For example, to switch to use a DNS name, or after server IP changes. Learn more in [this section](#change-ikev2-server-address).\n</details>\n\n### Windows 7, 8, 10 and 11\n\n#### Auto-import configuration\n\n[**Screencast:** IKEv2 Auto Import Configuration on Windows](https://ko-fi.com/post/IKEv2-Auto-Import-Configuration-on-Windows-8-10-a-K3K1DQCHW)\n\n**Windows 8, 10 and 11+** users can automatically import IKEv2 configuration:\n\n1. Securely transfer the generated `.p12` file to your computer.\n1. Right-click on [ikev2_config_import.cmd](https://github.com/hwdsl2/vpn-extras/releases/latest/download/ikev2_config_import.cmd) and save this helper script to the **same folder** as the `.p12` file.\n1. Right-click on the saved script, select **Properties**. Click on **Unblock** at the bottom, then click on **OK**.\n1. Right-click on the saved script, select **Run as administrator** and follow the prompts.\n\nTo connect to the VPN: Click on the wireless/network icon in your system tray, select the new VPN entry, and click **Connect**. Once connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n**Note:** If you reinstalled the VPN server, you may want to first remove existing IKEv2 client and CA certificates, then follow the steps above to import the new `.p12` file. This helps make sure that Windows uses the correct client certificate when connecting to the VPN. See \"Remove the IKEv2 VPN connection\" below for more details.\n\n#### Manually import configuration\n\n[[Supporters] **Screencast:** IKEv2 Manually Import Configuration on Windows](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)\n\nAlternatively, **Windows 7, 8, 10 and 11+** users can manually import IKEv2 configuration:\n\n1. Securely transfer the generated `.p12` file to your computer, then import it into the certificate store.\n\n   To import the `.p12` file, run the following from an [elevated command prompt](http://www.winhelponline.com/blog/open-elevated-command-prompt-windows/):\n\n   ```console\n   # Import .p12 file (replace with your own value)\n   certutil -f -importpfx \"\\path\\to\\your\\file.p12\" NoExport\n   ```\n\n   **Note:** If there is no password for client config files, press Enter to continue, or if manually importing the `.p12` file, leave the password field blank.\n\n   Alternatively, you can [manually import the .p12 file](https://wiki.strongswan.org/projects/strongswan/wiki/Win7Certs/9). Make sure that the client cert is placed in \"Personal -> Certificates\", and the CA cert is placed in \"Trusted Root Certification Authorities -> Certificates\".\n\n1. On the Windows computer, add a new IKEv2 VPN connection.\n\n   For **Windows 8, 10 and 11+**, it is recommended to create the VPN connection using the following commands from a command prompt, for improved security and performance.\n\n   ```console\n   # Create VPN connection (replace server address with your own value)\n   powershell -command ^\"Add-VpnConnection -ServerAddress 'Your VPN Server IP (or DNS name)' ^\n     -Name 'My IKEv2 VPN' -TunnelType IKEv2 -AuthenticationMethod MachineCertificate ^\n     -EncryptionLevel Required -PassThru^\"\n   # Set IPsec configuration\n   powershell -command ^\"Set-VpnConnectionIPsecConfiguration -ConnectionName 'My IKEv2 VPN' ^\n     -AuthenticationTransformConstants GCMAES128 -CipherTransformConstants GCMAES128 ^\n     -EncryptionMethod AES256 -IntegrityCheckMethod SHA256 -PfsGroup None ^\n     -DHGroup Group14 -PassThru -Force^\"\n   ```\n\n   **Windows 7** does not support these commands, you can [manually create the VPN connection](https://wiki.strongswan.org/projects/strongswan/wiki/Win7Config/8).\n\n   **Note:** The server address you specify must **exactly match** the server address in the output of the IKEv2 helper script. For example, if you specified the server's DNS name during IKEv2 setup, you must enter the DNS name in the **Internet address** field.\n\n1. **This step is required if you manually created the VPN connection.**\n\n   Enable stronger ciphers for IKEv2 with a one-time registry change. Download and import the `.reg` file below, or run the following from an elevated command prompt. Read more [here](https://docs.strongswan.org/docs/5.9/interop/windowsClients.html).\n\n   - For Windows 7, 8, 10 and 11 ([download .reg file](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Enable_Stronger_Ciphers_for_IKEv2_on_Windows.reg))\n\n     ```console\n     REG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v NegotiateDH2048_AES256 /t REG_DWORD /d 0x1 /f\n     ```\n\nTo connect to the VPN: Click on the wireless/network icon in your system tray, select the new VPN entry, and click **Connect**. Once connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n<details>\n<summary>\nRemove the IKEv2 VPN connection.\n</summary>\n\nUsing the following steps, you can remove the VPN connection and optionally restore the computer to the status before IKEv2 configuration import.\n\n1. Remove the added VPN connection in Windows Settings -> Network -> VPN. Windows 7 users can remove the VPN connection in Network and Sharing Center -> Change adapter settings.\n\n1. (Optional) Remove IKEv2 certificates.\n\n   1. **Windows 8, 10 and 11:** Press Win+R and enter `certlm.msc`, or search for `certlm.msc` in the Start Menu. Open *Certificates - Local Computer*.   \n      **Windows 7:** Press Win+R and enter `mmc`, or search for `mmc` in the Start Menu. Open *Management Console*. Open `File - Add/Remove Snap-In`. Select to add `Certificates` and in the window that opens, select `Computer account -> Local Computer`. Click on `Finish -> OK` to save the settings.\n\n   1. Go to Certificates -> Personal -> Certificates and delete the IKEv2 client certificate. The name of the certificate is the same as the IKEv2 client name you specified (default: `vpnclient`). The certificate was issued by `IKEv2 VPN CA`.\n\n   1. Go to Certificates -> Trusted Root Certification Authorities -> Certificates and delete the IKEv2 VPN CA certificate. The certificate was issued to `IKEv2 VPN CA` by `IKEv2 VPN CA`. Before deleting, make sure that there are no other certificate(s) issued by `IKEv2 VPN CA` in Certificates -> Personal -> Certificates.\n\n1. (Optional. For users who manually created the VPN connection) Restore registry settings. Note that you should backup the registry before editing.\n\n   1. Press Win+R, or search for `regedit` in the Start Menu. Open *Registry Editor*.\n\n   1. Go to `HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\Rasman\\Parameters` and delete the item with name `NegotiateDH2048_AES256`, if it exists.\n</details>\n\n### OS X (macOS)\n\n[[Supporters] **Screencast:** IKEv2 Import Configuration and Connect on macOS](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)\n\nFirst, securely transfer the generated `.mobileconfig` file to your Mac, then double-click and follow the prompts to import as a macOS profile. If your Mac runs macOS Big Sur or newer, open System Preferences and go to the Profiles section to finish importing. For macOS Ventura and newer, open System Settings and search for Profiles. When finished, check to make sure \"IKEv2 VPN\" is listed under System Preferences -> Profiles.\n\nTo connect to the VPN:\n\n1. Open System Preferences and go to the Network section.\n1. Select the VPN connection with `Your VPN Server IP` (or DNS name).\n1. Check the **Show VPN status in menu bar** checkbox. For macOS Ventura and newer, this setting can be configured in System Settings -> Control Center -> Menu Bar Only section.\n1. Click **Connect**, or slide the VPN switch ON.\n\n(Optional feature) Enable **VPN On Demand** to automatically start a VPN connection when your Mac is on Wi-Fi. To enable, check the **Connect on demand** checkbox for the VPN connection, and click **Apply**. To find this setting on macOS Ventura and newer, click on the \"i\" icon on the right of the VPN connection.\n\nYou can customize VPN On Demand rules to exclude certain Wi-Fi networks (such as your home network). For more information, see the chapter \"Guide: Customize IKEv2 VPN On Demand rules for macOS and iOS\" in [:book: Book: Set Up Your Own IPsec VPN, OpenVPN and WireGuard Server](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J).\n\n<details>\n<summary>\nIf you manually set up IKEv2 without using the helper script, click here for instructions.\n</summary>\n\nFirst, securely transfer the generated `.p12` file to your Mac, then double-click to import into the **login** keychain in **Keychain Access**. Next, double-click on the imported `IKEv2 VPN CA` certificate, expand **Trust** and select **Always Trust** from the **IP Security (IPsec)** drop-down menu. Close the dialog using the red \"X\" on the top-left corner. When prompted, use Touch ID or enter your password and click \"Update Settings\".\n\nWhen finished, check to make sure both the new client certificate and `IKEv2 VPN CA` are listed under the **Certificates** category of **login** keychain.\n\n1. Open System Preferences and go to the Network section.\n1. Click the **+** button in the lower-left corner of the window.\n1. Select **VPN** from the **Interface** drop-down menu.\n1. Select **IKEv2** from the **VPN Type** drop-down menu.\n1. Enter anything you like for the **Service Name**.\n1. Click **Create**.\n1. Enter `Your VPN Server IP` (or DNS name) for the **Server Address**.   \n   **Note:** If you specified the server's DNS name (instead of its IP address) during IKEv2 setup, you must enter the DNS name in the **Server Address** and **Remote ID** fields.\n1. Enter `Your VPN Server IP` (or DNS name) for the **Remote ID**.\n1. Enter `Your VPN client name` in the **Local ID** field.   \n   **Note:** This must match exactly the client name you specified during IKEv2 setup. Same as the first part of your `.p12` filename.\n1. Click the **Authentication Settings...** button.\n1. Select **None** from the **Authentication Settings** drop-down menu.\n1. Select the **Certificate** radio button, then select the new client certificate.\n1. Click **OK**.\n1. Check the **Show VPN status in menu bar** checkbox.\n1. Click **Apply** to save the VPN connection information.\n1. Click **Connect**.\n</details>\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n**Note:** macOS 14 (Sonoma) has a minor issue that may cause IKEv2 VPN to disconnect and reconnect once every 24-48 minutes. Other macOS versions are not affected. For more details and a workaround, see [macOS Sonoma clients reconnect](#macos-sonoma-clients-reconnect).\n\n<details>\n<summary>\nRemove the IKEv2 VPN connection.\n</summary>\n\nTo remove the IKEv2 VPN connection, open System Preferences -> Profiles and remove the IKEv2 VPN profile you added.\n</details>\n\n### iOS\n\n[[Supporters] **Screencast:** IKEv2 Import Configuration and Connect on iOS (iPhone & iPad)](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)\n\nFirst, securely transfer the generated `.mobileconfig` file to your iOS device, then import it as an iOS profile. To transfer the file, you may use:\n\n1. AirDrop, or\n1. Upload to your device (any App folder) using [File Sharing](https://support.apple.com/en-us/HT210598), then open the \"Files\" App on your iOS device, move the uploaded file to the \"On My iPhone\" folder. After that, tap the file and go to the \"Settings\" App to import, or\n1. Host the file on a secure website of yours, then download and import it in Mobile Safari.\n\nWhen finished, check to make sure \"IKEv2 VPN\" is listed under Settings -> General -> VPN & Device Management or Profile(s).\n\nTo connect to the VPN:\n\n1. Go to Settings -> VPN. Select the VPN connection with `Your VPN Server IP` (or DNS name).\n1. Slide the **VPN** switch ON.\n\n(Optional feature) Enable **VPN On Demand** to automatically start a VPN connection when your iOS device is on Wi-Fi. To enable, tap the \"i\" icon on the right of the VPN connection, and enable **Connect On Demand**.\n\nYou can customize VPN On Demand rules to exclude certain Wi-Fi networks (such as your home network). For more information, see the chapter \"Guide: Customize IKEv2 VPN On Demand rules for macOS and iOS\" in [:book: Book: Set Up Your Own IPsec VPN, OpenVPN and WireGuard Server](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J).\n\n<details>\n<summary>\nCustomize VPN On Demand rules: Connect on Wi-Fi and cellular networks.\n</summary>\n\nThe default VPN On Demand configuration only starts a VPN connection on Wi-Fi networks, but not on cellular networks. If you want the VPN to connect on both Wi-Fi and cellular networks:\n\n1. Edit `/opt/src/ikev2.sh` on the VPN server. Find the lines:\n   ```\n     <dict>\n       <key>InterfaceTypeMatch</key>\n       <string>Cellular</string>\n       <key>Action</key>\n       <string>Disconnect</string>\n     </dict>\n   ```\n   and replace \"Disconnect\" with \"Connect\":\n   ```\n     <dict>\n       <key>InterfaceTypeMatch</key>\n       <string>Cellular</string>\n       <key>Action</key>\n       <string>Connect</string>\n     </dict>\n   ```\n2. Save the file, then run `sudo ikev2.sh` to export updated client config files for your iOS device(s).\n3. Remove the previously imported VPN profile from your iOS device(s), then import the new `.mobileconfig` file(s) from step 2.\n</details>\n<details>\n<summary>\nIf you manually set up IKEv2 without using the helper script, click here for instructions.\n</summary>\n\nFirst, securely transfer the generated `ca.cer` and `.p12` files to your iOS device, then import them one by one as iOS profiles. To transfer the files, you may use:\n\n1. AirDrop, or\n1. Upload to your device (any App folder) using [File Sharing](https://support.apple.com/en-us/HT210598), then open the \"Files\" App on your iOS device, move the uploaded files to the \"On My iPhone\" folder. After that, tap each file and go to the \"Settings\" App to import, or\n1. Host the files on a secure website of yours, then download and import them in Mobile Safari.\n\nWhen finished, check to make sure both the new client certificate and `IKEv2 VPN CA` are listed under Settings -> General -> VPN & Device Management or Profile(s).\n\n1. Go to Settings -> General -> VPN & Device Management -> VPN.\n1. Tap **Add VPN Configuration...**.\n1. Tap **Type**. Select **IKEv2** and go back.\n1. Tap **Description** and enter anything you like.\n1. Tap **Server** and enter `Your VPN Server IP` (or DNS name).   \n   **Note:** If you specified the server's DNS name (instead of its IP address) during IKEv2 setup, you must enter the DNS name in the **Server** and **Remote ID** fields.\n1. Tap **Remote ID** and enter `Your VPN Server IP` (or DNS name).\n1. Enter `Your VPN client name` in the **Local ID** field.   \n   **Note:** This must match exactly the client name you specified during IKEv2 setup. Same as the first part of your `.p12` filename.\n1. Tap **User Authentication**. Select **None** and go back.\n1. Make sure the **Use Certificate** switch is ON.\n1. Tap **Certificate**. Select the new client certificate and go back.\n1. Tap **Done**.\n1. Slide the **VPN** switch ON.\n</details>\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n<details>\n<summary>\nRemove the IKEv2 VPN connection.\n</summary>\n\nTo remove the IKEv2 VPN connection, open Settings -> General -> VPN & Device Management or Profile(s) and remove the IKEv2 VPN profile you added.\n</details>\n\n### Android\n\n#### Using strongSwan VPN client\n\n[[Supporters] **Screencast:** Connect using Android strongSwan VPN Client](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)\n\nAndroid users can connect using strongSwan VPN client (recommended).\n\n1. Securely transfer the generated `.sswan` file to your Android device.\n1. Install strongSwan VPN Client from [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android), [**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) or [**strongSwan download server**](https://download.strongswan.org/Android/).\n1. Launch the strongSwan VPN client.\n1. Tap the \"more options\" menu on top right, then tap **Import VPN profile**.\n1. Choose the `.sswan` file you transferred from the VPN server.   \n   **Note:** To find the `.sswan` file, tap the three-line menu button, then browse to the location you saved the file.\n1. On the \"Import VPN profile\" screen, tap **IMPORT CERTIFICATE FROM VPN PROFILE**, and follow the prompts.\n1. On the \"Choose certificate\" screen, select the new client certificate, then tap **Select**.\n1. Tap **IMPORT**.\n1. Tap the new VPN profile to connect.\n\n(Optional feature) You can choose to enable the \"Always-on VPN\" feature on Android. Launch the **Settings** app, go to Network & internet -> Advanced -> VPN, click the gear icon on the right of \"strongSwan VPN Client\", then enable the **Always-on VPN** and **Block connections without VPN** options.\n\n<details>\n<summary>\nIf your device runs Android 6.0 or older, click here for additional instructions.\n</summary>\n\nIf your device runs Android 6.0 (Marshmallow) or older, in order to connect using the strongSwan VPN client, you must make the following change on the VPN server: Edit `/etc/ipsec.d/ikev2.conf` on the server. Append `authby=rsa-sha1` to the end of the `conn ikev2-cp` section, indented by two spaces. Save the file and run `service ipsec restart`.\n</details>\n<details>\n<summary>\nIf you manually set up IKEv2 without using the helper script, click here for instructions.\n</summary>\n\n**Android 10 and newer:**\n\n1. Securely transfer the generated `.p12` file to your Android device.\n1. Install strongSwan VPN Client from [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android), [**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) or [**strongSwan download server**](https://download.strongswan.org/Android/).\n1. Launch the **Settings** application.\n1. Go to Security -> Advanced -> Encryption & credentials.\n1. Tap **Install a certificate**.\n1. Tap **VPN & app user certificate**.\n1. Choose the `.p12` file you transferred from the VPN server, and follow the prompts.   \n   **Note:** To find the `.p12` file, tap the three-line menu button, then browse to the location you saved the file.\n1. Launch the strongSwan VPN client and tap **Add VPN Profile**.\n1. Enter `Your VPN Server IP` (or DNS name) in the **Server** field.   \n   **Note:** If you specified the server's DNS name (instead of its IP address) during IKEv2 setup, you must enter the DNS name in the **Server** field.\n1. Select **IKEv2 Certificate** from the **VPN Type** drop-down menu.\n1. Tap **Select user certificate**, select the new client certificate and confirm.\n1. **(Important)** Tap **Show advanced settings**. Scroll down, find and enable the **Use RSA/PSS signatures** option.\n1. Save the new VPN connection, then tap to connect.\n\n**Android 4 to 9:**\n\n1. Securely transfer the generated `.p12` file to your Android device.\n1. Install strongSwan VPN Client from [**Google Play**](https://play.google.com/store/apps/details?id=org.strongswan.android), [**F-Droid**](https://f-droid.org/en/packages/org.strongswan.android/) or [**strongSwan download server**](https://download.strongswan.org/Android/).\n1. Launch the strongSwan VPN client and tap **Add VPN Profile**.\n1. Enter `Your VPN Server IP` (or DNS name) in the **Server** field.   \n   **Note:** If you specified the server's DNS name (instead of its IP address) during IKEv2 setup, you must enter the DNS name in the **Server** field.\n1. Select **IKEv2 Certificate** from the **VPN Type** drop-down menu.\n1. Tap **Select user certificate**, then tap **Install certificate**.\n1. Choose the `.p12` file you transferred from the VPN server, and follow the prompts.   \n   **Note:** To find the `.p12` file, tap the three-line menu button, then browse to the location you saved the file.\n1. **(Important)** Tap **Show advanced settings**. Scroll down, find and enable the **Use RSA/PSS signatures** option.\n1. Save the new VPN connection, then tap to connect.\n</details>\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n#### Using native IKEv2 client\n\n[[Supporters] **Screencast:** Connect using Native VPN Client on Android 11+](https://ko-fi.com/post/Support-this-project-and-get-access-to-supporter-o-O5O7FVF8J)\n\nAndroid 11+ users can also connect using the native IKEv2 client.\n\n1. Securely transfer the generated `.p12` file to your Android device.\n1. Launch the **Settings** application.\n1. Go to Security -> Advanced -> Encryption & credentials.\n1. Tap **Install a certificate**.\n1. Tap **VPN & app user certificate**.\n1. Choose the `.p12` file you transferred from the VPN server.   \n   **Note:** To find the `.p12` file, tap the three-line menu button, then browse to the location you saved the file.\n1. Enter a name for the certificate, then tap **OK**.\n1. Go to Settings -> Network & internet -> VPN, then tap the \"+\" button.\n1. Enter a name for the VPN profile.\n1. Select **IKEv2/IPSec RSA** from the **Type** drop-down menu.\n1. Enter `Your VPN Server IP` (or DNS name) in the **Server address** field.   \n   **Note:** This must **exactly match** the server address in the output of the IKEv2 helper script.\n1. Enter anything you like for the **IPSec identifier**.   \n   **Note:** This field should not be required. It is a bug in Android.\n1. Select the certificate you imported from the **IPSec user certificate** drop-down menu.\n1. Select the certificate you imported from the **IPSec CA certificate** drop-down menu.\n1. Select **(receive from server)** from the **IPSec server certificate** drop-down menu.\n1. Tap **Save**. Then tap the new VPN connection and tap **Connect**.\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n### Chrome OS\n\nFirst, on your VPN server, export the CA certificate as `ca.cer`:\n\n```bash\nsudo certutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -a -o ca.cer\n```\n\nSecurely transfer the generated `.p12` and `ca.cer` files to your Chrome OS device.\n\nInstall user and CA certificates:\n\n1. Open a new tab in Google Chrome.\n1. In the address bar, enter **chrome://settings/certificates**\n1. **(Important)** Click **Import and Bind**, not **Import**.\n1. In the box that opens, choose the `.p12` file you transferred from the VPN server and select **Open**.\n1. Click **OK** if the certificate does not have a password. Otherwise, enter the certificate's password.\n1. Click the **Authorities** tab. Then click **Import**.\n1. In the box that opens, select **All files** in the drop-down menu at the bottom left.\n1. Choose the `ca.cer` file you transferred from the VPN server and select **Open**.\n1. Keep the default options and click **OK**.\n\nAdd a new VPN connection:\n\n1. Go to Settings -> Network.\n1. Click **Add connection**, then click **Add built-in VPN**.\n1. Enter anything you like for the **Service name**.\n1. Select **IPsec (IKEv2)** in the **Provider type** drop-down menu.\n1. Enter `Your VPN Server IP` (or DNS name) for the **Server hostname**.\n1. Select **User certificate** in the **Authentication type** drop-down menu.\n1. Select **IKEv2 VPN CA [IKEv2 VPN CA]** in the **Server CA certificate** drop-down menu.\n1. Select **IKEv2 VPN CA [client name]** in the **User certificate** drop-down menu.\n1. Leave other fields blank.\n1. Enable **Save identity and password**.\n1. Click **Connect**.\n\nOnce connected, you will see a VPN icon overlay on the network status icon. You can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\n(Optional feature) You can choose to enable the \"Always-on VPN\" feature on Chrome OS. To manage this setting, go to Settings -> Network, then click **VPN**.\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n### Linux\n\nBefore configuring Linux VPN clients, you must make the following change on the VPN server: Edit `/etc/ipsec.d/ikev2.conf` on the server. Append `authby=rsa-sha1` to the end of the `conn ikev2-cp` section, indented by two spaces. Save the file and run `service ipsec restart`.\n\nTo configure your Linux computer to connect to IKEv2 as a VPN client, first install the strongSwan plugin for NetworkManager:\n\n#### Ubuntu and Debian\n\n```bash\nsudo apt-get update\nsudo apt-get install network-manager-strongswan\n```\n\n#### Arch Linux\n\n```bash\nsudo pacman -Syu  # upgrade all packages\nsudo pacman -S networkmanager-strongswan\n```\n\n#### Fedora\n\n\nFor KDE Plasma/LXQt users:\n\n```bash\nsudo dnf install NetworkManager-strongswan-gnome plasma-nm-strongswan\n```\nOther DEs:\n```bash\nsudo dnf install NetworkManager-strongswan-gnome\n```\n\n\n#### CentOS\n\n```bash\nsudo yum install epel-release\nsudo yum --enablerepo=epel install NetworkManager-strongswan-gnome\n```\n\nNext, securely transfer the generated `.p12` file from the VPN server to your Linux computer. After that, extract the CA certificate, client certificate and private key. Replace `vpnclient.p12` in the example below with the name of your `.p12` file.\n\n```bash\n# Example: Extract CA certificate, client certificate and private key.\n#          You may delete the .p12 file when finished.\n# Note: You may need to enter the import password, which can be found\n#       in the output of the IKEv2 helper script. If the output does not\n#       contain an import password, press Enter to continue.\n# Note: If using OpenSSL 3.x (run \"openssl version\" to check),\n#       append \"-legacy\" to the 3 commands below.\nopenssl pkcs12 -in vpnclient.p12 -cacerts -nokeys -out ca.cer\nopenssl pkcs12 -in vpnclient.p12 -clcerts -nokeys -out client.cer\nopenssl pkcs12 -in vpnclient.p12 -nocerts -nodes  -out client.key\nrm vpnclient.p12\n\n# (Important) Protect certificate and private key files\n# Note: This step is optional, but strongly recommended.\nsudo chown root:root ca.cer client.cer client.key\nsudo chmod 600 ca.cer client.cer client.key\n```\n>[!IMPORTANT]\n>\n>**_Fedora_** and its derivatives require a few extra steps to setup due to their default security policies.\n><details markdown=\"1\">\n><summary>For <b>Fedora/Nobara 39+</b> clients:</summary>\n><br>\n>\n>\n>## 1. Enable SHA1 Support\n>\n>Fedora 39+ disables SHA-1 cryptographic support by default. Since this VPN setup uses SHA-1 for certificate generation, you need to re-enable it system-wide. Run the following command:\n>\n>```\n>sudo update-crypto-policies --set DEFAULT:SHA1\n>```\n>**<ins>Reboot your system</ins>** after running this command. <br/>\n>    \n>## 2. Set Secure File Ownership\n>\n>Fedora systems require that certificate and key files be owned by root. You can set the correct ownership using the `chown` command.\n>\n>```\n>sudo chown root:root ca.cer client.cer client.key\n>```\n>\n>## 3. Create System Directories\n>\n>Create the official directories where the strongSwan service looks for certificates and private keys.\n>\n>```\n>sudo mkdir -p /etc/ipsec.d/{certs,private}\n>```\n>\n>## 4. Move Files into Place\n>\n>Move the certificate and key files from your current location into the newly created system directories.\n>\n>\n>```\n># Move certificates\n>sudo mv /path/to/ca.cer /path/to/client.cer /etc/ipsec.d/certs/\n>\n># Move private key\n>sudo mv /path/to/client.key /etc/ipsec.d/private/\n>```\n>\n>## 5. Apply SELinux Contexts (If SELinux is Active)\n>    \n>This command updates the security context of the files, ensuring they are correctly labeled for use by the VPN service. It will only run if SELinux is enabled on your system (_à la_ Fedora).\n>\n>```bash\n> bash -c '\n># Check if SELinux is enabled and apply contexts if necessary\n>if command -v sestatus >/dev/null 2>&1 && sestatus | grep -q \"SELinux status:.*enabled\"; then\n>    sudo restorecon -R -v /etc/ipsec.d/\n>    echo \"SELinux contexts applied successfully. Proceed to step 6.\"\n>else\n>    echo \"SELinux not active or not found - skipping context restoration. Proceed to step 6.\"\n>fi'\n>```\n>\n>## 6. Continue to NetworkManager Setup\n>\n>You are now ready to configure the connection using the graphical editor. Open it with:\n>\n>```\n>sudo nm-connection-editor\n>```\n>Proceed with the general Linux instructions below. When prompted to select certificate and key files during setup, use the files you just transferred to `/etc/ipsec.d/`. (Press **`Ctrl+L`** in the file picker to type the full paths directly.)\n>\n>The paths, for your convenience, are:\n>\n>`/etc/ipsec.d/certs/` & `/etc/ipsec.d/private/`\n></details>\n\n\nYou can then set up and enable the VPN connection:\n\n1. Go to Settings -> Network -> VPN. Click the **+** button.\n1. Select **IPsec/IKEv2 (strongswan)**.\n1. Enter anything you like in the **Name** field.\n1. In the **Gateway (Server)** section, enter `Your VPN Server IP` (or DNS name) for the **Address**.\n1. Select the `ca.cer` file for the **Certificate**.\n1. In the **Client** section, select **Certificate(/private key)** in the **Authentication** drop-down menu.\n1. Select **Certificate/private key** in the **Certificate** drop-down menu (if exists).\n1. Select the `client.cer` file for the **Certificate (file)**.\n1. Select the `client.key` file for the **Private key**.\n1. In the **Options** section, check the **Request an inner IP address** checkbox.\n1. In the **Cipher proposals (Algorithms)** section, check the **Enable custom proposals** checkbox.\n1. Leave the **IKE** field blank.\n1. Enter `aes128gcm16` in the **ESP** field.\n1. Click **Add** to save the VPN connection information.\n1. Turn the **VPN** switch ON.\n\n\n>[!TIP]\n> If you're using the KDE Plasma desktop, you might encounter issues when configuring the VPN through the graphical System Settings. To ensure a smooth setup, we recommend launching the dedicated connection editor instead by running `sudo nm-connection-editor` in a terminal.\n\n\nAlternatively, you may connect using the command line. See [#1399](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1399), [#1007](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1007) and [#1789](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1789) for example steps. If you encounter error `Could not find source connection`, edit `/etc/netplan/01-netcfg.yaml` and replace `renderer: networkd` with `renderer: NetworkManager`, then run `sudo netplan apply`. If using `nmcli` to connect to the VPN, run `sudo nmcli c up VPN`. To disconnect: `sudo nmcli c down VPN`.\n\nOnce connected, you can verify that your traffic is being routed properly by [looking up your IP address on Google](https://www.google.com/search?q=my+ip). It should say \"Your public IP address is `Your VPN Server IP`\".\n\nIf you get an error when trying to connect, see [Troubleshooting](#ikev2-troubleshooting).\n\n### RouterOS\n\n**Note:** These steps were contributed by [@Unix-User](https://github.com/Unix-User). It is recommended to run terminal commands via an SSH connection, e.g. via Putty.\n\n1. Securely transfer the generated `.p12` file to your computer.\n\n   <details>\n   <summary>\n   Click to see screencast.\n   </summary>\n\n   ![routeros get certificate](images/routeros-get-cert.gif)\n   </details>\n\n2. In WinBox, go to System > certificates > import. Import the `.p12` certificate file twice (yes, import the same file two times!). Verify in your certificates panel. You will see 2 files, the one that is marked KT is the key.\n\n   <details>\n   <summary>\n   Click to see screencast.\n   </summary>\n\n   ![routeros import certificate](images/routeros-import-cert.gif)\n   </details>\n\n   Or you can use terminal instead (empty passphrase):\n\n   ```bash\n   [admin@MikroTik] > /certificate/import file-name=mikrotik.p12\n   passphrase:\n\n     certificates-imported: 2\n     private-keys-imported: 0\n            files-imported: 1\n       decryption-failures: 0\n     keys-with-no-certificate: 0\n\n   [admin@MikroTik] > /certificate/import file-name=mikrotik.p12\n   passphrase:\n\n        certificates-imported: 0\n        private-keys-imported: 1\n               files-imported: 1\n          decryption-failures: 0\n     keys-with-no-certificate: 0\n\n   ```\n\n3. Run these commands in terminal. Replace the following with your own values.\n`YOUR_VPN_SERVER_IP_OR_DNS_NAME` is your VPN server IP or DNS name.\n`IMPORTED_CERTIFICATE` is the name of the certificate from step 2 above, e.g. `vpnclient.p12_0`\n(the one flagged with KT - Priv. Key Trusted - if not flagged as KT, import certificate again).\n`THESE_ADDRESSES_GO_THROUGH_VPN` are the local network addresses that you want to browse through the VPN.\nAssuming that your local network behind RouterOS is `192.168.0.0/24`, you can use `192.168.0.0/24`\nfor the entire network, or use `192.168.0.10` for just one device, and so on.\n\n   ```bash\n   /ip firewall address-list add address=THESE_ADDRESSES_GO_THROUGH_VPN list=local\n   /ip ipsec mode-config add name=ike2-rw responder=no src-address-list=local\n   /ip ipsec policy group add name=ike2-rw\n   /ip ipsec profile add name=ike2-rw\n   /ip ipsec peer add address=YOUR_VPN_SERVER_IP_OR_DNS_NAME exchange-mode=ike2 \\\n       name=ike2-rw-client profile=ike2-rw\n   /ip ipsec proposal add name=ike2-rw pfs-group=none\n   /ip ipsec identity add auth-method=digital-signature certificate=IMPORTED_CERTIFICATE \\\n       generate-policy=port-strict mode-config=ike2-rw \\\n       peer=ike2-rw-client policy-template-group=ike2-rw\n   /ip ipsec policy add group=ike2-rw proposal=ike2-rw template=yes\n   ```\n4. For more information, see [#1112](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1112#issuecomment-1059628623).\n\n> tested on   \n> mar/02/2022 12:52:57 by RouterOS 6.48   \n> RouterBOARD 941-2nD\n\n## IKEv2 troubleshooting\n\n*Read this in other languages: [English](ikev2-howto.md#ikev2-troubleshooting), [中文](ikev2-howto-zh.md#ikev2-故障排除).*\n\n**See also:** [Check logs and VPN status](clients.md#check-logs-and-vpn-status), [IKEv1 troubleshooting](clients.md#ikev1-troubleshooting) and [Advanced usage](advanced-usage.md).\n\n* [Cannot connect to the VPN server](#cannot-connect-to-the-vpn-server)\n* [Ubuntu 20.04 cannot import client config](#ubuntu-2004-cannot-import-client-config)\n* [macOS Sonoma clients reconnect](#macos-sonoma-clients-reconnect)\n* [Unable to connect multiple IKEv2 clients](#unable-to-connect-multiple-ikev2-clients)\n* [IKE authentication credentials are unacceptable](#ike-authentication-credentials-are-unacceptable)\n* [Policy match error](#policy-match-error)\n* [Parameter is incorrect](#parameter-is-incorrect)\n* [Cannot open websites after connecting to IKEv2](#cannot-open-websites-after-connecting-to-ikev2)\n* [Windows 10 connecting](#windows-10-connecting)\n* [Other known issues](#other-known-issues)\n\n### Cannot connect to the VPN server\n\nFirst, make sure that the VPN server address specified on your VPN client device **exactly matches** the server address in the output of the IKEv2 helper script. For example, you cannot use a DNS name to connect if it was not specified when setting up IKEv2. To change the IKEv2 server address, read [this section](#change-ikev2-server-address).\n\nFor servers with an external firewall (e.g. [EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)/[GCE](https://cloud.google.com/vpc/docs/firewalls)), open UDP ports 500 and 4500 for the VPN. Aliyun users, see [#433](https://github.com/hwdsl2/setup-ipsec-vpn/issues/433).\n\n[Check logs and VPN status](clients.md#check-logs-and-vpn-status) for errors. If you encounter retransmission related errors and are unable to connect, there may be network issues between the VPN client and server. If you are connecting from mainland China, consider switching to alternative solutions other than IPsec VPN.\n\n### Ubuntu 20.04 cannot import client config\n\nIf you installed the IPsec VPN before 2024-04-10, and your VPN server runs Ubuntu Linux version 20.04, you may have encountered an issue where newly generated client configuration files (`.mobileconfig`) fail to import on iOS or macOS device(s) with errors like \"incorrect password\". This could be caused by updates to libnss3 related packages on Ubuntu 20.04, which required some changes ([25670f3](https://github.com/hwdsl2/setup-ipsec-vpn/commit/25670f3)) in the IKEv2 script.\n\nTo fix this issue, first update the IKEv2 script on your server to the latest version using [these instructions](#update-ikev2-helper-script). After that, run `sudo ikev2.sh` and select \"export\" to re-create the client configuration files.\n\n### macOS Sonoma clients reconnect\n\nmacOS 14 (Sonoma) has [a minor issue](https://github.com/hwdsl2/setup-ipsec-vpn/issues/1486) that may cause IKEv2 VPN to disconnect and reconnect once every 24-48 minutes. Other macOS versions are not affected. First [check your macOS version](https://support.apple.com/en-us/HT201260). To work around this issue, follow the steps below.\n\n**Note:** If you installed IPsec VPN after December 10, 2023, no action is required because the following fixes are already included.\n\n1. Edit `/etc/ipsec.d/ikev2.conf` on the VPN server. Find the line:\n   ```\n     ike=aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n   ```\n   and replace it with the following:\n   ```\n     ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n   ```\n   **Note:** Docker users should first [open a Bash shell inside the container](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage.md#bash-shell-inside-container).\n1. Save the file and run `service ipsec restart`. Docker users: After step 4 below, `exit` the container and run `docker restart ipsec-vpn-server`.\n1. Edit `/opt/src/ikev2.sh` on the VPN server. Find and replace the following sections with these new values:\n   ```\n     <key>ChildSecurityAssociationParameters</key>\n     <dict>\n       <key>DiffieHellmanGroup</key>\n       <integer>19</integer>\n       <key>EncryptionAlgorithm</key>\n       <string>AES-256-GCM</string>\n       <key>LifeTimeInMinutes</key>\n       <integer>1410</integer>\n     </dict>\n   ```\n   ```\n     <key>IKESecurityAssociationParameters</key>\n     <dict>\n       <key>DiffieHellmanGroup</key>\n       <integer>19</integer>\n       <key>EncryptionAlgorithm</key>\n       <string>AES-256-GCM</string>\n       <key>IntegrityAlgorithm</key>\n       <string>SHA2-256</string>\n       <key>LifeTimeInMinutes</key>\n       <integer>1410</integer>\n     </dict>\n   ```\n1. Run `sudo ikev2.sh` to export (or add) updated client config files for each macOS device you have.\n1. Remove the previously imported IKEv2 profile (if any) from your macOS device(s), then import the updated `.mobileconfig` file(s). See [Configure IKEv2 VPN clients](#configure-ikev2-vpn-clients). Docker users, see [Configure and use IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md#configure-and-use-ikev2-vpn).\n\n### Unable to connect multiple IKEv2 clients\n\nTo connect multiple IKEv2 clients from behind the same NAT (e.g. home router) at the same time, you will need to generate a unique certificate for each client. Otherwise, you could encounter the issue where a later connected client affects the VPN connection of an existing client, which may lose Internet access.\n\nTo generate certificates for additional IKEv2 clients, run the helper script with the `--addclient` option. To customize client options, run the script without arguments.\n\n```bash\nsudo ikev2.sh --addclient [client name]\n```\n\n### IKE authentication credentials are unacceptable\n\nIf you encounter this error, make sure that the VPN server address specified on your VPN client device **exactly matches** the server address in the output of the IKEv2 helper script. For example, you cannot use a DNS name to connect if it was not specified when setting up IKEv2. To change the IKEv2 server address, read [this section](#change-ikev2-server-address).\n\n### Policy match error\n\nTo fix this error, you will need to enable stronger ciphers for IKEv2 with a one-time registry change. Download and import the `.reg` file below, or run the following from an elevated command prompt.\n\n- For Windows 7, 8, 10 and 11 ([download .reg file](https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0/Enable_Stronger_Ciphers_for_IKEv2_on_Windows.reg))\n\n```console\nREG ADD HKLM\\SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters /v NegotiateDH2048_AES256 /t REG_DWORD /d 0x1 /f\n```\n\n### Parameter is incorrect\n\nIf you encounter \"Error 87: The parameter is incorrect\" when trying to connect using IKEv2 mode, try the solutions in [this issue](https://github.com/trailofbits/algo/issues/1051), more specifically, step 2 \"reset device manager adapters\".\n\n### Cannot open websites after connecting to IKEv2\n\nIf your VPN client device cannot open websites after successfully connecting to IKEv2, try the following fixes:\n\n1. Some cloud providers, such as [Google Cloud](https://cloud.google.com), [set a lower MTU by default](https://cloud.google.com/network-connectivity/docs/vpn/concepts/mtu-considerations). This could cause network issues with IKEv2 VPN clients. To fix, try setting the MTU to 1500 on the VPN server:\n\n   ```bash\n   # Replace ens4 with the network interface name on your server\n   sudo ifconfig ens4 mtu 1500\n   ```\n\n   This setting **does not** persist after a reboot. To change the MTU size permanently, refer to relevant articles on the web.\n\n1. If your Android or Linux VPN client can connect using IKEv2 mode, but cannot open websites, try the fix in [Android/Linux MTU/MSS issues](clients.md#androidlinux-mtumss-issues).\n\n1. Windows VPN clients may not use the DNS servers specified by IKEv2 after connecting, if the client's configured DNS servers on the Internet adapter are from the local network segment. This can be fixed by manually entering DNS servers such as Google Public DNS (8.8.8.8, 8.8.4.4) in network interface properties -> TCP/IPv4. For more information, see [Windows DNS leaks and IPv6](clients.md#windows-dns-leaks-and-ipv6).\n\n### Windows 10 connecting\n\nIf using Windows 10 and the VPN is stuck on \"connecting\" for more than a few minutes, try these steps:\n\n1. Right-click on the wireless/network icon in your system tray.\n1. Select **Open Network & Internet settings**, then on the page that opens, click **VPN** on the left.\n1. Select the new VPN entry, then click **Connect**.\n\n### Other known issues\n\nThe built-in VPN client in Windows may not support IKEv2 fragmentation (this feature [requires](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ikee/74df968a-7125-431d-9c98-4ea929e548dc) Windows 10 v1803 or newer). On some networks, this can cause the connection to fail or have other issues. You may instead try the [IPsec/L2TP](clients.md) or [IPsec/XAuth](clients-xauth.md) mode.\n\n## Manage IKEv2 clients\n\n* [List existing clients](#list-existing-clients)\n* [Add a client certificate](#add-a-client-certificate)\n* [Export configuration for an existing client](#export-configuration-for-an-existing-client)\n* [Delete a client certificate](#delete-a-client-certificate)\n* [Revoke a client certificate](#revoke-a-client-certificate)\n\n### List existing clients\n\nTo list the names of existing IKEv2 clients, run the helper script with the `--listclients` option. Use option `-h` to show usage.\n\n```bash\nsudo ikev2.sh --listclients\n```\n\n### Add a client certificate\n\nTo generate certificates for additional IKEv2 clients, run the helper script with the `--addclient` option. To customize client options, run the script without arguments.\n\n```bash\nsudo ikev2.sh --addclient [client name]\n```\n\nAlternatively, you may manually add a client certificate. Refer to step 4 in [this section](#manually-set-up-ikev2).\n\n### Export configuration for an existing client\n\nBy default, the IKEv2 helper script exports client configuration after running. If later you want to export an existing client, you may use:\n\n```bash\nsudo ikev2.sh --exportclient [client name]\n```\n\n### Delete a client certificate\n\n**Important:** Deleting a client certificate from the IPsec database **WILL NOT** prevent VPN client(s) from connecting using that certificate! For this use case, you **MUST** [revoke the client certificate](#revoke-a-client-certificate) instead of deleting it.\n\n<details>\n<summary>\nFirst, read the important note above. Then click here for instructions.\n</summary>\n\n**Warning:** The client certificate and private key will be **permanently deleted**. This **cannot be undone**!\n\nTo delete an existing client:\n\n```bash\nsudo ikev2.sh --deleteclient [client name]\n```\n\n<details>\n<summary>\nAlternatively, you can manually delete a client certificate.\n</summary>\n\n1. List certificates in the IPsec database:\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   Example output:\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n1. Delete the client certificate and private key. Replace \"Nickname\" below with the nickname of the client certificate you want to delete, e.g. `vpnclient`.\n\n   ```bash\n   certutil -F -d sql:/etc/ipsec.d -n \"Nickname\"\n   certutil -D -d sql:/etc/ipsec.d -n \"Nickname\" 2>/dev/null\n   ```\n\n1. (Optional) Delete the previously generated client configuration files (`.p12`, `.mobileconfig` and `.sswan` files) for this VPN client, if any.\n</details>\n</details>\n\n### Revoke a client certificate\n\nIn certain circumstances, you may need to revoke a previously generated VPN client certificate.\n\nTo revoke an existing client:\n\n```bash\nsudo ikev2.sh --revokeclient [client name]\n```\n\n<details>\n<summary>\nAlternatively, you can manually revoke a client certificate.\n</summary>\n\nAlternatively, you can manually revoke a client certificate. This can be done using `crlutil`. See example steps below, commands must be run as `root`.\n\n1. Check the database, and identify the nickname of the client certificate you want to revoke.\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient-to-revoke                                u,u,u\n   ```\n\n   In this example, we will revoke the certificate with nickname `vpnclient-to-revoke`, issued by `IKEv2 VPN CA`.\n\n1. Find the serial number of this client certificate.\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d -n \"vpnclient-to-revoke\"\n   ```\n\n   ```\n   Certificate:\n       Data:\n           Version: 3 (0x2)\n           Serial Number:\n               00:cd:69:ff:74\n   ... ...\n   ```\n\n   From the output, we see that the serial number is `CD69FF74` in hexadecimal, which is `3446275956` in decimal. It will be used in the next steps.\n\n1. Create a new Certificate Revocation List (CRL). You only need to do this once for each CA.\n\n   ```bash\n   if ! crlutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" 2>/dev/null; then\n     crlutil -G -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -c /dev/null\n   fi\n   ```\n\n   ```\n   CRL Info:\n   :\n       Version: 2 (0x1)\n       Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption\n       Issuer: \"O=IKEv2 VPN,CN=IKEv2 VPN CA\"\n       This Update: Sat Jun 06 22:00:00 2020\n       CRL Extensions:\n   ```\n\n1. Add the client certificate you want to revoke to the CRL. Here we specify the certificate's serial number in decimal, and the revocation time in GeneralizedTime format (YYYYMMDDhhmmssZ) in UTC.\n\n   ```bash\n   crlutil -M -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" <<EOF\n   addcert 3446275956 20200606220100Z\n   EOF\n   ```\n\n   ```\n   CRL Info:\n   :\n       Version: 2 (0x1)\n       Signature Algorithm: PKCS #1 SHA-256 With RSA Encryption\n       Issuer: \"O=IKEv2 VPN,CN=IKEv2 VPN CA\"\n       This Update: Sat Jun 06 22:02:00 2020\n       Entry 1 (0x1):\n           Serial Number:\n               00:cd:69:ff:74\n           Revocation Date: Sat Jun 06 22:01:00 2020\n       CRL Extensions:\n   ```\n\n   **Note:** If you want to remove a certificate from the CRL, replace `addcert 3446275956 20200606220100Z` above with `rmcert 3446275956`. For other `crlutil` usage, read [here](https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_crlutil/index.html).\n\n1. Finally, let Libreswan re-read the updated CRL.\n\n   ```bash\n   ipsec crls\n   ```\n</details>\n\n## Change IKEv2 server address\n\nIn certain circumstances, you may need to change the IKEv2 server address after setup. For example, to switch to use a DNS name, or after server IP changes. Note that the server address you specify on VPN client devices must **exactly match** the server address in the output of the IKEv2 helper script. Otherwise, devices may be unable to connect.\n\nTo change the server address, run the [helper script](../extras/ikev2changeaddr.sh) and follow the prompts.\n\n```bash\nwget https://get.vpnsetup.net/ikev2addr -O ikev2addr.sh\nsudo bash ikev2addr.sh\n```\n\n**Important:** After running this script, you must manually update the server address (and remote ID, if applicable) on any existing IKEv2 client devices. For iOS clients, you'll need to run `sudo ikev2.sh` to export the updated client config file and import it to the iOS device.\n\n## Update IKEv2 helper script\n\nThe IKEv2 helper script is updated from time to time for bug fixes and improvements ([commit log](https://github.com/hwdsl2/setup-ipsec-vpn/commits/master/extras/ikev2setup.sh)). When a newer version is available, you may optionally update the IKEv2 helper script on your server. Note that these commands will overwrite any existing `ikev2.sh`.\n\n```bash\nwget https://get.vpnsetup.net/ikev2 -O /opt/src/ikev2.sh\nchmod +x /opt/src/ikev2.sh && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n```\n\n## Set up IKEv2 using helper script\n\n**Note:** By default, IKEv2 is automatically set up when running the VPN setup script. You may skip this section and continue to [configure IKEv2 VPN clients](#configure-ikev2-vpn-clients).\n\n**Important:** Before continuing, you should have successfully [set up your own VPN server](https://github.com/hwdsl2/setup-ipsec-vpn). Docker users, see [Configure and use IKEv2 VPN](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md#configure-and-use-ikev2-vpn).\n\nUse this [helper script](../extras/ikev2setup.sh) to automatically set up IKEv2 on the VPN server:\n\n```bash\n# Set up IKEv2 using default options\nsudo ikev2.sh --auto\n# Alternatively, you may customize IKEv2 options\nsudo ikev2.sh\n```\n\n**Note:** If IKEv2 is already set up, but you want to customize IKEv2 options, first [remove IKEv2](#remove-ikev2), then set it up again using `sudo ikev2.sh`.\n\nWhen finished, continue to [configure IKEv2 VPN clients](#configure-ikev2-vpn-clients). Advanced users can optionally enable [IKEv2-only mode](advanced-usage.md#ikev2-only-vpn).\n\n<details>\n<summary>\nError: \"sudo: ikev2.sh: command not found\".\n</summary>\n\nThis is normal if you used an older version of the VPN setup script. First, download the IKEv2 helper script:\n\n```bash\nwget https://get.vpnsetup.net/ikev2 -O /opt/src/ikev2.sh\nchmod +x /opt/src/ikev2.sh && ln -s /opt/src/ikev2.sh /usr/bin\n```\n\nThen run the script using the instructions above.\n</details>\n<details>\n<summary>\nYou may optionally specify a DNS name, client name and/or custom DNS servers.\n</summary>\n\nWhen running IKEv2 setup in auto mode, advanced users can optionally specify a DNS name for the IKEv2 server address. The DNS name must be a fully qualified domain name (FQDN). Example:\n\n```bash\nsudo VPN_DNS_NAME='vpn.example.com' ikev2.sh --auto\n```\n\nSimilarly, you may specify a name for the first IKEv2 client. The default is `vpnclient` if not specified.\n\n```bash\nsudo VPN_CLIENT_NAME='your_client_name' ikev2.sh --auto\n```\n\nBy default, IKEv2 clients are set to use [Google Public DNS](https://developers.google.com/speed/public-dns/) when the VPN is active. You may specify custom DNS server(s) for IKEv2. Example:\n\n```bash\nsudo VPN_DNS_SRV1=1.1.1.1 VPN_DNS_SRV2=1.0.0.1 ikev2.sh --auto\n```\n\nBy default, no password is required when importing IKEv2 client configuration. You can choose to protect client config files using a random password.\n\n```bash\nsudo VPN_PROTECT_CONFIG=yes ikev2.sh --auto\n```\n</details>\n<details>\n<summary>\nView usage information for the IKEv2 script.\n</summary>\n\n```\nUsage: bash ikev2.sh [options]\n\nOptions:\n  --auto                        run IKEv2 setup in auto mode using default options (for initial setup only)\n  --addclient [client name]     add a new client using default options\n  --exportclient [client name]  export configuration for an existing client\n  --listclients                 list the names of existing clients\n  --revokeclient [client name]  revoke an existing client\n  --deleteclient [client name]  delete an existing client\n  --removeikev2                 remove IKEv2 and delete all certificates and keys from the IPsec database\n  -y, --yes                     assume \"yes\" as answer to prompts when revoking/deleting a client or removing IKEv2\n  -h, --help                    show this help message and exit\n\nTo customize IKEv2 or client options, run this script without arguments.\n```\n</details>\n\n## Manually set up IKEv2\n\nAs an alternative to using the [helper script](#set-up-ikev2-using-helper-script), advanced users can manually set up IKEv2 on the VPN server. Before continuing, it is recommended to [update Libreswan](../README.md#upgrade-libreswan) to the latest version.\n\nThe following example shows how to manually configure IKEv2 with Libreswan. Commands below must be run as `root`.\n\n<details>\n<summary>\nView example steps for manually configuring IKEv2 with Libreswan.\n</summary>\n\n1. Find the VPN server's public IP, save it to a variable and check.\n\n   ```bash\n   PUBLIC_IP=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n   [ -z \"$PUBLIC_IP\" ] && PUBLIC_IP=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n   printf '%s\\n' \"$PUBLIC_IP\"\n   ```\n\n   Check to make sure the output matches the server's public IP. This variable is required in the steps below.\n\n   **Note:** Alternatively, you may specify the server's DNS name here. e.g. `PUBLIC_IP=myvpn.example.com`.\n\n1. Add a new IKEv2 connection:\n\n   ```bash\n   if ! grep -qs '^include /etc/ipsec\\.d/\\*\\.conf$' /etc/ipsec.conf; then\n     echo >> /etc/ipsec.conf\n     echo 'include /etc/ipsec.d/*.conf' >> /etc/ipsec.conf\n   fi\n   ```\n\n   **Note:** If you specified the server's DNS name (instead of its IP address) in step 1 above, you must replace `leftid=$PUBLIC_IP` in the command below with `leftid=@$PUBLIC_IP`.\n\n   ```bash\n   cat > /etc/ipsec.d/ikev2.conf <<EOF\n\n   conn ikev2-cp\n     left=%defaultroute\n     leftcert=$PUBLIC_IP\n     leftid=$PUBLIC_IP\n     leftsendcert=always\n     leftsubnet=0.0.0.0/0\n     leftrsasigkey=%cert\n     right=%any\n     rightid=%fromcert\n     rightaddresspool=192.168.43.10-192.168.43.250\n     rightca=%same\n     rightrsasigkey=%cert\n     narrowing=yes\n     dpddelay=30\n     retransmit-timeout=300s\n     auto=add\n     ikev2=insist\n     rekey=no\n     pfs=no\n     ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n     phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2\n     ikelifetime=24h\n     salifetime=24h\n   EOF\n   ```\n\n   We need to add a few more lines to that file. First check your Libreswan version, then run one of the following commands:\n\n   ```bash\n   ipsec --version\n   ```\n\n   For Libreswan 3.23 and newer:\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns=\"8.8.8.8 8.8.4.4\"\n     encapsulation=yes\n     mobike=no\n   EOF\n   ```\n\n   **Note:** The MOBIKE IKEv2 extension allows VPN clients to change network attachment points, e.g. switch between mobile data and Wi-Fi and keep the IPsec tunnel up on the new IP. If your server (or Docker host) is **NOT** running Ubuntu Linux, and you wish to enable MOBIKE support, replace `mobike=no` with `mobike=yes` in the command above. **DO NOT** enable this option on Ubuntu systems or Raspberry Pis.\n\n   For Libreswan 3.19-3.22:\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns1=8.8.8.8\n     modecfgdns2=8.8.4.4\n     encapsulation=yes\n   EOF\n   ```\n\n   For Libreswan 3.18 and older:\n\n   ```bash\n   cat >> /etc/ipsec.d/ikev2.conf <<EOF\n     modecfgdns1=8.8.8.8\n     modecfgdns2=8.8.4.4\n     forceencaps=yes\n   EOF\n   ```\n\n1. Generate Certificate Authority (CA) and VPN server certificates.\n\n   **Note:** Specify the certificate validity period (in months) with \"-v\". e.g. \"-v 120\".\n\n   Generate CA certificate:\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -x -n \"IKEv2 VPN CA\" \\\n     -s \"O=IKEv2 VPN,CN=IKEv2 VPN CA\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \"CT,,\" -2\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n\n   Is this a CA certificate [y/N]?\n   y\n   Enter the path length constraint, enter to skip [<0 for unlimited path]: >\n   Is this a critical extension [y/N]?\n   N\n   ```\n\n   Generate VPN server certificate:\n\n   **Note:** If you specified the server's DNS name (instead of its IP address) in step 1 above, you must replace `--extSAN \"ip:$PUBLIC_IP,dns:$PUBLIC_IP\"` in the command below with `--extSAN \"dns:$PUBLIC_IP\"`.\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -c \"IKEv2 VPN CA\" -n \"$PUBLIC_IP\" \\\n     -s \"O=IKEv2 VPN,CN=$PUBLIC_IP\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \",,\" \\\n     --keyUsage digitalSignature,keyEncipherment \\\n     --extKeyUsage serverAuth \\\n     --extSAN \"ip:$PUBLIC_IP,dns:$PUBLIC_IP\"\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n   ```\n\n1. Generate client certificate(s), then export the `.p12` file that contains the client certificate, private key, and CA certificate.\n\n   **Note:** You may repeat this step to generate certificates for additional VPN clients, but make sure to replace every `vpnclient` with `vpnclient2`, etc. To connect multiple IKEv2 clients from behind the same NAT (e.g. home router) at the same time, you will need to generate a unique certificate for each client.\n\n   Generate client certificate:\n\n   ```bash\n   certutil -z <(head -c 1024 /dev/urandom) \\\n     -S -c \"IKEv2 VPN CA\" -n \"vpnclient\" \\\n     -s \"O=IKEv2 VPN,CN=vpnclient\" \\\n     -k rsa -g 3072 -v 120 \\\n     -d sql:/etc/ipsec.d -t \",,\" \\\n     --keyUsage digitalSignature,keyEncipherment \\\n     --extKeyUsage serverAuth,clientAuth -8 \"vpnclient\"\n   ```\n\n   ```\n   Generating key.  This may take a few moments...\n   ```\n\n   Export `.p12` file:\n\n   ```bash\n   pk12util -d sql:/etc/ipsec.d -n \"vpnclient\" -o vpnclient.p12\n   ```\n\n   ```\n   Enter password for PKCS12 file:\n   Re-enter password:\n   pk12util: PKCS12 EXPORT SUCCESSFUL\n   ```\n\n   Enter a secure password to protect the exported `.p12` file (when importing into an iOS or macOS device, this password cannot be empty).\n\n1. (For iOS clients) Export the CA certificate as `ca.cer`:\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" -a -o ca.cer\n   ```\n\n1. The database should now contain:\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n   **Note:** To display a certificate, use `certutil -L -d sql:/etc/ipsec.d -n \"Nickname\"`. To revoke a client certificate, follow [these steps](#revoke-a-client-certificate). For other `certutil` usage, read [here](https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_certutil/index.html).\n\n1. **(Important) Restart the IPsec service**:\n\n   ```bash\n   service ipsec restart\n   ```\n\nBefore continuing, you **must** restart the IPsec service. The IKEv2 setup on the VPN server is now complete. Follow instructions to [configure VPN clients](#configure-ikev2-vpn-clients).\n</details>\n\n## Remove IKEv2\n\nIf you want to remove IKEv2 from the VPN server, but keep the [IPsec/L2TP](clients.md) and [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth.md) modes (if installed), run the helper script. **Warning:** All IKEv2 configuration including certificates and keys will be **permanently deleted**. This **cannot be undone**!\n\n```bash\nsudo ikev2.sh --removeikev2\n```\n\nAfter removing IKEv2, if you want to set it up again, refer to [this section](#set-up-ikev2-using-helper-script).\n\n<details>\n<summary>\nAlternatively, you can manually remove IKEv2.\n</summary>\n\nTo manually remove IKEv2 from the VPN server, but keep the [IPsec/L2TP](clients.md) and [IPsec/XAuth (\"Cisco IPsec\")](clients-xauth.md) modes, follow these steps. Commands must be run as `root`.\n\n**Warning:** All IKEv2 configuration including certificates and keys will be **permanently deleted**. This **cannot be undone**!\n\n1. Rename (or delete) the IKEv2 config file:\n\n   ```bash\n   mv /etc/ipsec.d/ikev2.conf /etc/ipsec.d/ikev2.conf.bak\n   ```\n\n   **Note:** If you used an older version (before 2020-05-31) of the IKEv2 helper script or instructions, file `/etc/ipsec.d/ikev2.conf` may not exist. In this case, please instead remove the `conn ikev2-cp` section from file `/etc/ipsec.conf`.\n\n1. **(Important) Restart the IPsec service**:\n\n   ```bash\n   service ipsec restart\n   ```\n\n1. List certificates in the IPsec database:\n\n   ```bash\n   certutil -L -d sql:/etc/ipsec.d\n   ```\n\n   Example output:\n\n   ```\n   Certificate Nickname                               Trust Attributes\n                                                      SSL,S/MIME,JAR/XPI\n\n   IKEv2 VPN CA                                       CTu,u,u\n   ($PUBLIC_IP)                                       u,u,u\n   vpnclient                                          u,u,u\n   ```\n\n1. Delete the Certificate Revocation List (CRL), if any:\n\n   ```bash\n   crlutil -D -d sql:/etc/ipsec.d -n \"IKEv2 VPN CA\" 2>/dev/null\n   ```\n\n1. Delete certificates and keys. Replace \"Nickname\" below with each certificate's nickname. Repeat these commands for each certificate. When finished, list certificates in the IPsec database again, and confirm that the list is empty.\n\n   ```bash\n   certutil -F -d sql:/etc/ipsec.d -n \"Nickname\"\n   certutil -D -d sql:/etc/ipsec.d -n \"Nickname\" 2>/dev/null\n   ```\n</details>\n\n## References\n\n* https://libreswan.org/wiki/VPN_server_for_remote_clients_using_IKEv2\n* https://libreswan.org/wiki/HOWTO:_Using_NSS_with_libreswan\n* https://libreswan.org/man/ipsec.conf.5.html\n* https://docs.strongswan.org/docs/5.9/interop/windowsClients.html\n* https://docs.strongswan.org/docs/5.9/os/androidVpnClient.html\n* https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_certutil/index.html\n* https://firefox-source-docs.mozilla.org/security/nss/legacy/tools/nss_tools_crlutil/index.html\n\n## License\n\nCopyright (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nThis work is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nAttribution required: please include my name in any derivative and let me know how you have improved it!\n"
  },
  {
    "path": "docs/manage-users-zh.md",
    "content": "[English](manage-users.md) | [中文](manage-users-zh.md)\n\n# 管理 VPN 用户\n\n在默认情况下，将只创建一个用于 VPN 登录的用户账户。如果你需要查看或管理 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式的用户，请阅读本文档。对于 IKEv2，参见[管理 IKEv2 客户端](ikev2-howto-zh.md#管理-ikev2-客户端)。\n\n* [使用辅助脚本管理 VPN 用户](#使用辅助脚本管理-vpn-用户)\n* [查看 VPN 用户](#查看-vpn-用户)\n* [查看或更改 IPsec PSK](#查看或更改-ipsec-psk)\n* [手动管理 VPN 用户](#手动管理-vpn-用户)\n\n## 使用辅助脚本管理 VPN 用户\n\n你可以使用辅助脚本添加，删除或者更新 VPN 用户。它们将同时更新 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式的用户。对于 IKEv2，参见[管理 IKEv2 客户端](ikev2-howto-zh.md#管理-ikev2-客户端)。\n\n**注：** 将下面的命令的参数换成你自己的值。VPN 用户信息保存在文件 `/etc/ppp/chap-secrets` 和 `/etc/ipsec.d/passwd`。脚本在修改这些文件之前会先做备份，使用 `.old-日期-时间` 为后缀。\n\n### 添加或更改一个 VPN 用户\n\n添加一个新 VPN 用户，或者为一个已有的 VPN 用户更改密码。\n\n运行[辅助脚本](../extras/add_vpn_user.sh)并按提示操作：\n\n```bash\nsudo addvpnuser.sh\n```\n\n<details>\n<summary>\n错误：\"sudo: addvpnuser.sh: command not found\".\n</summary>\n\n如果你使用了较早版本的 VPN 安装脚本，这是正常的。首先下载辅助脚本：\n\n```bash\nwget https://get.vpnsetup.net/adduser -O /opt/src/addvpnuser.sh\nchmod +x /opt/src/addvpnuser.sh && ln -s /opt/src/addvpnuser.sh /usr/bin\n```\n\n然后按照说明运行脚本。\n</details>\n\n另外，你也可以在添加参数的情况下运行脚本：\n\n```bash\n# 所有变量值必须用 '单引号' 括起来\n# *不要* 在值中使用这些字符：  \\ \" '\nsudo addvpnuser.sh '要添加的用户名' '密码'\n# 或者\nsudo addvpnuser.sh '要更新的用户名' '新密码'\n```\n\n### 删除一个 VPN 用户\n\n删除指定的 VPN 用户。\n\n运行[辅助脚本](../extras/del_vpn_user.sh)并按提示操作：\n\n```bash\nsudo delvpnuser.sh\n```\n\n<details>\n<summary>\n错误：\"sudo: delvpnuser.sh: command not found\".\n</summary>\n\n如果你使用了较早版本的 VPN 安装脚本，这是正常的。首先下载辅助脚本：\n\n```bash\nwget https://get.vpnsetup.net/deluser -O /opt/src/delvpnuser.sh\nchmod +x /opt/src/delvpnuser.sh && ln -s /opt/src/delvpnuser.sh /usr/bin\n```\n\n然后按照说明运行脚本。\n</details>\n\n另外，你也可以在添加参数的情况下运行脚本：\n\n```bash\n# 所有变量值必须用 '单引号' 括起来\n# *不要* 在值中使用这些字符：  \\ \" '\nsudo delvpnuser.sh '要删除的用户名'\n```\n\n### 更新所有的 VPN 用户\n\n移除 **所有的 VPN 用户** 并替换为你指定的列表中的用户。\n\n首先下载[辅助脚本](../extras/update_vpn_users.sh)：\n\n```bash\nwget https://get.vpnsetup.net/updateusers -O updateusers.sh\n```\n\n**重要：** 这个脚本会将你当前 **所有的 VPN 用户** 移除并替换为你指定的列表中的用户。如果你需要保留已有的 VPN 用户，则必须将它们包含在下面的变量中。\n\n要使用这个脚本，从以下选项中选择一个：\n\n**选项 1:** 编辑脚本并输入 VPN 用户信息：\n\n```bash\nnano -w updateusers.sh\n[替换为你自己的值： YOUR_USERNAMES 和 YOUR_PASSWORDS]\nsudo bash updateusers.sh\n```\n\n**选项 2:** 将 VPN 用户信息定义为环境变量：\n\n```bash\n# VPN用户名和密码列表，用空格分隔\n# 所有变量值必须用 '单引号' 括起来\n# *不要* 在值中使用这些字符：  \\ \" '\nsudo \\\nVPN_USERS='用户名1 用户名2 ...' \\\nVPN_PASSWORDS='密码1 密码2 ...' \\\nbash updateusers.sh\n```\n\n## 查看 VPN 用户\n\n在默认情况下，VPN 安装脚本将为 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式创建相同的用户。\n\n对于 IPsec/L2TP，VPN 用户信息保存在文件 `/etc/ppp/chap-secrets`。该文件的格式如下：\n\n```bash\n\"用户名1\"  l2tpd  \"密码1\"  *\n\"用户名2\"  l2tpd  \"密码2\"  *\n... ...\n```\n\n对于 IPsec/XAuth (\"Cisco IPsec\")，VPN 用户信息保存在文件 `/etc/ipsec.d/passwd`。这个文件中的密码以加盐哈希值的形式保存。更多详情请见[手动管理 VPN 用户](#手动管理-vpn-用户)。\n\n## 查看或更改 IPsec PSK\n\nIPsec PSK（预共享密钥）保存在文件 `/etc/ipsec.secrets`。所有的 VPN 用户将共享同一个 IPsec PSK。该文件的格式如下：\n\n```bash\n%any  %any  : PSK \"你的IPsec预共享密钥\"\n```\n\n如果要更换一个新的 PSK，可以编辑此文件。**不要**在值中使用这些字符：`\\ \" '`\n\n完成后必须重启服务：\n\n```bash\nservice ipsec restart\nservice xl2tpd restart\n```\n\n## 手动管理 VPN 用户\n\n对于 IPsec/L2TP，VPN 用户信息保存在文件 `/etc/ppp/chap-secrets`。该文件的格式如下：\n\n```bash\n\"用户名1\"  l2tpd  \"密码1\"  *\n\"用户名2\"  l2tpd  \"密码2\"  *\n... ...\n```\n\n你可以添加更多用户，每个用户对应文件中的一行。**不要**在值中使用这些字符：`\\ \" '`\n\n对于 IPsec/XAuth (\"Cisco IPsec\")，VPN 用户信息保存在文件 `/etc/ipsec.d/passwd`。该文件的格式如下：\n\n```bash\n用户名1:密码1的加盐哈希值:xauth-psk\n用户名2:密码2的加盐哈希值:xauth-psk\n... ...\n```\n\n这个文件中的密码以加盐哈希值的形式保存。该步骤可以借助比如 `openssl` 工具来完成：\n\n```bash\n# 以下命令的输出为：密码1的加盐哈希值\n# 将你的密码用 '单引号' 括起来\nopenssl passwd -1 '密码1'\n```\n\n## 授权协议\n\n版权所有 (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n这个项目是以[知识共享署名-相同方式共享3.0](http://creativecommons.org/licenses/by-sa/3.0/) 许可协议授权。   \n必须署名： 请包括我的名字在任何衍生产品，并且让我知道你是如何改善它的！\n"
  },
  {
    "path": "docs/manage-users.md",
    "content": "[English](manage-users.md) | [中文](manage-users-zh.md)\n\n# Manage VPN Users\n\nBy default, a single user account for VPN login is created. If you wish to view or manage users for the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes, read this document. For IKEv2, see [Manage IKEv2 clients](ikev2-howto.md#manage-ikev2-clients).\n\n* [Manage VPN users using helper scripts](#manage-vpn-users-using-helper-scripts)\n* [View VPN users](#view-vpn-users)\n* [View or update the IPsec PSK](#view-or-update-the-ipsec-psk)\n* [Manually manage VPN users](#manually-manage-vpn-users)\n\n## Manage VPN users using helper scripts\n\nYou may use helper scripts to add, delete or update VPN users for both IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes. For IKEv2, see [Manage IKEv2 clients](ikev2-howto.md#manage-ikev2-clients).\n\n**Note:** Replace command arguments below with your own values. VPN users are stored in `/etc/ppp/chap-secrets` and `/etc/ipsec.d/passwd`. The scripts will backup these files before making changes, with `.old-date-time` suffix.\n\n### Add or edit a VPN user\n\nAdd a new VPN user, or update an existing VPN user with a new password.\n\nRun the [helper script](../extras/add_vpn_user.sh) and follow the prompts:\n\n```bash\nsudo addvpnuser.sh\n```\n\n<details>\n<summary>\nError: \"sudo: addvpnuser.sh: command not found\".\n</summary>\n\nThis is normal if you used an older version of the VPN setup script. First, download the helper script:\n\n```bash\nwget https://get.vpnsetup.net/adduser -O /opt/src/addvpnuser.sh\nchmod +x /opt/src/addvpnuser.sh && ln -s /opt/src/addvpnuser.sh /usr/bin\n```\n\nThen run the script using the instructions.\n</details>\n\nAlternatively, you can run the script with arguments:\n\n```bash\n# All values MUST be placed inside 'single quotes'\n# DO NOT use these special characters within values: \\ \" '\nsudo addvpnuser.sh 'username_to_add' 'password'\n# OR\nsudo addvpnuser.sh 'username_to_update' 'new_password'\n```\n\n### Delete a VPN user\n\nDelete the specified VPN user.\n\nRun the [helper script](../extras/del_vpn_user.sh) and follow the prompts:\n\n```bash\nsudo delvpnuser.sh\n```\n\n<details>\n<summary>\nError: \"sudo: delvpnuser.sh: command not found\".\n</summary>\n\nThis is normal if you used an older version of the VPN setup script. First, download the helper script:\n\n```bash\nwget https://get.vpnsetup.net/deluser -O /opt/src/delvpnuser.sh\nchmod +x /opt/src/delvpnuser.sh && ln -s /opt/src/delvpnuser.sh /usr/bin\n```\n\nThen run the script using the instructions.\n</details>\n\nAlternatively, you can run the script with arguments:\n\n```bash\n# All values MUST be placed inside 'single quotes'\n# DO NOT use these special characters within values: \\ \" '\nsudo delvpnuser.sh 'username_to_delete'\n```\n\n### Update all VPN users\n\nRemove **all existing VPN users** and replace with the list of users you specify.\n\nFirst, download the [helper script](../extras/update_vpn_users.sh):\n\n```bash\nwget https://get.vpnsetup.net/updateusers -O updateusers.sh\n```\n\n**Important:** This script will remove **all existing VPN users** and replace with the list of users you specify. Therefore, you must include any existing user(s) you want to keep in the variables below.\n\nTo use this script, choose one of the following options:\n\n**Option 1:** Edit the script and enter VPN user details:\n\n```bash\nnano -w updateusers.sh\n[Replace with your own values: YOUR_USERNAMES and YOUR_PASSWORDS]\nsudo bash updateusers.sh\n```\n\n**Option 2:** Define VPN user details as environment variables:\n\n```bash\n# List of VPN usernames and passwords, separated by spaces\n# All values MUST be placed inside 'single quotes'\n# DO NOT use these special characters within values: \\ \" '\nsudo \\\nVPN_USERS='username1 username2 ...' \\\nVPN_PASSWORDS='password1 password2 ...' \\\nbash updateusers.sh\n```\n\n## View VPN users\n\nBy default, the VPN setup scripts will create the same VPN user for both IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nFor IPsec/L2TP, VPN users are specified in `/etc/ppp/chap-secrets`. The format of this file is:\n\n```bash\n\"username1\"  l2tpd  \"password1\"  *\n\"username2\"  l2tpd  \"password2\"  *\n... ...\n```\n\nFor IPsec/XAuth (\"Cisco IPsec\"), VPN users are specified in `/etc/ipsec.d/passwd`. Passwords in this file are salted and hashed. See [Manually manage VPN users](#manually-manage-vpn-users) for more details.\n\n## View or update the IPsec PSK\n\nThe IPsec PSK (pre-shared key) is stored in `/etc/ipsec.secrets`. All VPN users will share the same IPsec PSK. The format of this file is:\n\n```bash\n%any  %any  : PSK \"your_ipsec_pre_shared_key\"\n```\n\nTo change to a new PSK, just edit this file. DO NOT use these special characters within values: `\\ \" '`\n\nYou must restart services when finished:\n\n```bash\nservice ipsec restart\nservice xl2tpd restart\n```\n\n## Manually manage VPN users\n\nFor IPsec/L2TP, VPN users are specified in `/etc/ppp/chap-secrets`. The format of this file is:\n\n```bash\n\"username1\"  l2tpd  \"password1\"  *\n\"username2\"  l2tpd  \"password2\"  *\n... ...\n```\n\nYou can add more users, use one line for each user. DO NOT use these special characters within values: `\\ \" '`\n\nFor IPsec/XAuth (\"Cisco IPsec\"), VPN users are specified in `/etc/ipsec.d/passwd`. The format of this file is:\n\n```bash\nusername1:password1hashed:xauth-psk\nusername2:password2hashed:xauth-psk\n... ...\n```\n\nPasswords in this file are salted and hashed. This step can be done using e.g. the `openssl` utility:\n\n```bash\n# The output will be password1hashed\n# Put your password inside 'single quotes'\nopenssl passwd -1 'password1'\n```\n\n## License\n\nCopyright (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nThis work is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nAttribution required: please include my name in any derivative and let me know how you have improved it!\n"
  },
  {
    "path": "docs/uninstall-zh.md",
    "content": "[English](uninstall.md) | [中文](uninstall-zh.md)\n\n# 卸载 VPN\n\n* [使用辅助脚本卸载 VPN](#使用辅助脚本卸载-vpn)\n* [手动卸载 VPN](#手动卸载-vpn)\n\n## 使用辅助脚本卸载 VPN\n\n要卸载 IPsec VPN，运行[辅助脚本](../extras/vpnuninstall.sh)：\n\n**警告：** 此辅助脚本将从你的服务器中删除 IPsec VPN。所有的 VPN 配置将被**永久删除**，并且 Libreswan 和 xl2tpd 将被移除。此操作**不可撤销**！\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\n如果无法下载，请点这里。\n</summary>\n\n你也可以使用 `curl` 下载：\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\n或者，你也可以使用这些链接：\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\n## 手动卸载 VPN\n\n另外，你也可以手动卸载 IPsec VPN。按照以下步骤操作。这些命令需要用 `root` 账户运行，或者使用 `sudo`。\n\n**警告：** 以下步骤将从你的服务器中删除 IPsec VPN。所有的 VPN 配置将被**永久删除**，并且 Libreswan 和 xl2tpd 将被移除。此操作**不可撤销**！\n\n### 步骤\n\n* [第一步](#第一步)\n* [第二步](#第二步)\n* [第三步](#第三步)\n* [第四步](#第四步)\n* [可选步骤](#可选步骤)\n* [完成后](#完成后)\n\n### 第一步\n\n```bash\nservice ipsec stop\nservice xl2tpd stop\nrm -rf /usr/local/sbin/ipsec /usr/local/libexec/ipsec /usr/local/share/doc/libreswan\nrm -f /etc/init/ipsec.conf /lib/systemd/system/ipsec.service /etc/init.d/ipsec \\\n      /usr/lib/systemd/system/ipsec.service /etc/logrotate.d/libreswan \\\n      /usr/lib/tmpfiles.d/libreswan.conf\n```\n\n### 第二步\n\n#### Ubuntu & Debian\n\n`apt-get purge xl2tpd`\n\n#### CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\n\n`yum remove xl2tpd`\n\n#### Alpine Linux\n\n`apk del xl2tpd`\n\n### 第三步\n\n#### Ubuntu, Debian & Alpine Linux\n\n编辑 `/etc/iptables.rules` 并删除不需要的规则。你之前的防火墙规则（如果有）备份在 `/etc/iptables.rules.old-日期-时间`。另外如果文件 `/etc/iptables/rules.v4` 存在，请编辑它。\n\n如果启用了 IPv6 支持，请也编辑 `/etc/ip6tables.rules` 以及 `/etc/iptables/rules.v6`（如果存在）并删除不需要的规则。\n\n#### CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\n\n编辑 `/etc/sysconfig/iptables` 并删除不需要的规则。你之前的防火墙规则（如果有）备份在 `/etc/sysconfig/iptables.old-日期-时间`。\n\n如果启用了 IPv6 支持，请也编辑 `/etc/sysconfig/ip6tables` 并删除不需要的规则。\n\n**注：** 如果使用 Rocky Linux, AlmaLinux, Oracle Linux 8 或者 CentOS/RHEL 8 并且在安装 VPN 时 firewalld 正在运行，则可能已配置 nftables。编辑 `/etc/sysconfig/nftables.conf` 并删除不需要的规则。你之前的防火墙规则备份在 `/etc/sysconfig/nftables.conf.old-日期-时间`。\n\n### 第四步\n\n编辑 `/etc/sysctl.conf` 并删除该标记后面的行： `# Added by hwdsl2 VPN script`。   \n编辑 `/etc/rc.local` 并删除该标记后面的行： `# Added by hwdsl2 VPN script`。\\*不要\\* 删除 `exit 0` （如果有）。\n\n### 可选步骤\n\n**注：** 这一步是可选的。\n\n删除这些配置文件：\n\n* /etc/ipsec.conf*\n* /etc/ipsec.secrets*\n* /etc/ppp/chap-secrets*\n* /etc/ppp/options.xl2tpd*\n* /etc/pam.d/pluto\n* /etc/sysconfig/pluto\n* /etc/default/pluto\n* /etc/ipsec.d (目录)\n* /etc/xl2tpd (目录)\n\n要快速删除，可以复制并粘贴以下命令：\n\n```bash\nrm -f /etc/ipsec.conf* /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ppp/options.xl2tpd* \\\n      /etc/pam.d/pluto /etc/sysconfig/pluto /etc/default/pluto\nrm -rf /etc/ipsec.d /etc/xl2tpd\n```\n\n删除辅助脚本：\n\n```bash\nrm -f /usr/bin/ikev2.sh /opt/src/ikev2.sh \\\n      /usr/bin/addvpnuser.sh /opt/src/addvpnuser.sh \\\n      /usr/bin/delvpnuser.sh /opt/src/delvpnuser.sh\n```\n\n删除 fail2ban：\n\n**注：** 这是可选的。Fail2ban 可以帮助保护你的服务器上的 SSH。\\*不推荐\\*删除它。\n\n```bash\nservice fail2ban stop\n# Ubuntu & Debian\napt-get purge fail2ban\n# CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\nyum remove fail2ban\n# Alpine Linux\napk del fail2ban\n```\n\n### 完成后\n\n重启你的服务器。\n\n## 授权协议\n\n版权所有 (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \n这个项目是以[知识共享署名-相同方式共享3.0](http://creativecommons.org/licenses/by-sa/3.0/) 许可协议授权。   \n必须署名： 请包括我的名字在任何衍生产品，并且让我知道你是如何改善它的！\n"
  },
  {
    "path": "docs/uninstall.md",
    "content": "[English](uninstall.md) | [中文](uninstall-zh.md)\n\n# Uninstall the VPN\n\n* [Uninstall using helper script](#uninstall-using-helper-script)\n* [Manually uninstall the VPN](#manually-uninstall-the-vpn)\n\n## Uninstall using helper script\n\nTo uninstall IPsec VPN, run the [helper script](../extras/vpnuninstall.sh):\n\n**Warning:** This helper script will remove IPsec VPN from your server. All VPN configuration will be **permanently deleted**, and Libreswan and xl2tpd will be removed. This **cannot be undone**!\n\n```bash\nwget https://get.vpnsetup.net/unst -O unst.sh && sudo bash unst.sh\n```\n\n<details>\n<summary>\nClick here if you are unable to download.\n</summary>\n\nYou may also use `curl` to download:\n\n```bash\ncurl -fsSL https://get.vpnsetup.net/unst -o unst.sh && sudo bash unst.sh\n```\n\nAlternative script URLs:\n\n```bash\nhttps://github.com/hwdsl2/setup-ipsec-vpn/raw/master/extras/vpnuninstall.sh\nhttps://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras/vpnuninstall.sh\n```\n</details>\n\n## Manually uninstall the VPN\n\nAlternatively, you may manually uninstall IPsec VPN by following these steps. Commands must be run as `root`, or with `sudo`.\n\n**Warning:** These steps will remove IPsec VPN from your server. All VPN configuration will be **permanently deleted**, and Libreswan and xl2tpd will be removed. This **cannot be undone**!\n\n### Steps\n\n* [First step](#first-step)\n* [Second step](#second-step)\n* [Third step](#third-step)\n* [Fourth step](#fourth-step)\n* [Optional](#optional)\n* [When finished](#when-finished)\n\n### First step\n\n```bash\nservice ipsec stop\nservice xl2tpd stop\nrm -rf /usr/local/sbin/ipsec /usr/local/libexec/ipsec /usr/local/share/doc/libreswan\nrm -f /etc/init/ipsec.conf /lib/systemd/system/ipsec.service /etc/init.d/ipsec \\\n      /usr/lib/systemd/system/ipsec.service /etc/logrotate.d/libreswan \\\n      /usr/lib/tmpfiles.d/libreswan.conf\n```\n\n### Second step\n\n#### Ubuntu & Debian\n\n`apt-get purge xl2tpd`\n\n#### CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\n\n`yum remove xl2tpd`\n\n#### Alpine Linux\n\n`apk del xl2tpd`\n\n### Third step\n\n#### Ubuntu, Debian & Alpine Linux\n\nEdit `/etc/iptables.rules` and remove unneeded rules. Your original rules (if any) are backed up as `/etc/iptables.rules.old-date-time`. In addition, edit `/etc/iptables/rules.v4` if the file exists.\n\nIf IPv6 support was enabled, also edit `/etc/ip6tables.rules` and `/etc/iptables/rules.v6` (if it exists) and remove unneeded rules.\n\n#### CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\n\nEdit `/etc/sysconfig/iptables` and remove unneeded rules. Your original rules (if any) are backed up as `/etc/sysconfig/iptables.old-date-time`.\n\nIf IPv6 support was enabled, also edit `/etc/sysconfig/ip6tables` and remove unneeded rules.\n\n**Note:** If using Rocky Linux, AlmaLinux, Oracle Linux 8 or CentOS/RHEL 8 and firewalld was active during VPN setup, nftables may be configured. Edit `/etc/sysconfig/nftables.conf` and remove unneeded rules. Your original rules are backed up as `/etc/sysconfig/nftables.conf.old-date-time`.\n\n### Fourth step\n\nEdit `/etc/sysctl.conf` and remove the lines after `# Added by hwdsl2 VPN script`.   \nEdit `/etc/rc.local` and remove the lines after `# Added by hwdsl2 VPN script`. DO NOT remove `exit 0` (if any).\n\n### Optional\n\n**Note:** This step is optional.\n\nRemove these config files:\n\n* /etc/ipsec.conf*\n* /etc/ipsec.secrets*\n* /etc/ppp/chap-secrets*\n* /etc/ppp/options.xl2tpd*\n* /etc/pam.d/pluto\n* /etc/sysconfig/pluto\n* /etc/default/pluto\n* /etc/ipsec.d (directory)\n* /etc/xl2tpd (directory)\n\nCopy and paste for fast removal:\n\n```bash\nrm -f /etc/ipsec.conf* /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ppp/options.xl2tpd* \\\n      /etc/pam.d/pluto /etc/sysconfig/pluto /etc/default/pluto\nrm -rf /etc/ipsec.d /etc/xl2tpd\n```\n\nRemove helper scripts:\n\n```bash\nrm -f /usr/bin/ikev2.sh /opt/src/ikev2.sh \\\n      /usr/bin/addvpnuser.sh /opt/src/addvpnuser.sh \\\n      /usr/bin/delvpnuser.sh /opt/src/delvpnuser.sh\n```\n\nRemove fail2ban:\n\n**Note:** This is optional. Fail2ban can help protect SSH on your server. Removing it is NOT recommended.\n\n```bash\nservice fail2ban stop\n# Ubuntu & Debian\napt-get purge fail2ban\n# CentOS/RHEL, Rocky Linux, AlmaLinux, Oracle Linux & Amazon Linux 2\nyum remove fail2ban\n# Alpine Linux\napk del fail2ban\n```\n\n### When finished\n\nReboot your server.\n\n## License\n\nCopyright (C) 2016-2026 [Lin Song](https://github.com/hwdsl2) [![View my profile on LinkedIn](https://static.licdn.com/scds/common/u/img/webpromo/btn_viewmy_160x25.png)](https://www.linkedin.com/in/linsongui)   \n\n[![Creative Commons License](https://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)   \nThis work is licensed under the [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)  \nAttribution required: please include my name in any derivative and let me know how you have improved it!\n"
  },
  {
    "path": "docs/vpn-book-ja.md",
    "content": "[&laquo; トップページへ戻る](../README-ja.md) | [English](vpn-book.md) | [简体中文](vpn-book-zh.md) | [繁體中文](vpn-book-zh-Hant.md) | [日本語](vpn-book-ja.md)\n\n## 新刊：Privacy Tools in the Age of AI\n\nAI時代において、次世代レベルのプライバシー保護を構築する方法を学びましょう。この本は電子書籍、紙版、オーディオブックの各形式で入手できます：\n\n&raquo; [Amazon](https://books2read.com/privacy?store=amazon)   \n&raquo; [Google Play](https://books2read.com/privacy?store=google)   \n&raquo; [Apple Books](https://books2read.com/privacy?store=apple)   \n&raquo; [Hoopla](https://books2read.com/privacy?store=hoopla)   \n&raquo; [その他のプラットフォーム](https://books2read.com/privacy)\n\n他言語版：[Español](https://books2read.com/privacyes)、[Deutsch](https://books2read.com/privacyde)、[Français](https://books2read.com/privacyfr)、[Italiano](https://books2read.com/privacyit)。\n\n## VPNサーバーの構築方法: ステップバイステップガイド\n\nこの本は、IPsec VPN、OpenVPN、WireGuardサーバーを自前で構築するための**ステップバイステップガイド**です。この本は電子書籍とペーパーバックの形式で入手できます：\n\n&raquo; [Amazon](https://books2read.com/vpnguideja?store=amazon)   \n&raquo; [その他のプラットフォーム](https://books2read.com/vpnguideja)\n\n他言語版：[English](https://books2read.com/vpnguide)、[简体中文](https://books2read.com/vpnguidezh)、[繁體中文](https://books2read.com/vpnguidezht)、[Español](https://books2read.com/vpnguidees)、[Deutsch](https://books2read.com/vpnguidede)、[Français](https://books2read.com/vpnguidefr)、[Italiano](https://books2read.com/vpnguideit)、[Nederlands](https://books2read.com/vpnguidenl)、[Português](https://books2read.com/vpnguidept)。\n\n## VPNサーバー完全ガイド: クラウド上で自前のVPNを構築するには\n\nこの本は、IPsec VPN、OpenVPN、WireGuardサーバーを自前で構築するための**完全ガイド**です。この本は電子書籍とペーパーバックの形式で入手できます：\n\n&raquo; [Amazon](https://books2read.com/vpnja?store=amazon)   \n&raquo; [その他のプラットフォーム](https://books2read.com/vpnja)\n\n他言語版：[English](https://books2read.com/vpn)、[简体中文](https://books2read.com/vpnzh)、[繁體中文](https://books2read.com/vpnzht)、[Español](https://books2read.com/vpnes)、[Deutsch](https://books2read.com/vpnde)、[Français](https://books2read.com/vpnfr)、[Italiano](https://books2read.com/vpnit)。\n\n著者ページ：[amazon.com/author/linsong](https://amazon.com/author/linsong)\n"
  },
  {
    "path": "docs/vpn-book-zh-Hant.md",
    "content": "[&laquo; 返回首頁](../README-zh-Hant.md) | [English](vpn-book.md) | [简体中文](vpn-book-zh.md) | [繁體中文](vpn-book-zh-Hant.md) | [日本語](vpn-book-ja.md)\n\n## 新：Privacy Tools in the Age of AI\n\n了解如何在人工智慧時代建立更高等級的隱私保護。本書提供電子書、精裝本、平裝本與有聲書格式。\n\n&raquo; [Amazon](https://books2read.com/privacy?store=amazon)   \n&raquo; [Google Play](https://books2read.com/privacy?store=google)   \n&raquo; [Apple Books](https://books2read.com/privacy?store=apple)   \n&raquo; [Hoopla](https://books2read.com/privacy?store=hoopla)   \n&raquo; [其他平台](https://books2read.com/privacy)\n\n其他語言版本：[Español](https://books2read.com/privacyes)、[Deutsch](https://books2read.com/privacyde)、[Français](https://books2read.com/privacyfr)、[Italiano](https://books2read.com/privacyit)。\n\n## 架設自己的 VPN 伺服器：IPsec VPN、OpenVPN 與 WireGuard 實作指南\n\n本書是架設你自己的 IPsec VPN、OpenVPN 與 WireGuard 伺服器的**實作指南**。提供電子書與平裝本格式。\n\n&raquo; [Google Play](https://books2read.com/vpnguidezht?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpnguidezht?store=apple)   \n&raquo; [Amazon](https://books2read.com/vpnguidezht?store=amazon)   \n&raquo; [Amazon 平裝本](https://books2read.com/vpnguidezht?store=amazon-paperback&format=PAPERBACK)   \n&raquo; [其他平台](https://books2read.com/vpnguidezht)\n\n其他語言版本：[简体中文](https://books2read.com/vpnguidezh)、[English](https://books2read.com/vpnguide)、[Español](https://books2read.com/vpnguidees)、[Deutsch](https://books2read.com/vpnguidede)、[Français](https://books2read.com/vpnguidefr)、[Italiano](https://books2read.com/vpnguideit)、[Nederlands](https://books2read.com/vpnguidenl)、[Português](https://books2read.com/vpnguidept)、[日本語](https://books2read.com/vpnguideja)。\n\n## 架設自己的 VPN 伺服器：IPsec VPN、OpenVPN 與 WireGuard 完整指南\n\n本書是架設你自己的 IPsec VPN、OpenVPN 與 WireGuard 伺服器的**完整指南**。提供電子書與平裝本格式。\n\n&raquo; [Google Play](https://books2read.com/vpnzht?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpnzht?store=apple)   \n&raquo; [Amazon](https://books2read.com/vpnzht?store=amazon)   \n&raquo; [Amazon 平裝本](https://books2read.com/vpnzht?store=amazon-paperback&format=PAPERBACK)   \n&raquo; [其他平台](https://books2read.com/vpnzht)\n\n其他語言版本：[简体中文](https://books2read.com/vpnzh)、[English](https://books2read.com/vpn)、[Español](https://books2read.com/vpnes)、[Deutsch](https://books2read.com/vpnde)、[Français](https://books2read.com/vpnfr)、[Italiano](https://books2read.com/vpnit)、[日本語](https://books2read.com/vpnja)。\n\n作者頁面：[amazon.com/author/linsong](https://amazon.com/author/linsong)\n"
  },
  {
    "path": "docs/vpn-book-zh.md",
    "content": "[&laquo; 返回主页](../README-zh.md) | [English](vpn-book.md) | [简体中文](vpn-book-zh.md) | [繁體中文](vpn-book-zh-Hant.md) | [日本語](vpn-book-ja.md)\n\n## 新：Privacy Tools in the Age of AI\n\n了解如何在人工智能时代构建更高级别的隐私保护。本书提供电子书、精装本、平装本和有声读物格式。\n\n&raquo; [Amazon](https://books2read.com/privacy?store=amazon)   \n&raquo; [Google Play](https://books2read.com/privacy?store=google)   \n&raquo; [Apple Books](https://books2read.com/privacy?store=apple)   \n&raquo; [Hoopla](https://books2read.com/privacy?store=hoopla)   \n&raquo; [其他平台](https://books2read.com/privacy)\n\n其他语言版本：[Español](https://books2read.com/privacyes)、[Deutsch](https://books2read.com/privacyde)、[Français](https://books2read.com/privacyfr)、[Italiano](https://books2read.com/privacyit)。\n\n## 搭建自己的 VPN 服务器：IPsec VPN、OpenVPN 与 WireGuard 实战指南\n\n本书是搭建你自己的 IPsec VPN、OpenVPN 和 WireGuard 服务器的**实战指南**。提供电子书和平装本格式。\n\n&raquo; [Google Play](https://books2read.com/vpnguidezh?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpnguidezh?store=apple)   \n&raquo; [Amazon](https://books2read.com/vpnguidezh?store=amazon)   \n&raquo; [Amazon 平装本](https://books2read.com/vpnguidezh?store=amazon-paperback&format=PAPERBACK)   \n&raquo; [其他平台](https://books2read.com/vpnguidezh)\n\n其他语言版本：[繁體中文](https://books2read.com/vpnguidezht)、[English](https://books2read.com/vpnguide)、[Español](https://books2read.com/vpnguidees)、[Deutsch](https://books2read.com/vpnguidede)、[Français](https://books2read.com/vpnguidefr)、[Italiano](https://books2read.com/vpnguideit)、[Nederlands](https://books2read.com/vpnguidenl)、[Português](https://books2read.com/vpnguidept)、[日本語](https://books2read.com/vpnguideja)。\n\n## 搭建自己的 VPN 服务器：IPsec VPN、OpenVPN 与 WireGuard 完整指南\n\n本书是搭建你自己的 IPsec VPN、OpenVPN 和 WireGuard 服务器的**完整指南**。提供电子书和平装本格式。\n\n&raquo; [Google Play](https://books2read.com/vpnzh?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpnzh?store=apple)   \n&raquo; [Amazon](https://books2read.com/vpnzh?store=amazon)   \n&raquo; [Amazon 平装本](https://books2read.com/vpnzh?store=amazon-paperback&format=PAPERBACK)   \n&raquo; [其他平台](https://books2read.com/vpnzh)\n\n其他语言版本：[繁體中文](https://books2read.com/vpnzht)、[English](https://books2read.com/vpn)、[Español](https://books2read.com/vpnes)、[Deutsch](https://books2read.com/vpnde)、[Français](https://books2read.com/vpnfr)、[Italiano](https://books2read.com/vpnit)、[日本語](https://books2read.com/vpnja)。\n\n作者页面：[amazon.com/author/linsong](https://amazon.com/author/linsong)\n"
  },
  {
    "path": "docs/vpn-book.md",
    "content": "[&laquo; Back to home page](../README.md) | [English](vpn-book.md) | [简体中文](vpn-book-zh.md) | [繁體中文](vpn-book-zh-Hant.md) | [日本語](vpn-book-ja.md)\n\n## New: Privacy Tools in the Age of AI\n\nLearn how to build next-level privacy protection in the age of AI. This book is available in eBook, print and audiobook formats on:\n\n&raquo; [Amazon](https://books2read.com/privacy?store=amazon)   \n&raquo; [Google Play](https://books2read.com/privacy?store=google)   \n&raquo; [Apple Books](https://books2read.com/privacy?store=apple)   \n&raquo; [Hoopla](https://books2read.com/privacy?store=hoopla)   \n&raquo; [Other Platforms](https://books2read.com/privacy)\n\nOther language versions: [Español](https://books2read.com/privacyes), [Deutsch](https://books2read.com/privacyde), [Français](https://books2read.com/privacyfr), [Italiano](https://books2read.com/privacyit).\n\n## Build Your Own VPN Server: A Step by Step Guide\n\nThis book is a **step-by-step guide** to building your own IPsec VPN, OpenVPN and WireGuard server. Available in eBook, print and audiobook formats on:\n\n&raquo; [Amazon](https://books2read.com/vpnguide?store=amazon)   \n&raquo; [Google Play](https://books2read.com/vpnguide?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpnguide?store=apple)   \n&raquo; [Hoopla](https://books2read.com/vpnguide?store=hoopla)   \n&raquo; [Other Platforms](https://books2read.com/vpnguide)\n\nOther language versions: [简体中文](https://books2read.com/vpnguidezh), [繁體中文](https://books2read.com/vpnguidezht), [Español](https://books2read.com/vpnguidees), [Deutsch](https://books2read.com/vpnguidede), [Français](https://books2read.com/vpnguidefr), [Italiano](https://books2read.com/vpnguideit), [Nederlands](https://books2read.com/vpnguidenl), [Português](https://books2read.com/vpnguidept), [日本語](https://books2read.com/vpnguideja).\n\n## Set Up Your Own IPsec VPN, OpenVPN and WireGuard Server\n\nThis book is a **comprehensive guide** to building your own IPsec VPN, OpenVPN and WireGuard server. Available in eBook, print and audiobook formats on:\n\n&raquo; [Amazon](https://books2read.com/vpn?store=amazon)   \n&raquo; [Google Play](https://books2read.com/vpn?store=google)   \n&raquo; [Apple Books](https://books2read.com/vpn?store=apple)   \n&raquo; [Hoopla](https://books2read.com/vpn?store=hoopla)   \n&raquo; [Other Platforms](https://books2read.com/vpn)\n\nOther language versions: [简体中文](https://books2read.com/vpnzh), [繁體中文](https://books2read.com/vpnzht), [Español](https://books2read.com/vpnes), [Deutsch](https://books2read.com/vpnde), [Français](https://books2read.com/vpnfr), [Italiano](https://books2read.com/vpnit), [日本語](https://books2read.com/vpnja).\n\nAuthor page: [amazon.com/author/linsong](https://amazon.com/author/linsong)\n"
  },
  {
    "path": "extras/add_vpn_user.sh",
    "content": "#!/bin/bash\n#\n# Script to add/update a VPN user for both IPsec/L2TP and Cisco IPsec\n#\n# Copyright (C) 2018-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\n\nshow_intro() {\ncat <<'EOF'\n\nWelcome! Use this script to add or update a VPN user account for both\nIPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nIf the username you specify already exists, it will be updated\nwith the new password. Otherwise, a new VPN user will be added.\nEOF\n}\n\nadd_vpn_user() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf \\\n    || [ ! -f /etc/ppp/chap-secrets ] || [ ! -f /etc/ipsec.d/passwd ]; then\ncat 1>&2 <<'EOF'\nError: Your must first set up the IPsec VPN server before adding VPN users.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n  command -v openssl >/dev/null 2>&1 || exiterr \"'openssl' not found. Abort.\"\n  if [ \"$1\" = \"-h\" ] || [ \"$1\" = \"--help\" ]; then\ncat 1>&2 <<EOF\nUsage: sudo bash $0 'username_to_add' 'password'\n       sudo bash $0 'username_to_update' 'new_password'\nYou may also run this script interactively without arguments.\nEOF\n    exit 1\n  fi\n  VPN_USER=$1\n  VPN_PASSWORD=$2\n  if [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    show_intro\n    echo\n    echo \"List of existing VPN usernames:\"\n    cut -f1 -d : /etc/ipsec.d/passwd | LC_ALL=C sort\n    echo\n    echo \"Enter the VPN username you want to add or update.\"\n    read -rp \"Username: \" VPN_USER\n    if [ -z \"$VPN_USER\" ]; then\n      echo \"Abort. No changes were made.\" >&2\n      exit 1\n    fi\n    read -rp \"Password: \" VPN_PASSWORD\n    if [ -z \"$VPN_PASSWORD\" ]; then\n      echo \"Abort. No changes were made.\" >&2\n      exit 1\n    fi\n  fi\n  if printf '%s' \"$VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n  if [ -n \"$1\" ] && [ -n \"$2\" ]; then\n    show_intro\n  fi\ncat <<EOF\n\n================================================\n\nVPN user to add or update:\n\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n================================================\n\nEOF\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      echo \"Adding or updating VPN user...\"\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n  # Backup config files\n  conf_bk \"/etc/ppp/chap-secrets\"\n  conf_bk \"/etc/ipsec.d/passwd\"\n  # Add or update VPN user\n  sed -i \"/^\\\"$VPN_USER\\\" /d\" /etc/ppp/chap-secrets\ncat >> /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n  # shellcheck disable=SC2016\n  sed -i '/^'\"$VPN_USER\"':\\$1\\$/d' /etc/ipsec.d/passwd\n  VPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat >> /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n  # Update file attributes\n  chmod 600 /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\ncat <<'EOF'\nDone!\n\nNote: All VPN users will share the same IPsec PSK.\n      If you forgot the PSK, check /etc/ipsec.secrets.\n\nEOF\n}\n\n## Defer until we have the complete script\nadd_vpn_user \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/del_vpn_user.sh",
    "content": "#!/bin/bash\n#\n# Script to delete a VPN user for both IPsec/L2TP and Cisco IPsec\n#\n# Copyright (C) 2018-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\n\nshow_intro() {\ncat <<'EOF'\n\nWelcome! Use this script to delete a VPN user account for both\nIPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\nEOF\n}\n\ndel_vpn_user() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf \\\n    || [ ! -f /etc/ppp/chap-secrets ] || [ ! -f /etc/ipsec.d/passwd ]; then\ncat 1>&2 <<'EOF'\nError: Your must first set up the IPsec VPN server before deleting VPN users.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n  if [ \"$1\" = \"-h\" ] || [ \"$1\" = \"--help\" ]; then\ncat 1>&2 <<EOF\nUsage: sudo bash $0 'username_to_delete'\nYou may also run this script interactively without arguments.\nEOF\n    exit 1\n  fi\n  VPN_USER=$1\n  if [ -z \"$VPN_USER\" ]; then\n    show_intro\n    echo\n    echo \"List of existing VPN usernames:\"\n    cut -f1 -d : /etc/ipsec.d/passwd | LC_ALL=C sort\n    echo\n    echo \"Enter the VPN username you want to delete.\"\n    read -rp \"Username: \" VPN_USER\n    if [ -z \"$VPN_USER\" ]; then\n      echo \"Abort. No changes were made.\" >&2\n      exit 1\n    fi\n  fi\n  if printf '%s' \"$VPN_USER\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN username must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_USER\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN username must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n  if [ \"$(grep -c \"^\\\"$VPN_USER\\\" \" /etc/ppp/chap-secrets)\" = 0 ] \\\n    || [ \"$(grep -c \"^$VPN_USER:\\\\\\$1\\\\\\$\" /etc/ipsec.d/passwd)\" = 0 ]; then\ncat 1>&2 <<'EOF'\nError: The specified VPN user does not exist in /etc/ppp/chap-secrets\n       and/or /etc/ipsec.d/passwd.\nEOF\n    exit 1\n  fi\n  if [ \"$(grep -c -v -e '^#' -e '^[[:space:]]*$' /etc/ppp/chap-secrets)\" = 1 ] \\\n    || [ \"$(grep -c -v -e '^#' -e '^[[:space:]]*$' /etc/ipsec.d/passwd)\" = 1 ]; then\ncat 1>&2 <<'EOF'\nError: Could not delete the only VPN user from /etc/ppp/chap-secrets\n       and/or /etc/ipsec.d/passwd.\nEOF\n    exit 1\n  fi\n  [ -n \"$1\" ] && show_intro\ncat <<EOF\n\n================================================\n\nVPN user to delete:\n\nUsername: $VPN_USER\n\n================================================\n\nEOF\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      echo \"Deleting VPN user...\"\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n  # Backup config files\n  conf_bk \"/etc/ppp/chap-secrets\"\n  conf_bk \"/etc/ipsec.d/passwd\"\n  # Delete VPN user\n  sed -i \"/^\\\"$VPN_USER\\\" /d\" /etc/ppp/chap-secrets\n  # shellcheck disable=SC2016\n  sed -i '/^'\"$VPN_USER\"':\\$1\\$/d' /etc/ipsec.d/passwd\n  # Update file attributes\n  chmod 600 /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\ncat <<'EOF'\nDone!\n\nEOF\n}\n\n## Defer until we have the complete script\ndel_vpn_user \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/ikev2changeaddr.sh",
    "content": "#!/bin/bash\n#\n# Script to change IKEv2 VPN server address\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2022-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr() { echo \"Error: $1\" >&2; exit 1; }\nbigecho() { echo \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_os() {\n  os_type=$(lsb_release -si 2>/dev/null)\n  [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n  case $os_type in\n    [Aa]lpine)\n      os_type=alpine\n      ;;\n    *)\n      os_type=other\n      ;;\n  esac\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(ipsec --version 2>/dev/null)\n  if ( ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf && ! grep -qs \"hwdsl2\" /opt/src/run.sh ) \\\n    || ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script can only be used with an IPsec server created using:\n       https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\ncheck_ikev2() {\n  if ! grep -qs \"conn ikev2-cp\" /etc/ipsec.d/ikev2.conf; then\ncat 1>&2 <<'EOF'\nError: You must first set up IKEv2 before changing IKEv2 server address.\n       See: https://vpnsetup.net/ikev2\nEOF\n    exit 1\n  fi\n}\n\ncheck_utils_exist() {\n  command -v certutil >/dev/null 2>&1 || exiterr \"'certutil' not found. Abort.\"\n}\n\nabort_and_exit() {\n  echo \"Abort. No changes were made.\" >&2\n  exit 1\n}\n\ncheck_cert_exists() {\n  certutil -L -d sql:/etc/ipsec.d -n \"$1\" >/dev/null 2>&1\n}\n\ncheck_ca_cert_exists() {\n  check_cert_exists \"IKEv2 VPN CA\" || exiterr \"Certificate 'IKEv2 VPN CA' does not exist. Abort.\"\n}\n\nget_server_address() {\n  server_addr_old=$(grep -s \"leftcert=\" /etc/ipsec.d/ikev2.conf | cut -f2 -d= | head -n 1)\n  check_ip \"$server_addr_old\" || check_dns_name \"$server_addr_old\" || exiterr \"Could not get current VPN server address.\"\n}\n\nshow_welcome() {\ncat <<EOF\nWelcome! Use this script to change this IKEv2 VPN server's address.\n\nCurrent server address: $server_addr_old\n\nEOF\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\nget_server_ip() {\n  use_default_ip=0\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && { use_default_ip=1; return 0; }\n  bigecho \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n}\n\nenter_server_address() {\n  echo \"Do you want IKEv2 VPN clients to connect to this server using a DNS name,\"\n  printf \"e.g. vpn.example.com, instead of its IP address? [y/N] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY])\n      use_dns_name=1\n      echo\n      ;;\n    *)\n      use_dns_name=0\n      echo\n      ;;\n  esac\n  if [ \"$use_dns_name\" = 1 ]; then\n    read -rp \"Enter the DNS name of this VPN server: \" server_addr\n    until check_dns_name \"$server_addr\"; do\n      echo \"Invalid DNS name. You must enter a fully qualified domain name (FQDN).\"\n      read -rp \"Enter the DNS name of this VPN server: \" server_addr\n    done\n  else\n    get_server_ip\n    [ \"$use_default_ip\" = 0 ] && echo\n    read -rp \"Enter the IPv4 address of this VPN server: [$public_ip] \" server_addr\n    [ -z \"$server_addr\" ] && server_addr=\"$public_ip\"\n    until check_ip \"$server_addr\"; do\n      echo \"Invalid IP address.\"\n      read -rp \"Enter the IPv4 address of this VPN server: [$public_ip] \" server_addr\n      [ -z \"$server_addr\" ] && server_addr=\"$public_ip\"\n    done\n  fi\n}\n\ncheck_server_address() {\n  if [ \"$server_addr\" = \"$server_addr_old\" ]; then\n    echo >&2\n    echo \"Error: IKEv2 server address is already '$server_addr'. Nothing to do.\" >&2\n    abort_and_exit\n  fi\n}\n\nconfirm_changes() {\ncat <<EOF\n\nYou are about to change this IKEv2 VPN server's address.\n\n*IMPORTANT* After running this script, you must manually update\nthe server address (and remote ID, if applicable) on any existing\nIKEv2 client devices. For iOS clients, you'll need to export and\nre-import client configuration using the IKEv2 helper script.\n\n===========================================\n\nCurrent server address: $server_addr_old\nNew server address:     $server_addr\n\n===========================================\n\nEOF\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      abort_and_exit\n      ;;\n  esac\n}\n\ncreate_server_cert() {\n  if check_cert_exists \"$server_addr\"; then\n    bigecho \"Server certificate '$server_addr' already exists, skipping...\"\n  else\n    bigecho \"Generating server certificate...\"\n    if [ \"$use_dns_name\" = 1 ]; then\n      certutil -z <(head -c 1024 /dev/urandom) \\\n        -S -c \"IKEv2 VPN CA\" -n \"$server_addr\" \\\n        -s \"O=IKEv2 VPN,CN=$server_addr\" \\\n        -k rsa -g 3072 -v 120 \\\n        -d sql:/etc/ipsec.d -t \",,\" \\\n        --keyUsage digitalSignature,keyEncipherment \\\n        --extKeyUsage serverAuth \\\n        --extSAN \"dns:$server_addr\" >/dev/null 2>&1 || exiterr \"Failed to create server certificate.\"\n    else\n      certutil -z <(head -c 1024 /dev/urandom) \\\n        -S -c \"IKEv2 VPN CA\" -n \"$server_addr\" \\\n        -s \"O=IKEv2 VPN,CN=$server_addr\" \\\n        -k rsa -g 3072 -v 120 \\\n        -d sql:/etc/ipsec.d -t \",,\" \\\n        --keyUsage digitalSignature,keyEncipherment \\\n        --extKeyUsage serverAuth \\\n        --extSAN \"ip:$server_addr,dns:$server_addr\" >/dev/null 2>&1 || exiterr \"Failed to create server certificate.\"\n    fi\n  fi\n}\n\nupdate_ikev2_conf() {\n  bigecho \"Updating IKEv2 configuration...\"\n  if ! grep -qs '^include /etc/ipsec\\.d/\\*\\.conf$' /etc/ipsec.conf; then\n    echo >> /etc/ipsec.conf\n    echo 'include /etc/ipsec.d/*.conf' >> /etc/ipsec.conf\n  fi\n  sed -i\".old-$SYS_DT\" \\\n      -e \"/^[[:space:]]\\+leftcert=/d\" \\\n      -e \"/^[[:space:]]\\+leftid=/d\" /etc/ipsec.d/ikev2.conf\n  if [ \"$use_dns_name\" = 1 ]; then\n    sed -i \"/conn ikev2-cp/a \\  leftid=@$server_addr\" /etc/ipsec.d/ikev2.conf\n  else\n    sed -i \"/conn ikev2-cp/a \\  leftid=$server_addr\" /etc/ipsec.d/ikev2.conf\n  fi\n  sed -i \"/conn ikev2-cp/a \\  leftcert=$server_addr\" /etc/ipsec.d/ikev2.conf\n}\n\nupdate_ikev2_log() {\n  ikev2_log=\"/etc/ipsec.d/ikev2setup.log\"\n  if [ -s \"$ikev2_log\" ]; then\n    sed -i \"/VPN server address:/s/$server_addr_old/$server_addr/\" \"$ikev2_log\"\n  fi\n}\n\nrestart_ipsec_service() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  service ipsec restart 2>/dev/null\n}\n\nprint_client_info() {\ncat <<EOF\n\nSuccessfully changed IKEv2 server address!\n\nEOF\n}\n\nikev2changeaddr() {\n  check_root\n  check_os\n  check_libreswan\n  check_ikev2\n  check_utils_exist\n  check_ca_cert_exists\n  get_server_address\n\n  show_welcome\n  enter_server_address\n  check_server_address\n  confirm_changes\n\n  create_server_cert\n  update_ikev2_conf\n  update_ikev2_log\n  if [ \"$os_type\" = \"alpine\" ]; then\n    ipsec auto --replace ikev2-cp >/dev/null\n  else\n    restart_ipsec_service\n  fi\n  print_client_info\n}\n\n## Defer until we have the complete script\nikev2changeaddr \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/ikev2onlymode.sh",
    "content": "#!/bin/bash\n#\n# Script to enable or disable IKEv2-only mode\n#\n# Copyright (C) 2022-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr() { echo \"Error: $1\" >&2; exit 1; }\nbigecho() { echo \"## $1\"; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\nabort_and_exit() {\n  echo \"Abort. No changes were made.\" >&2\n  exit 1\n}\n\ncontinue_or_abort() {\n  printf '%s' \"$1\"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      abort_and_exit\n      ;;\n  esac\n}\n\ncheck_ikev2_exists() {\n  grep -qs \"conn ikev2-cp\" /etc/ipsec.conf || [ -f /etc/ipsec.d/ikev2.conf ]\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(ipsec --version 2>/dev/null)\n  swan_ver=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf \\\n    || ! grep -qs \"config setup\" /etc/ipsec.conf \\\n    || ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: Your must first set up the IPsec VPN server before selecting IKEv2-only mode.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n  if ! check_ikev2_exists; then\ncat 1>&2 <<'EOF'\nError: Your must first set up IKEv2 before selecting IKEv2-only mode.\n       See: https://vpnsetup.net/ikev2\nEOF\n    exit 1\n  fi\n}\n\ncheck_swan_ver() {\n  if ! printf '%s\\n%s' \"4.2\" \"$swan_ver\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$swan_ver' is not supported.\n       IKEv2-only mode requires Libreswan 4.2 or newer.\n       To update Libreswan, run:\n       wget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\nEOF\n    exit 1\n  fi\n}\n\nget_ikev2_only_status() {\n  if grep -qs \"ikev1-policy=drop\" /etc/ipsec.conf \\\n    || grep -qs \"ikev1-policy=reject\" /etc/ipsec.conf; then\n    ikev2_only_status=ENABLED\n    option_text=\"Disable IKEv2-only mode\"\n  else\n    ikev2_only_status=DISABLED\n    option_text=\"Enable IKEv2-only mode\"\n  fi\n}\n\nconfirm_disable_ikev2_only() {\ncat <<'EOF'\n\nNote: This option will disable IKEv2-only mode on this VPN server. With IKEv2-only\n      mode disabled, VPN clients can connect to this server using IKEv1 (including\n      IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes) in addition to IKEv2.\n\nEOF\n  continue_or_abort \"Do you want to continue? [Y/n] \"\n}\n\nconfirm_enable_ikev2_only() {\ncat <<'EOF'\n\nNote: This option will enable IKEv2-only mode on this VPN server. With IKEv2-only\n      mode enabled, VPN clients can *only* connect to this server using IKEv2.\n      All IKEv1 connections (including IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\")\n      modes) will be dropped.\n\nEOF\n  continue_or_abort \"Do you want to continue? [Y/n] \"\n}\n\ntoggle_ikev2_only() {\n  if [ \"$ikev2_only_status\" = \"ENABLED\" ]; then\n    confirm_disable_ikev2_only\n    bigecho \"Disabling IKEv2-only mode...\"\n    sed -i\".old-$SYS_DT\" \"/ikev1-policy=/d\" /etc/ipsec.conf\n    sed -i \"/config setup/a \\  ikev1-policy=accept\" /etc/ipsec.conf\n  elif [ \"$ikev2_only_status\" = \"DISABLED\" ]; then\n    confirm_enable_ikev2_only\n    bigecho \"Enabling IKEv2-only mode...\"\n    sed -i\".old-$SYS_DT\" \"/ikev1-policy=/d\" /etc/ipsec.conf\n    sed -i \"/config setup/a \\  ikev1-policy=drop\" /etc/ipsec.conf\n  fi\n}\n\nrestart_ipsec_service() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  service ipsec restart 2>/dev/null\n}\n\nprint_complete() {\ncat <<'EOF'\nDone!\n\nEOF\n}\n\nselect_menu_option() {\ncat <<EOF\n\nIKEv2-only mode is currently $ikev2_only_status on this VPN server.\n\nSelect an option:\n  1) $option_text\n  2) Exit\nEOF\n  read -rp \"Option: \" selected_option\n  until [[ \"$selected_option\" =~ ^[1-2]$ ]]; do\n    printf '%s\\n' \"$selected_option: invalid selection.\"\n    read -rp \"Option: \" selected_option\n  done\n}\n\nikev2onlymode() {\n  check_root\n  check_libreswan\n  check_swan_ver\n  get_ikev2_only_status\n  select_menu_option\n  case $selected_option in\n    1)\n      toggle_ikev2_only\n      restart_ipsec_service\n      print_complete\n      exit 0\n      ;;\n    *)\n      exit 0\n      ;;\n  esac\n}\n\n## Defer until we have the complete script\nikev2onlymode \"$@\"\n"
  },
  {
    "path": "extras/ikev2setup.sh",
    "content": "#!/bin/bash\n#\n# Script to set up and manage IKEv2 on Ubuntu, Debian, CentOS/RHEL, Rocky Linux,\n# AlmaLinux, Oracle Linux, Amazon Linux 2 and Alpine Linux\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexiterr() { echo \"Error: $1\" >&2; exit 1; }\nbigecho() { echo \"## $1\"; }\nbigecho2() { printf '\\e[2K\\r%s' \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_container() {\n  in_container=0\n  if grep -qs \"hwdsl2\" /opt/src/run.sh; then\n    in_container=1\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if grep -q \"release 7\" \"$rh_file\"; then\n      os_ver=7\n    elif grep -q \"release 8\" \"$rh_file\"; then\n      os_ver=8\n      grep -qi stream \"$rh_file\" && os_ver=8s\n    elif grep -q \"release 9\" \"$rh_file\"; then\n      os_ver=9\n      grep -qi stream \"$rh_file\" && os_ver=9s\n    elif grep -q \"release 10\" \"$rh_file\"; then\n      os_ver=10\n      grep -qi stream \"$rh_file\" && os_ver=10s\n    else\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n    if [ \"$os_type\" = \"centos\" ] \\\n      && { [ \"$os_ver\" = 7 ] || [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 8s ]; }; then\n      exiterr \"CentOS Linux $os_ver is EOL and not supported.\"\n    fi\n  elif grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    os_type=amzn\n    os_ver=2\n  else\n    os_type=$(lsb_release -si 2>/dev/null)\n    [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n    case $os_type in\n      [Uu]buntu)\n        os_type=ubuntu\n        ;;\n      [Dd]ebian|[Kk]ali)\n        os_type=debian\n        ;;\n      [Rr]aspbian)\n        os_type=raspbian\n        ;;\n      [Aa]lpine)\n        os_type=alpine\n        ;;\n      *)\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       Ubuntu, Debian, CentOS/RHEL, Rocky Linux, AlmaLinux,\n       Oracle Linux, Amazon Linux 2 or Alpine Linux\nEOF\n        exit 1\n        ;;\n    esac\n    if [ \"$os_type\" = \"alpine\" ]; then\n      os_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\" | cut -d '.' -f 1,2)\n    else\n      os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n      if [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = \"stretchsid\" ] \\\n        || [ \"$os_ver\" = \"bustersid\" ] || [ -z \"$os_ver\" ]; then\ncat 1>&2 <<EOF\nError: This script requires Debian >= 10 or Ubuntu >= 20.04.\n       This version of Ubuntu/Debian is too old and not supported.\nEOF\n        exit 1\n      fi\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(ipsec --version 2>/dev/null)\n  if ( ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf && ! grep -qs \"hwdsl2\" /opt/src/run.sh ) \\\n    || ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: Your must first set up the IPsec VPN server before setting up IKEv2.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\ncheck_swan_ver() {\n  swan_ver=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! printf '%s\\n%s' \"3.23\" \"$swan_ver\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$swan_ver' is not supported.\n       This script requires Libreswan 3.23 or newer.\n       To update Libreswan, run:\n       wget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\nEOF\n    exit 1\n  fi\n}\n\ncheck_utils_exist() {\n  command -v certutil >/dev/null 2>&1 || exiterr \"'certutil' not found. Abort.\"\n  command -v crlutil >/dev/null 2>&1 || exiterr \"'crlutil' not found. Abort.\"\n  command -v pk12util >/dev/null 2>&1 || exiterr \"'pk12util' not found. Abort.\"\n}\n\nabort_and_exit() {\n  echo \"Abort. No changes were made.\" >&2\n  exit 1\n}\n\nconfirm_or_abort() {\n  printf '%s' \"$1\"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY])\n      echo\n      ;;\n    *)\n      abort_and_exit\n      ;;\n  esac\n}\n\nshow_header() {\ncat <<'EOF'\n\nIKEv2 Script   Copyright (c) 2020-2026 Lin Song   20 Mar 2026\n\nEOF\n}\n\nshow_usage() {\n  if [ -n \"$1\" ]; then\n    echo \"Error: $1\" >&2\n  fi\n  show_header\ncat 1>&2 <<EOF\nUsage: bash $0 [options]\n\nOptions:\n  --auto                        run IKEv2 setup in auto mode using default options (for initial setup only)\n  --addclient [client name]     add a new client using default options\n  --exportclient [client name]  export configuration for an existing client\n  --listclients                 list the names of existing clients\n  --revokeclient [client name]  revoke an existing client\n  --deleteclient [client name]  delete an existing client\n  --removeikev2                 remove IKEv2 and delete all certificates and keys from the IPsec database\n  -y, --yes                     assume \"yes\" as answer to prompts when revoking/deleting a client or removing IKEv2\n  -h, --help                    show this help message and exit\n\nTo customize IKEv2 or client options, run this script without arguments.\nFor documentation, see: https://vpnsetup.net/ikev2\nEOF\n  exit 1\n}\n\ncheck_ikev2_exists() {\n  grep -qs \"conn ikev2-cp\" \"$IPSEC_CONF\" || [ -f \"$IKEV2_CONF\" ]\n}\n\ncheck_client_name() {\n  ! { [ \"${#1}\" -gt \"64\" ] || printf '%s' \"$1\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n    || case $1 in -*) true ;; *) false ;; esac; }\n}\n\ncheck_cert_exists() {\n  certutil -L -d \"$CERT_DB\" -n \"$1\" >/dev/null 2>&1\n}\n\ncheck_cert_exists_and_exit() {\n  if certutil -L -d \"$CERT_DB\" -n \"$1\" >/dev/null 2>&1; then\n    echo \"Error: Certificate '$1' already exists.\" >&2\n    abort_and_exit\n  fi\n}\n\ncheck_cert_status() {\n  cert_status=$(certutil -V -u C -d \"$CERT_DB\" -n \"$1\")\n}\n\ncheck_arguments() {\n  if [ \"$use_defaults\" = 1 ] && check_ikev2_exists; then\n    echo \"Error: Invalid parameter '--auto'. IKEv2 is already set up on this server.\" >&2\n    echo \"       To manage VPN clients, re-run this script without '--auto'.\" >&2\n    echo \"       To change IKEv2 server address, see https://vpnsetup.net/ikev2\" >&2\n    exit 1\n  fi\n  if [ \"$((add_client + export_client + list_clients + revoke_client + delete_client))\" -gt 1 ]; then\n    show_usage \"Invalid parameters. Specify only one of '--addclient', '--exportclient', '--listclients', '--revokeclient' or '--deleteclient'.\"\n  fi\n  if [ \"$remove_ikev2\" = 1 ]; then\n    if [ \"$((add_client + export_client + list_clients + revoke_client + delete_client + use_defaults))\" -gt 0 ]; then\n      show_usage \"Invalid parameters. '--removeikev2' cannot be specified with other parameters.\"\n    fi\n  fi\n  if ! check_ikev2_exists; then\n    [ \"$add_client\" = 1 ] && exiterr \"You must first set up IKEv2 before adding a client.\"\n    [ \"$export_client\" = 1 ] && exiterr \"You must first set up IKEv2 before exporting a client.\"\n    [ \"$list_clients\" = 1 ] && exiterr \"You must first set up IKEv2 before listing clients.\"\n    [ \"$revoke_client\" = 1 ] && exiterr \"You must first set up IKEv2 before revoking a client.\"\n    [ \"$delete_client\" = 1 ] && exiterr \"You must first set up IKEv2 before deleting a client.\"\n    [ \"$remove_ikev2\" = 1 ] && exiterr \"Cannot remove IKEv2 because it has not been set up on this server.\"\n  fi\n  if [ \"$add_client\" = 1 ]; then\n    if [ -z \"$client_name\" ] || ! check_client_name \"$client_name\"; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    elif check_cert_exists \"$client_name\"; then\n      exiterr \"Invalid client name. Client '$client_name' already exists.\"\n    fi\n  fi\n  if [ \"$export_client\" = 1 ] || [ \"$revoke_client\" = 1 ] || [ \"$delete_client\" = 1 ]; then\n    get_server_address\n    if [ -z \"$client_name\" ] || ! check_client_name \"$client_name\" \\\n      || [ \"$client_name\" = \"$CA_NAME\" ] || [ \"$client_name\" = \"$server_addr\" ] \\\n      || ! check_cert_exists \"$client_name\"; then\n      exiterr \"Invalid client name, or client does not exist.\"\n    fi\n    if [ \"$delete_client\" = 0 ] && ! check_cert_status \"$client_name\"; then\n      printf '%s' \"Error: Certificate '$client_name' \" >&2\n      if printf '%s' \"$cert_status\" | grep -q \"revoked\"; then\n        if [ \"$revoke_client\" = 1 ]; then\n          echo \"has already been revoked.\" >&2\n        else\n          echo \"has been revoked.\" >&2\n        fi\n      elif printf '%s' \"$cert_status\" | grep -q \"expired\"; then\n        echo \"has expired.\" >&2\n      else\n        echo \"is invalid.\" >&2\n      fi\n      exit 1\n    fi\n  fi\n}\n\ncheck_server_dns_name() {\n  if [ -n \"$VPN_DNS_NAME\" ]; then\n    check_dns_name \"$VPN_DNS_NAME\" || exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_custom_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"Invalid DNS server(s).\"\n  fi\n}\n\ncheck_client_validity() {\n  ! { printf '%s' \"$1\" | LC_ALL=C grep -q '[^0-9]\\+' || [ \"$1\" -lt \"1\" ] \\\n  || [ \"$1\" -gt \"120\" ] || [ \"$1\" != \"$((10#$1))\" ]; }\n}\n\ncheck_and_set_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    client_name=\"$VPN_CLIENT_NAME\"\n    check_client_name \"$client_name\" \\\n      || exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n  else\n    client_name=vpnclient\n  fi\n  check_cert_exists \"$client_name\" && exiterr \"Client '$client_name' already exists.\"\n}\n\ncheck_and_set_client_validity() {\n  if [ -n \"$VPN_CLIENT_VALIDITY\" ]; then\n    client_validity=\"$VPN_CLIENT_VALIDITY\"\n    if ! check_client_validity \"$client_validity\"; then\ncat <<EOF\nWARNING: Invalid client cert validity period. Must be an integer between 1 and 120.\n         Falling back to default validity (120 months).\nEOF\n      VPN_CLIENT_VALIDITY=\"\"\n      client_validity=120\n    fi\n  else\n    client_validity=120\n  fi\n}\n\nset_server_address() {\n  if [ -n \"$VPN_DNS_NAME\" ]; then\n    use_dns_name=1\n    server_addr=\"$VPN_DNS_NAME\"\n  else\n    use_dns_name=0\n    get_server_ip\n    check_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP.\"\n    server_addr=\"$public_ip\"\n  fi\n  check_cert_exists_and_exit \"$server_addr\"\n}\n\nset_dns_servers() {\n  if [ -n \"$VPN_DNS_SRV1\" ] && [ -n \"$VPN_DNS_SRV2\" ]; then\n    dns_server_1=\"$VPN_DNS_SRV1\"\n    dns_server_2=\"$VPN_DNS_SRV2\"\n    dns_servers=\"$VPN_DNS_SRV1 $VPN_DNS_SRV2\"\n  elif [ -n \"$VPN_DNS_SRV1\" ]; then\n    dns_server_1=\"$VPN_DNS_SRV1\"\n    dns_server_2=\"\"\n    dns_servers=\"$VPN_DNS_SRV1\"\n  else\n    dns_server_1=8.8.8.8\n    dns_server_2=8.8.4.4\n    dns_servers=\"8.8.8.8 8.8.4.4\"\n  fi\n}\n\nshow_welcome() {\ncat <<'EOF'\nWelcome! Use this script to set up IKEv2 on your VPN server.\n\nI need to ask you a few questions before starting setup.\nYou can use the default options and just press enter if you are OK with them.\n\nEOF\n}\n\nshow_start_setup() {\n  op_text=default\n  if [ -n \"$VPN_DNS_NAME\" ] || [ -n \"$VPN_CLIENT_NAME\" ] \\\n    || [ -n \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_PROTECT_CONFIG\" ] \\\n    || [ -n \"$VPN_CLIENT_VALIDITY\" ]; then\n    op_text=custom\n  fi\n  bigecho \"Starting IKEv2 setup in auto mode, using $op_text options.\"\n}\n\nshow_add_client() {\n  op_text=default\n  if [ -n \"$VPN_CLIENT_VALIDITY\" ]; then\n    op_text=custom\n  fi\n  bigecho \"Adding a new IKEv2 client '$client_name', using $op_text options.\"\n}\n\nshow_export_client() {\n  bigecho \"Exporting IKEv2 client '$client_name'.\"\n}\n\nget_export_dir() {\n  export_to_home_dir=0\n  if grep -qs \"hwdsl2\" /opt/src/run.sh; then\n    export_dir=\"/etc/ipsec.d/\"\n  else\n    export_dir=~/\n    if [ -n \"$SUDO_USER\" ] && getent group \"$SUDO_USER\" >/dev/null 2>&1; then\n      user_home_dir=$(getent passwd \"$SUDO_USER\" 2>/dev/null | cut -d: -f6)\n      if [ -d \"$user_home_dir\" ] && [ \"$user_home_dir\" != \"/\" ]; then\n        export_dir=\"$user_home_dir/\"\n        export_to_home_dir=1\n      fi\n    fi\n  fi\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\nget_server_ip() {\n  use_default_ip=0\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && { use_default_ip=1; return 0; }\n  bigecho2 \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n}\n\nget_server_address() {\n  server_addr=$(grep -s \"leftcert=\" \"$IKEV2_CONF\" | cut -f2 -d= | head -n 1)\n  [ -z \"$server_addr\" ] && server_addr=$(grep -s \"leftcert=\" \"$IPSEC_CONF\" | cut -f2 -d= | head -n 1)\n  check_ip \"$server_addr\" || check_dns_name \"$server_addr\" || exiterr \"Could not get VPN server address.\"\n}\n\nlist_existing_clients() {\n  echo \"Checking for existing IKEv2 client(s)...\"\n  echo\n  client_names=$(certutil -L -d \"$CERT_DB\" | grep -v -e '^$' -e \"$CA_NAME\" -e '\\.' | tail -n +3 | cut -f1 -d ' ')\n  max_len=$(printf '%s\\n' \"$client_names\" | wc -L 2>/dev/null)\n  [[ $max_len =~ ^[0-9]+$ ]] || max_len=64\n  [ \"$max_len\" -gt \"64\" ] && max_len=64\n  [ \"$max_len\" -lt \"16\" ] && max_len=16\n  printf \"%-${max_len}s  %s\\n\" 'Client Name' 'Certificate Status'\n  printf \"%-${max_len}s  %s\\n\" '------------' '-------------------'\n  if [ -n \"$client_names\" ]; then\n    client_list=$(printf '%s\\n' \"$client_names\" | LC_ALL=C sort)\n    while IFS= read -r line; do\n      printf \"%-${max_len}s  \" \"$line\"\n      client_status=$(certutil -V -u C -d \"$CERT_DB\" -n \"$line\" | grep -o -e ' valid' -e expired -e revoked | sed -e 's/^ //')\n      [ -z \"$client_status\" ] && client_status=unknown\n      printf '%s\\n' \"$client_status\"\n    done <<< \"$client_list\"\n  fi\n  client_count=$(printf '%s\\n' \"$client_names\" | wc -l 2>/dev/null)\n  [ -z \"$client_names\" ] && client_count=0\n  if [ \"$client_count\" = 1 ]; then\n    printf '\\n%s\\n' \"Total: 1 client\"\n  elif [ -n \"$client_count\" ]; then\n    printf '\\n%s\\n' \"Total: $client_count clients\"\n  fi\n}\n\nenter_server_address() {\n  echo \"Do you want IKEv2 clients to connect to this server using a DNS name,\"\n  printf \"e.g. vpn.example.com, instead of its IP address? [y/N] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY])\n      use_dns_name=1\n      echo\n      ;;\n    *)\n      use_dns_name=0\n      echo\n      ;;\n  esac\n  if [ \"$use_dns_name\" = 1 ]; then\n    read -rp \"Enter the DNS name of this VPN server: \" server_addr\n    until check_dns_name \"$server_addr\"; do\n      echo \"Invalid DNS name. You must enter a fully qualified domain name (FQDN).\"\n      read -rp \"Enter the DNS name of this VPN server: \" server_addr\n    done\n  else\n    get_server_ip\n    [ \"$use_default_ip\" = 0 ] && { echo; echo; }\n    read -rp \"Enter the IPv4 address of this VPN server: [$public_ip] \" server_addr\n    [ -z \"$server_addr\" ] && server_addr=\"$public_ip\"\n    until check_ip \"$server_addr\"; do\n      echo \"Invalid IP address.\"\n      read -rp \"Enter the IPv4 address of this VPN server: [$public_ip] \" server_addr\n      [ -z \"$server_addr\" ] && server_addr=\"$public_ip\"\n    done\n  fi\n}\n\nenter_client_name() {\n  echo\n  echo \"Provide a name for the IKEv2 client.\"\n  echo \"Use one word only, no special characters except '-' and '_'.\"\n  if [ \"$1\" = \"with_defaults\" ]; then\n    read -rp \"Client name: [vpnclient] \" client_name\n    [ -z \"$client_name\" ] && client_name=vpnclient\n  else\n    read -rp \"Client name: \" client_name\n    [ -z \"$client_name\" ] && abort_and_exit\n  fi\n  while ! check_client_name \"$client_name\" || check_cert_exists \"$client_name\"; do\n    if ! check_client_name \"$client_name\"; then\n      echo \"Invalid client name.\"\n    else\n      echo \"Invalid client name. Client '$client_name' already exists.\"\n    fi\n    if [ \"$1\" = \"with_defaults\" ]; then\n      read -rp \"Client name: [vpnclient] \" client_name\n      [ -z \"$client_name\" ] && client_name=vpnclient\n    else\n      read -rp \"Client name: \" client_name\n      [ -z \"$client_name\" ] && abort_and_exit\n    fi\n  done\n}\n\nenter_client_name_for() {\n  echo\n  list_existing_clients\n  if [ \"$client_count\" = 0 ]; then\n    echo\n    echo \"No IKEv2 clients in the IPsec database. Nothing to $1.\" >&2\n    exit 1\n  fi\n  get_server_address\n  echo\n  read -rp \"Enter the name of the IKEv2 client to $1: \" client_name\n  [ -z \"$client_name\" ] && abort_and_exit\n  while ! check_client_name \"$client_name\" || [ \"$client_name\" = \"$CA_NAME\" ] \\\n    || [ \"$client_name\" = \"$server_addr\" ] || ! check_cert_exists \"$client_name\" \\\n    || ! check_cert_status \"$client_name\"; do\n    if ! check_client_name \"$client_name\" || [ \"$client_name\" = \"$CA_NAME\" ] \\\n    || [ \"$client_name\" = \"$server_addr\" ] || ! check_cert_exists \"$client_name\"; then\n      echo \"Invalid client name, or client does not exist.\"\n    else\n      [ \"$1\" = \"delete\" ] && break\n      printf '%s' \"Error: Certificate '$client_name' \"\n      if printf '%s' \"$cert_status\" | grep -q \"revoked\"; then\n        if [ \"$1\" = \"revoke\" ]; then\n          echo \"has already been revoked.\"\n        else\n          echo \"has been revoked.\"\n        fi\n      elif printf '%s' \"$cert_status\" | grep -q \"expired\"; then\n        echo \"has expired.\"\n      else\n        echo \"is invalid.\"\n      fi\n    fi\n    read -rp \"Enter the name of the IKEv2 client to $1: \" client_name\n    [ -z \"$client_name\" ] && abort_and_exit\n  done\n}\n\nenter_client_validity() {\n  echo\n  echo \"Specify the validity period (in months) for this client certificate.\"\n  read -rp \"Enter an integer between 1 and 120: [120] \" client_validity\n  [ -z \"$client_validity\" ] && client_validity=120\n  while ! check_client_validity \"$client_validity\"; do\n    echo \"Invalid validity period.\"\n    read -rp \"Enter an integer between 1 and 120: [120] \" client_validity\n    [ -z \"$client_validity\" ] && client_validity=120\n  done\n}\n\nenter_custom_dns() {\n  echo\n  echo \"By default, clients are set to use Google Public DNS when the VPN is active.\"\n  printf \"Do you want to specify custom DNS servers for IKEv2? [y/N] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY])\n      use_custom_dns=1\n      ;;\n    *)\n      use_custom_dns=0\n      dns_server_1=8.8.8.8\n      dns_server_2=8.8.4.4\n      dns_servers=\"8.8.8.8 8.8.4.4\"\n      ;;\n  esac\n  if [ \"$use_custom_dns\" = 1 ]; then\n    read -rp \"Enter primary DNS server: \" dns_server_1\n    until check_ip \"$dns_server_1\"; do\n      echo \"Invalid DNS server.\"\n      read -rp \"Enter primary DNS server: \" dns_server_1\n    done\n    read -rp \"Enter secondary DNS server (Enter to skip): \" dns_server_2\n    until [ -z \"$dns_server_2\" ] || check_ip \"$dns_server_2\"; do\n      echo \"Invalid DNS server.\"\n      read -rp \"Enter secondary DNS server (Enter to skip): \" dns_server_2\n    done\n    if [ -n \"$dns_server_2\" ]; then\n      dns_servers=\"$dns_server_1 $dns_server_2\"\n    else\n      dns_servers=\"$dns_server_1\"\n    fi\n  else\n    echo \"Using Google Public DNS (8.8.8.8, 8.8.4.4).\"\n  fi\n  echo\n}\n\ncheck_mobike_support() {\n  mobike_support=1\n  if uname -m | grep -qi -e '^arm' -e '^aarch64'; then\n    modprobe -q configs\n    if [ -f /proc/config.gz ]; then\n      if ! zcat /proc/config.gz | grep -q \"CONFIG_XFRM_MIGRATE=y\"; then\n        mobike_support=0\n      fi\n    else\n      mobike_support=0\n    fi\n  fi\n  kernel_conf=\"/boot/config-$(uname -r)\"\n  if [ -f \"$kernel_conf\" ]; then\n    if ! grep -qs \"CONFIG_XFRM_MIGRATE=y\" \"$kernel_conf\"; then\n      mobike_support=0\n    fi\n  fi\n  # Linux kernels on Ubuntu do not support MOBIKE\n  if [ \"$in_container\" = 0 ]; then\n    if [ \"$os_type\" = \"ubuntu\" ] || uname -v | grep -qi ubuntu; then\n      mobike_support=0\n    fi\n  else\n    if uname -v | grep -qi ubuntu; then\n      mobike_support=0\n    fi\n  fi\n  if uname -a | grep -qi qnap; then\n    mobike_support=0\n  fi\n  if uname -a | grep -qi synology; then\n    mobike_support=0\n  fi\n  if [ \"$mobike_support\" = 1 ]; then\n    bigecho2 \"Checking for MOBIKE support... available\"\n  else\n    bigecho2 \"Checking for MOBIKE support... not available\"\n  fi\n}\n\nselect_mobike() {\n  echo\n  mobike_enable=0\n  if [ \"$mobike_support\" = 1 ]; then\ncat <<'EOF'\n\nThe MOBIKE IKEv2 extension allows VPN clients to change network attachment points,\ne.g. switch between mobile data and Wi-Fi and keep the IPsec tunnel up on the new IP.\n\nEOF\n    printf \"Enable MOBIKE support? [Y/n] \"\n    read -r response\n    case $response in\n      [yY][eE][sS]|[yY]|'')\n        mobike_enable=1\n        ;;\n      *)\n        mobike_enable=0\n        ;;\n    esac\n  fi\n}\n\ncheck_config_password() {\n  use_config_password=0\n  case $VPN_PROTECT_CONFIG in\n    [yY][eE][sS])\n      use_config_password=1\n      ;;\n    *)\n      if grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$CONF_FILE\"; then\n        use_config_password=1\n      fi\n      ;;\n  esac\n}\n\nselect_config_password() {\n  if [ \"$use_config_password\" = 0 ]; then\ncat <<'EOF'\n\nIKEv2 client config files contain the client certificate, private key and CA certificate.\nThis script can optionally generate a random password to protect these files.\n\nEOF\n    printf \"Protect client config files using a password? [y/N] \"\n    read -r response\n    case $response in\n      [yY][eE][sS]|[yY])\n        use_config_password=1\n        ;;\n      *)\n        use_config_password=0\n        ;;\n    esac\n  fi\n}\n\nselect_menu_option() {\ncat <<'EOF'\nIKEv2 is already set up on this server.\n\nSelect an option:\n  1) Add a new client\n  2) Export config for an existing client\n  3) List existing clients\n  4) Revoke an existing client\n  5) Delete an existing client\n  6) Remove IKEv2\n  7) Exit\nEOF\n  read -rp \"Option: \" selected_option\n  until [[ \"$selected_option\" =~ ^[1-7]$ ]]; do\n    printf '%s\\n' \"$selected_option: invalid selection.\"\n    read -rp \"Option: \" selected_option\n  done\n}\n\nprint_server_info() {\ncat <<EOF\nVPN server address: $server_addr\n\nEOF\n}\n\nconfirm_setup_options() {\ncat <<EOF\n\nWe are ready to set up IKEv2 now. Below are the setup options you selected.\n\n======================================\n\nServer address: $server_addr\nClient name: $client_name\n\nEOF\n  if [ \"$client_validity\" = 1 ]; then\n    echo \"Client cert valid for: 1 month\"\n  else\n    echo \"Client cert valid for: $client_validity months\"\n  fi\n  if [ \"$mobike_support\" = 1 ]; then\n    if [ \"$mobike_enable\" = 1 ]; then\n      echo \"MOBIKE support: Enable\"\n    else\n      echo \"MOBIKE support: Disable\"\n    fi\n  else\n    echo \"MOBIKE support: Not available\"\n  fi\n  if [ \"$use_config_password\" = 1 ]; then\n    echo \"Protect client config: Yes\"\n  else\n    echo \"Protect client config: No\"\n  fi\ncat <<EOF\nDNS server(s): $dns_servers\n\n======================================\n\nEOF\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      abort_and_exit\n      ;;\n  esac\n}\n\ncreate_client_cert() {\n  bigecho2 \"Generating client certificate...\"\n  sleep 1\n  certutil -z <(head -c 1024 /dev/urandom) \\\n    -S -c \"$CA_NAME\" -n \"$client_name\" \\\n    -s \"O=IKEv2 VPN,CN=$client_name\" \\\n    -k rsa -g 3072 -v \"$client_validity\" \\\n    -d \"$CERT_DB\" -t \",,\" \\\n    --keyUsage digitalSignature,keyEncipherment \\\n    --extKeyUsage serverAuth,clientAuth -8 \"$client_name\" >/dev/null 2>&1 || exiterr \"Failed to create client certificate.\"\n}\n\ncreate_p12_password() {\n  p12_password=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 18)\n  [ -z \"$p12_password\" ] && exiterr \"Could not generate a random password for .p12 file.\"\n}\n\nget_p12_password() {\n  if [ \"$use_config_password\" = 0 ]; then\n    create_p12_password\n  else\n    p12_password=$(grep -s '^IKEV2_CONFIG_PASSWORD=.\\+' \"$CONF_FILE\" | tail -n 1 | cut -f2- -d= | sed -e \"s/^'//\" -e \"s/'$//\")\n    if [ -z \"$p12_password\" ]; then\n      create_p12_password\n      if [ -n \"$CONF_FILE\" ] && [ -n \"$CONF_DIR\" ]; then\n        mkdir -p \"$CONF_DIR\"\n        printf '%s\\n' \"IKEV2_CONFIG_PASSWORD='$p12_password'\" >> \"$CONF_FILE\"\n        chmod 600 \"$CONF_FILE\"\n      fi\n    fi\n  fi\n}\n\nexport_p12_file() {\n  bigecho2 \"Creating client configuration...\"\n  get_p12_password\n  p12_file=\"$export_dir$client_name.p12\"\n  p12_file_enc=\"$export_dir$client_name.enc.p12\"\n  pk12util -W \"$p12_password\" -d \"$CERT_DB\" -n \"$client_name\" -o \"$p12_file_enc\" >/dev/null || exit 1\n  if [ \"$os_ver\" = \"bookwormsid\" ] || openssl version 2>/dev/null | grep -q \"^OpenSSL 3\"; then\n    ca_crt=\"$export_dir$client_name.ca.crt\"\n    client_crt=\"$export_dir$client_name.client.crt\"\n    client_key=\"$export_dir$client_name.client.key\"\n    pem_file=\"$export_dir$client_name.temp.pem\"\n    openssl pkcs12 -in \"$p12_file_enc\" -passin \"pass:$p12_password\" -cacerts -nokeys -out \"$ca_crt\" || exit 1\n    openssl pkcs12 -in \"$p12_file_enc\" -passin \"pass:$p12_password\" -clcerts -nokeys -out \"$client_crt\" || exit 1\n    openssl pkcs12 -in \"$p12_file_enc\" -passin \"pass:$p12_password\" -passout \"pass:$p12_password\" \\\n      -nocerts -out \"$client_key\" || exit 1\n    cat \"$client_key\" \"$client_crt\" \"$ca_crt\" > \"$pem_file\"\n    /bin/rm -f \"$client_key\" \"$client_crt\" \"$ca_crt\"\n    openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in \"$pem_file\" -out \"$p12_file_enc\" \\\n      -legacy -name \"$client_name\" -passin \"pass:$p12_password\" -passout \"pass:$p12_password\" || exit 1\n    if [ \"$use_config_password\" = 0 ]; then\n      openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in \"$pem_file\" -out \"$p12_file\" \\\n        -legacy -name \"$client_name\" -passin \"pass:$p12_password\" -passout pass: || exit 1\n    fi\n    /bin/rm -f \"$pem_file\"\n  elif [ \"$os_type\" = \"alpine\" ] || [ \"$os_ver\" = \"kalirolling\" ] || [ \"$os_ver\" = \"bullseyesid\" ]; then\n    pem_file=\"$export_dir$client_name.temp.pem\"\n    openssl pkcs12 -in \"$p12_file_enc\" -out \"$pem_file\" -passin \"pass:$p12_password\" -passout \"pass:$p12_password\" || exit 1\n    openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in \"$pem_file\" -out \"$p12_file_enc\" \\\n      -name \"$client_name\" -passin \"pass:$p12_password\" -passout \"pass:$p12_password\" || exit 1\n    if [ \"$use_config_password\" = 0 ]; then\n      openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in \"$pem_file\" -out \"$p12_file\" \\\n        -name \"$client_name\" -passin \"pass:$p12_password\" -passout pass: || exit 1\n    fi\n    /bin/rm -f \"$pem_file\"\n  elif [ \"$use_config_password\" = 0 ]; then\n    pk12util -W \"\" -d \"$CERT_DB\" -n \"$client_name\" -o \"$p12_file\" >/dev/null || exit 1\n  fi\n  if [ \"$use_config_password\" = 1 ]; then\n    /bin/cp -f \"$p12_file_enc\" \"$p12_file\"\n  fi\n  if [ \"$export_to_home_dir\" = 1 ]; then\n    chown \"$SUDO_USER:$SUDO_USER\" \"$p12_file\"\n  fi\n  chmod 600 \"$p12_file\"\n}\n\ninstall_base64_uuidgen() {\n  if ! command -v base64 >/dev/null 2>&1 || ! command -v uuidgen >/dev/null 2>&1; then\n    bigecho2 \"Installing required packages...\"\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ] || [ \"$os_type\" = \"raspbian\" ]; then\n      export DEBIAN_FRONTEND=noninteractive\n      apt-get -yqq update || apt-get -yqq update || exiterr \"'apt-get update' failed.\"\n    fi\n  fi\n  if ! command -v base64 >/dev/null 2>&1; then\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ] || [ \"$os_type\" = \"raspbian\" ]; then\n      apt-get -yqq install coreutils >/dev/null || exiterr \"'apt-get install' failed.\"\n    else\n      yum -y -q install coreutils >/dev/null || exiterr \"'yum install' failed.\"\n    fi\n  fi\n  if ! command -v uuidgen >/dev/null 2>&1; then\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ] || [ \"$os_type\" = \"raspbian\" ]; then\n      apt-get -yqq install uuid-runtime >/dev/null || exiterr \"'apt-get install' failed.\"\n    else\n      yum -y -q install util-linux >/dev/null || exiterr \"'yum install' failed.\"\n    fi\n  fi\n}\n\ninstall_uuidgen() {\n  if ! command -v uuidgen >/dev/null 2>&1; then\n    bigecho2 \"Installing required packages...\"\n    apk add -U -q uuidgen || exiterr \"'apk add' failed.\"\n  fi\n}\n\nupdate_ikev2_conf() {\n  if grep -qs 'ike=aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1$' \"$IKEV2_CONF\"; then\n    bigecho2 \"Updating IKEv2 configuration...\"\n    sed -i \\\n      \"/ike=aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1$/s/ike=/ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,/\" \\\n      \"$IKEV2_CONF\"\n    if [ \"$os_type\" = \"alpine\" ]; then\n      ipsec auto --add ikev2-cp >/dev/null\n    else\n      restart_ipsec_service >/dev/null\n    fi\n  fi\n}\n\ncreate_mobileconfig() {\n  [ -z \"$server_addr\" ] && get_server_address\n  p12_file_enc=\"$export_dir$client_name.enc.p12\"\n  p12_base64=$(base64 -w 52 \"$p12_file_enc\")\n  /bin/rm -f \"$p12_file_enc\"\n  [ -z \"$p12_base64\" ] && exiterr \"Could not encode .p12 file.\"\n  ca_base64=$(certutil -L -d \"$CERT_DB\" -n \"$CA_NAME\" -a | grep -v CERTIFICATE)\n  [ -z \"$ca_base64\" ] && exiterr \"Could not encode $CA_NAME certificate.\"\n  uuid1=$(uuidgen)\n  [ -z \"$uuid1\" ] && exiterr \"Could not generate UUID value.\"\n  mc_file=\"$export_dir$client_name.mobileconfig\"\ncat > \"$mc_file\" <<EOF\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>PayloadContent</key>\n  <array>\n    <dict>\n      <key>IKEv2</key>\n      <dict>\n        <key>AuthenticationMethod</key>\n        <string>Certificate</string>\n        <key>ChildSecurityAssociationParameters</key>\n        <dict>\n          <key>DiffieHellmanGroup</key>\n          <integer>19</integer>\n          <key>EncryptionAlgorithm</key>\n          <string>AES-256-GCM</string>\n          <key>LifeTimeInMinutes</key>\n          <integer>1410</integer>\n        </dict>\n        <key>DeadPeerDetectionRate</key>\n        <string>Medium</string>\n        <key>DisableRedirect</key>\n        <true/>\n        <key>EnableCertificateRevocationCheck</key>\n        <integer>0</integer>\n        <key>EnablePFS</key>\n        <integer>0</integer>\n        <key>IKESecurityAssociationParameters</key>\n        <dict>\n          <key>DiffieHellmanGroup</key>\n          <integer>19</integer>\n          <key>EncryptionAlgorithm</key>\n          <string>AES-256-GCM</string>\n          <key>IntegrityAlgorithm</key>\n          <string>SHA2-256</string>\n          <key>LifeTimeInMinutes</key>\n          <integer>1410</integer>\n        </dict>\n        <key>LocalIdentifier</key>\n        <string>$client_name</string>\n        <key>PayloadCertificateUUID</key>\n        <string>$uuid1</string>\n        <key>OnDemandEnabled</key>\n        <integer>0</integer>\n        <key>OnDemandRules</key>\n        <array>\n          <dict>\n            <key>InterfaceTypeMatch</key>\n            <string>WiFi</string>\n            <key>URLStringProbe</key>\n            <string>http://captive.apple.com/hotspot-detect.html</string>\n            <key>Action</key>\n            <string>Connect</string>\n          </dict>\n          <dict>\n            <key>InterfaceTypeMatch</key>\n            <string>Cellular</string>\n            <key>Action</key>\n            <string>Disconnect</string>\n          </dict>\n          <dict>\n            <key>Action</key>\n            <string>Ignore</string>\n          </dict>\n        </array>\n        <key>RemoteAddress</key>\n        <string>$server_addr</string>\n        <key>RemoteIdentifier</key>\n        <string>$server_addr</string>\n        <key>UseConfigurationAttributeInternalIPSubnet</key>\n        <integer>0</integer>\n      </dict>\n      <key>IPv4</key>\n      <dict>\n        <key>OverridePrimary</key>\n        <integer>1</integer>\n      </dict>\n      <key>PayloadDescription</key>\n      <string>Configures VPN settings</string>\n      <key>PayloadDisplayName</key>\n      <string>VPN</string>\n      <key>PayloadOrganization</key>\n      <string>IKEv2 VPN</string>\n      <key>PayloadIdentifier</key>\n      <string>com.apple.vpn.managed.$(uuidgen)</string>\n      <key>PayloadType</key>\n      <string>com.apple.vpn.managed</string>\n      <key>PayloadUUID</key>\n      <string>$(uuidgen)</string>\n      <key>PayloadVersion</key>\n      <integer>1</integer>\n      <key>Proxies</key>\n      <dict>\n        <key>HTTPEnable</key>\n        <integer>0</integer>\n        <key>HTTPSEnable</key>\n        <integer>0</integer>\n      </dict>\n      <key>UserDefinedName</key>\n      <string>$server_addr</string>\n      <key>VPNType</key>\n      <string>IKEv2</string>\n    </dict>\n    <dict>\nEOF\n  if [ \"$use_config_password\" = 0 ]; then\ncat >> \"$mc_file\" <<EOF\n      <key>Password</key>\n      <string>$p12_password</string>\nEOF\n  fi\ncat >> \"$mc_file\" <<EOF\n      <key>PayloadCertificateFileName</key>\n      <string>$client_name</string>\n      <key>PayloadContent</key>\n      <data>\n$p12_base64\n      </data>\n      <key>PayloadDescription</key>\n      <string>Adds a PKCS#12-formatted certificate</string>\n      <key>PayloadDisplayName</key>\n      <string>$client_name</string>\n      <key>PayloadIdentifier</key>\n      <string>com.apple.security.pkcs12.$(uuidgen)</string>\n      <key>PayloadType</key>\n      <string>com.apple.security.pkcs12</string>\n      <key>PayloadUUID</key>\n      <string>$uuid1</string>\n      <key>PayloadVersion</key>\n      <integer>1</integer>\n    </dict>\n    <dict>\n      <key>PayloadContent</key>\n      <data>\n$ca_base64\n      </data>\n      <key>PayloadCertificateFileName</key>\n      <string>ikev2vpnca</string>\n      <key>PayloadDescription</key>\n      <string>Adds a CA root certificate</string>\n      <key>PayloadDisplayName</key>\n      <string>Certificate Authority (CA)</string>\n      <key>PayloadIdentifier</key>\n      <string>com.apple.security.root.$(uuidgen)</string>\n      <key>PayloadType</key>\n      <string>com.apple.security.root</string>\n      <key>PayloadUUID</key>\n      <string>$(uuidgen)</string>\n      <key>PayloadVersion</key>\n      <integer>1</integer>\n    </dict>\n  </array>\n  <key>PayloadDisplayName</key>\n  <string>IKEv2 VPN $server_addr</string>\n  <key>PayloadIdentifier</key>\n  <string>com.apple.vpn.managed.$(uuidgen)</string>\n  <key>PayloadRemovalDisallowed</key>\n  <false/>\n  <key>PayloadType</key>\n  <string>Configuration</string>\n  <key>PayloadUUID</key>\n  <string>$(uuidgen)</string>\n  <key>PayloadVersion</key>\n  <integer>1</integer>\n</dict>\n</plist>\nEOF\n  if [ \"$export_to_home_dir\" = 1 ]; then\n    chown \"$SUDO_USER:$SUDO_USER\" \"$mc_file\"\n  fi\n  chmod 600 \"$mc_file\"\n}\n\ncreate_android_profile() {\n  [ -z \"$server_addr\" ] && get_server_address\n  p12_base64_oneline=$(base64 -w 52 \"$export_dir$client_name.p12\" | sed 's/$/\\\\n/' | tr -d '\\n')\n  [ -z \"$p12_base64_oneline\" ] && exiterr \"Could not encode .p12 file.\"\n  uuid2=$(uuidgen)\n  [ -z \"$uuid2\" ] && exiterr \"Could not generate UUID value.\"\n  sswan_file=\"$export_dir$client_name.sswan\"\ncat > \"$sswan_file\" <<EOF\n{\n  \"uuid\": \"$uuid2\",\n  \"name\": \"IKEv2 VPN $server_addr\",\n  \"type\": \"ikev2-cert\",\n  \"remote\": {\n    \"addr\": \"$server_addr\"\n  },\n  \"local\": {\n    \"p12\": \"$p12_base64_oneline\",\n    \"rsa-pss\": \"true\"\n  },\n  \"ike-proposal\": \"aes256-sha256-modp2048\",\n  \"esp-proposal\": \"aes128gcm16\"\n}\nEOF\n  if [ \"$export_to_home_dir\" = 1 ]; then\n    chown \"$SUDO_USER:$SUDO_USER\" \"$sswan_file\"\n  fi\n  chmod 600 \"$sswan_file\"\n}\n\nexport_client_config() {\n  if [ \"$os_type\" != \"alpine\" ]; then\n    install_base64_uuidgen\n  else\n    install_uuidgen\n  fi\n  update_ikev2_conf\n  export_p12_file\n  create_mobileconfig\n  create_android_profile\n}\n\ncreate_ca_server_certs() {\n  bigecho2 \"Generating CA and server certificates...\"\n  certutil -z <(head -c 1024 /dev/urandom) \\\n    -S -x -n \"$CA_NAME\" \\\n    -s \"O=IKEv2 VPN,CN=$CA_NAME\" \\\n    -k rsa -g 3072 -v 120 \\\n    -d \"$CERT_DB\" -t \"CT,,\" -2 >/dev/null 2>&1 <<ANSWERS || exiterr \"Failed to create CA certificate.\"\ny\n\nN\nANSWERS\n  sleep 1\n  if [ \"$use_dns_name\" = 1 ]; then\n    certutil -z <(head -c 1024 /dev/urandom) \\\n      -S -c \"$CA_NAME\" -n \"$server_addr\" \\\n      -s \"O=IKEv2 VPN,CN=$server_addr\" \\\n      -k rsa -g 3072 -v 120 \\\n      -d \"$CERT_DB\" -t \",,\" \\\n      --keyUsage digitalSignature,keyEncipherment \\\n      --extKeyUsage serverAuth \\\n      --extSAN \"dns:$server_addr\" >/dev/null 2>&1 || exiterr \"Failed to create server certificate.\"\n  else\n    certutil -z <(head -c 1024 /dev/urandom) \\\n      -S -c \"$CA_NAME\" -n \"$server_addr\" \\\n      -s \"O=IKEv2 VPN,CN=$server_addr\" \\\n      -k rsa -g 3072 -v 120 \\\n      -d \"$CERT_DB\" -t \",,\" \\\n      --keyUsage digitalSignature,keyEncipherment \\\n      --extKeyUsage serverAuth \\\n      --extSAN \"ip:$server_addr,dns:$server_addr\" >/dev/null 2>&1 || exiterr \"Failed to create server certificate.\"\n  fi\n}\n\ncreate_config_readme() {\n  readme_file=\"$export_dir$client_name-README.txt\"\n  if [ \"$in_container\" = 0 ] && [ \"$use_config_password\" = 0 ] \\\n    && [ \"$use_defaults\" = 1 ] && [ ! -t 1 ] && [ ! -f \"$readme_file\" ]; then\ncat > \"$readme_file\" <<'EOF'\nThese IKEv2 client config files were created during IPsec VPN setup.\nTo configure IKEv2 clients, see: https://vpnsetup.net/clients\nEOF\n    if [ \"$export_to_home_dir\" = 1 ]; then\n      chown \"$SUDO_USER:$SUDO_USER\" \"$readme_file\"\n    fi\n    chmod 600 \"$readme_file\"\n  fi\n}\n\nadd_ikev2_connection() {\n  bigecho2 \"Adding a new IKEv2 connection...\"\n  XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\n  IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n  IP6_PREFIX=$(printf '%s' \"$IP6_NET\" | sed 's|/[0-9]*$||; s|::$||')\n  lsubnet=\"0.0.0.0/0\"\n  rpool=\"$XAUTH_POOL\"\n  if [ -n \"$VPN_PUBLIC_IP6\" ]; then\n    lsubnet=\"0.0.0.0/0,::/0\"\n    rpool=\"$XAUTH_POOL,${IP6_PREFIX}::1000-${IP6_PREFIX}::1fff\"\n  fi\n  if ! grep -qs '^include /etc/ipsec\\.d/\\*\\.conf$' \"$IPSEC_CONF\"; then\n    echo >> \"$IPSEC_CONF\"\n    echo 'include /etc/ipsec.d/*.conf' >> \"$IPSEC_CONF\"\n  fi\ncat > \"$IKEV2_CONF\" <<EOF\n\nconn ikev2-cp\n  left=%defaultroute\n  leftcert=$server_addr\n  leftsendcert=always\n  leftsubnet=$lsubnet\n  leftrsasigkey=%cert\n  right=%any\n  rightid=%fromcert\n  rightaddresspool=$rpool\n  rightca=%same\n  rightrsasigkey=%cert\n  narrowing=yes\n  dpddelay=30\n  retransmit-timeout=300s\n  auto=add\n  ikev2=insist\n  rekey=no\n  pfs=no\n  ike=aes_gcm_c_256-hmac_sha2_256-ecp_256,aes256-sha2,aes128-sha2,aes256-sha1,aes128-sha1\n  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2\n  ikelifetime=24h\n  salifetime=24h\n  encapsulation=yes\nEOF\n  if [ \"$use_dns_name\" = 1 ]; then\ncat >> \"$IKEV2_CONF\" <<EOF\n  leftid=@$server_addr\nEOF\n  else\ncat >> \"$IKEV2_CONF\" <<EOF\n  leftid=$server_addr\nEOF\n  fi\n  if [ -n \"$dns_server_2\" ]; then\ncat >> \"$IKEV2_CONF\" <<EOF\n  modecfgdns=\"$dns_servers\"\nEOF\n  else\ncat >> \"$IKEV2_CONF\" <<EOF\n  modecfgdns=$dns_server_1\nEOF\n  fi\n  if [ \"$mobike_enable\" = 1 ]; then\n    echo \"  mobike=yes\" >> \"$IKEV2_CONF\"\n  else\n    echo \"  mobike=no\" >> \"$IKEV2_CONF\"\n  fi\n}\n\nrestart_ipsec_service() {\n  if [ \"$in_container\" = 0 ] || { [ \"$in_container\" = 1 ] && service ipsec status >/dev/null 2>&1; }; then\n    bigecho2 \"Restarting IPsec service...\"\n    mkdir -p /run/pluto\n    service ipsec restart 2>/dev/null\n  fi\n}\n\ncheck_ikev2_connection() {\n  if grep -qs 'mobike=yes' \"$IKEV2_CONF\"; then\n    (sleep 3\n    if ! ipsec status | grep -q ikev2-cp; then\n      sed -i '/mobike=yes/s/yes/no/' \"$IKEV2_CONF\"\n      if [ \"$os_type\" = \"alpine\" ]; then\n        ipsec auto --add ikev2-cp >/dev/null\n      else\n        restart_ipsec_service >/dev/null\n      fi\n    fi) >/dev/null 2>&1 &\n  fi\n}\n\ncreate_crl() {\n  bigecho \"Revoking client certificate...\"\n  if ! crlutil -L -d \"$CERT_DB\" -n \"$CA_NAME\" >/dev/null 2>&1; then\n    crlutil -G -d \"$CERT_DB\" -n \"$CA_NAME\" -c /dev/null >/dev/null\n  fi\n  sleep 2\n}\n\nadd_client_cert_to_crl() {\n  sn_txt=$(certutil -L -d \"$CERT_DB\" -n \"$client_name\" | grep -A 1 'Serial Number' | tail -n 1)\n  sn_hex=$(printf '%s' \"$sn_txt\" | sed -e 's/^ *//' -e 's/://g')\n  sn_dec=$((16#$sn_hex))\n  [ -z \"$sn_dec\" ] && exiterr \"Could not find serial number of client certificate.\"\ncrlutil -M -d \"$CERT_DB\" -n \"$CA_NAME\" >/dev/null <<EOF || exiterr \"Failed to add client certificate to CRL.\"\naddcert $sn_dec $(date -u +%Y%m%d%H%M%SZ)\nEOF\n}\n\nreload_crls() {\n  ipsec crls\n}\n\ndelete_client_cert() {\n  bigecho \"Deleting client certificate...\"\n  certutil -F -d \"$CERT_DB\" -n \"$client_name\"\n  certutil -D -d \"$CERT_DB\" -n \"$client_name\" 2>/dev/null\n}\n\nremove_client_config() {\n  p12_file=\"$export_dir$client_name.p12\"\n  mc_file=\"$export_dir$client_name.mobileconfig\"\n  sswan_file=\"$export_dir$client_name.sswan\"\n  if [ -f \"$p12_file\" ] || [ -f \"$mc_file\" ] || [ -f \"$sswan_file\" ]; then\n    bigecho \"Removing client config files...\"\n    if [ -f \"$p12_file\" ]; then\n      printf '%s\\n' \"$p12_file\"\n      /bin/rm -f \"$p12_file\"\n    fi\n    if [ -f \"$mc_file\" ]; then\n      printf '%s\\n' \"$mc_file\"\n      /bin/rm -f \"$mc_file\"\n    fi\n    if [ -f \"$sswan_file\" ]; then\n      printf '%s\\n' \"$sswan_file\"\n      /bin/rm -f \"$sswan_file\"\n    fi\n  fi\n}\n\nprint_client_added() {\ncat <<EOF\n\n\n================================================\n\nNew IKEv2 client \"$client_name\" added!\n\nEOF\n  print_server_info\n}\n\nprint_client_exported() {\ncat <<EOF\n\n\n================================================\n\nIKEv2 client \"$client_name\" exported!\n\nEOF\n  print_server_info\n}\n\nprint_client_revoked() {\n  echo\n  echo \"Client '$client_name' revoked!\"\n}\n\nprint_client_deleted() {\n  echo\n  echo \"Client '$client_name' deleted!\"\n}\n\nprint_setup_complete() {\n  printf '\\e[2K\\e[1A\\e[2K\\r'\n  [ \"$use_defaults\" = 1 ] && printf '\\e[1A\\e[2K\\e[1A\\e[2K\\e[1A\\e[2K\\r'\ncat <<EOF\n================================================\n\nIKEv2 setup successful. Details for IKEv2 mode:\n\nVPN server address: $server_addr\nVPN client name: $client_name\n\nEOF\n}\n\nprint_client_info() {\n  if [ \"$in_container\" = 0 ]; then\ncat <<'EOF'\nClient configuration is available at:\nEOF\n  else\ncat <<'EOF'\nClient configuration is available inside the\nDocker container at:\nEOF\n  fi\ncat <<EOF\n$export_dir$client_name.p12 (for Windows & Linux)\n$export_dir$client_name.sswan (for Android)\n$export_dir$client_name.mobileconfig (for iOS & macOS)\nEOF\n  if [ \"$use_config_password\" = 1 ]; then\ncat <<EOF\n\n*IMPORTANT* Password for client config files:\n$p12_password\nWrite this down, you'll need it for import!\nEOF\n  fi\n  config_url=\"https://vpnsetup.net/clients\"\n  if [ \"$in_container\" = 1 ]; then\n    config_url=\"${config_url}2\"\n  fi\ncat <<EOF\n\nNext steps: Configure IKEv2 clients. See:\n$config_url\n\n================================================\n\nEOF\n}\n\ncheck_swan_update() {\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$' \\\n    && [ -n \"$swan_ver\" ] && [ \"$swan_ver\" != \"$swan_ver_latest\" ] \\\n    && printf '%s\\n%s' \"$swan_ver\" \"$swan_ver_latest\" | sort -C -V; then\ncat <<EOF\nNote: A newer version of Libreswan ($swan_ver_latest) is available.\n      To update, run:\n      wget https://get.vpnsetup.net/upg -O vpnup.sh && sudo sh vpnup.sh\n\nEOF\n  fi\n}\n\ncheck_ipsec_conf() {\n  if grep -qs \"conn ikev2-cp\" \"$IPSEC_CONF\"; then\ncat 1>&2 <<EOF\nError: IKEv2 configuration section found in $IPSEC_CONF.\n       This script cannot automatically remove IKEv2 from this server.\n       To manually remove IKEv2, see https://vpnsetup.net/ikev2\nEOF\n    abort_and_exit\n  fi\n  if grep -qs \"ikev1-policy=drop\" \"$IPSEC_CONF\" \\\n    || grep -qs \"ikev1-policy=reject\" \"$IPSEC_CONF\"; then\ncat 1>&2 <<EOF\nError: IKEv2-only mode is currently enabled on this VPN server.\n       You must first disable IKEv2-only mode before removing IKEv2.\n       Otherwise, you will NOT be able to connect to this VPN server.\nEOF\n    abort_and_exit\n  fi\n}\n\nconfirm_revoke_cert() {\ncat <<EOF\nWARNING: You have selected to revoke IKEv2 client certificate '$client_name'.\n         After revocation, this certificate *cannot* be used by VPN client(s)\n         to connect to this VPN server.\n\nEOF\n  if [ \"$assume_yes\" != 1 ]; then\n    confirm_or_abort \"Are you sure you want to revoke '$client_name'? [y/N] \"\n  fi\n}\n\nconfirm_delete_cert() {\ncat <<EOF\nWARNING: Deleting a client certificate from the IPsec database *WILL NOT* prevent\n         VPN client(s) from connecting using that certificate! For this use case,\n         you *MUST* revoke the client certificate instead of deleting it.\n         This *cannot* be undone!\n\nEOF\n  if [ \"$assume_yes\" != 1 ]; then\n    confirm_or_abort \"Are you sure you want to delete '$client_name'? [y/N] \"\n  fi\n}\n\nconfirm_remove_ikev2() {\ncat <<'EOF'\nWARNING: This option will remove IKEv2 from this VPN server, but keep the IPsec/L2TP\n         and IPsec/XAuth (\"Cisco IPsec\") modes, if installed. All IKEv2 configuration\n         including certificates and keys will be *permanently deleted*.\n         This *cannot* be undone!\n\nEOF\n  if [ \"$assume_yes\" != 1 ]; then\n    confirm_or_abort \"Are you sure you want to remove IKEv2? [y/N] \"\n  fi\n}\n\ndelete_ikev2_conf() {\n  bigecho \"Deleting $IKEV2_CONF...\"\n  /bin/rm -f \"$IKEV2_CONF\"\n}\n\ndelete_certificates() {\n  echo\n  bigecho \"Deleting certificates and keys from the IPsec database...\"\n  cert_list=$(certutil -L -d \"$CERT_DB\" | grep -v -e '^$' -e \"$CA_NAME\" | tail -n +3 | cut -f1 -d ' ')\n  while IFS= read -r line; do\n    certutil -F -d \"$CERT_DB\" -n \"$line\"\n    certutil -D -d \"$CERT_DB\" -n \"$line\" 2>/dev/null\n  done <<< \"$cert_list\"\n  crlutil -D -d \"$CERT_DB\" -n \"$CA_NAME\" 2>/dev/null\n  certutil -F -d \"$CERT_DB\" -n \"$CA_NAME\"\n  certutil -D -d \"$CERT_DB\" -n \"$CA_NAME\" 2>/dev/null\n  if grep -qs '^IKEV2_CONFIG_PASSWORD=.\\+' \"$CONF_FILE\"; then\n    sed -i '/IKEV2_CONFIG_PASSWORD=/d' \"$CONF_FILE\"\n  fi\n}\n\nprint_ikev2_removed() {\n  echo\n  echo \"IKEv2 removed!\"\n}\n\nikev2setup() {\n  check_root\n  check_container\n  check_os\n  check_libreswan\n  check_swan_ver\n  check_utils_exist\n\n  use_defaults=0\n  assume_yes=0\n  add_client=0\n  export_client=0\n  list_clients=0\n  revoke_client=0\n  delete_client=0\n  remove_ikev2=0\n\n  while [ \"$#\" -gt 0 ]; do\n    case $1 in\n      --auto)\n        use_defaults=1\n        shift\n        ;;\n      --addclient)\n        add_client=1\n        client_name=\"$2\"\n        shift\n        shift\n        ;;\n      --exportclient)\n        export_client=1\n        client_name=\"$2\"\n        shift\n        shift\n        ;;\n      --listclients)\n        list_clients=1\n        shift\n        ;;\n      --revokeclient)\n        revoke_client=1\n        client_name=\"$2\"\n        shift\n        shift\n        ;;\n      --deleteclient)\n        delete_client=1\n        client_name=\"$2\"\n        shift\n        shift\n        ;;\n      --removeikev2)\n        remove_ikev2=1\n        shift\n        ;;\n      -y|--yes)\n        assume_yes=1\n        shift\n        ;;\n      -h|--help)\n        show_usage\n        ;;\n      *)\n        show_usage \"Unknown parameter: $1\"\n        ;;\n    esac\n  done\n\n  CA_NAME=\"IKEv2 VPN CA\"\n  CERT_DB=\"sql:/etc/ipsec.d\"\n  CONF_DIR=\"/etc/ipsec.d\"\n  CONF_FILE=\"/etc/ipsec.d/.vpnconfig\"\n  IKEV2_CONF=\"/etc/ipsec.d/ikev2.conf\"\n  IPSEC_CONF=\"/etc/ipsec.conf\"\n\n  check_arguments\n  check_config_password\n  get_export_dir\n\n  if [ \"$add_client\" = 1 ]; then\n    check_and_set_client_validity\n    show_header\n    show_add_client\n    create_client_cert\n    export_client_config\n    print_client_added\n    print_client_info\n    exit 0\n  fi\n\n  if [ \"$export_client\" = 1 ]; then\n    show_header\n    show_export_client\n    export_client_config\n    print_client_exported\n    print_client_info\n    exit 0\n  fi\n\n  if [ \"$list_clients\" = 1 ]; then\n    show_header\n    list_existing_clients\n    echo\n    exit 0\n  fi\n\n  if [ \"$revoke_client\" = 1 ]; then\n    show_header\n    confirm_revoke_cert\n    create_crl\n    add_client_cert_to_crl\n    reload_crls\n    remove_client_config\n    print_client_revoked\n    exit 0\n  fi\n\n  if [ \"$delete_client\" = 1 ]; then\n    show_header\n    confirm_delete_cert\n    delete_client_cert\n    remove_client_config\n    print_client_deleted\n    exit 0\n  fi\n\n  if [ \"$remove_ikev2\" = 1 ]; then\n    check_ipsec_conf\n    show_header\n    confirm_remove_ikev2\n    delete_ikev2_conf\n    if [ \"$os_type\" = \"alpine\" ]; then\n      ipsec auto --delete ikev2-cp\n    else\n      restart_ipsec_service\n    fi\n    delete_certificates\n    print_ikev2_removed\n    exit 0\n  fi\n\n  if check_ikev2_exists; then\n    show_header\n    select_menu_option\n    case $selected_option in\n      1)\n        enter_client_name\n        enter_client_validity\n        echo\n        create_client_cert\n        export_client_config\n        print_client_added\n        print_client_info\n        exit 0\n        ;;\n      2)\n        enter_client_name_for export\n        echo\n        export_client_config\n        print_client_exported\n        print_client_info\n        exit 0\n        ;;\n      3)\n        echo\n        list_existing_clients\n        echo\n        exit 0\n        ;;\n      4)\n        enter_client_name_for revoke\n        echo\n        confirm_revoke_cert\n        create_crl\n        add_client_cert_to_crl\n        reload_crls\n        remove_client_config\n        print_client_revoked\n        exit 0\n        ;;\n      5)\n        enter_client_name_for delete\n        echo\n        confirm_delete_cert\n        delete_client_cert\n        remove_client_config\n        print_client_deleted\n        exit 0\n        ;;\n      6)\n        check_ipsec_conf\n        echo\n        confirm_remove_ikev2\n        delete_ikev2_conf\n        if [ \"$os_type\" = \"alpine\" ]; then\n          ipsec auto --delete ikev2-cp\n        else\n          restart_ipsec_service\n        fi\n        delete_certificates\n        print_ikev2_removed\n        exit 0\n        ;;\n      *)\n        exit 0\n        ;;\n    esac\n  fi\n\n  check_cert_exists_and_exit \"$CA_NAME\"\n\n  if [ \"$use_defaults\" = 0 ]; then\n    show_header\n    show_welcome\n    enter_server_address\n    check_cert_exists_and_exit \"$server_addr\"\n    enter_client_name with_defaults\n    enter_client_validity\n    enter_custom_dns\n    check_mobike_support\n    select_mobike\n    select_config_password\n    confirm_setup_options\n  else\n    check_server_dns_name\n    check_custom_dns\n    check_and_set_client_name\n    check_and_set_client_validity\n    show_header\n    show_start_setup\n    set_server_address\n    set_dns_servers\n    check_mobike_support\n    mobike_enable=\"$mobike_support\"\n  fi\n\n  create_ca_server_certs\n  create_client_cert\n  export_client_config\n  create_config_readme\n  add_ikev2_connection\n  if [ \"$os_type\" = \"alpine\" ]; then\n    ipsec auto --add ikev2-cp >/dev/null\n  else\n    restart_ipsec_service\n  fi\n  check_ikev2_connection\n  print_setup_complete\n  print_client_info\n  if [ \"$in_container\" = 0 ]; then\n    check_swan_update\n  fi\n}\n\n## Defer setup until we have the complete script\nikev2setup \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/update_vpn_users.sh",
    "content": "#!/bin/bash\n#\n# Script to update VPN users for both IPsec/L2TP and Cisco IPsec\n#\n# Copyright (C) 2018-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - List of VPN usernames and passwords, separated by spaces\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_USERNAMES=''\nYOUR_PASSWORDS=''\n\n# Example:\n# YOUR_USERNAMES='username1 username2'\n# YOUR_PASSWORDS='password1 password2'\n\n# WARNING: *ALL* existing VPN users will be removed\n#          and replaced with the users listed here.\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nonespace() { printf '%s' \"$1\" | tr -s ' '; }\nnoquotes() { printf '%s' \"$1\" | sed -e 's/^\"\\(.*\\)\"$/\\1/' -e \"s/^'\\(.*\\)'$/\\1/\"; }\nnoquotes2() { printf '%s' \"$1\" | sed -e 's/\" \"/ /g' -e \"s/' '/ /g\"; }\n\nupdate_vpn_users() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf \\\n    || [ ! -f /etc/ppp/chap-secrets ] || [ ! -f /etc/ipsec.d/passwd ]; then\ncat 1>&2 <<'EOF'\nError: Your must first set up the IPsec VPN server before updating VPN users.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n  command -v openssl >/dev/null 2>&1 || exiterr \"'openssl' not found. Abort.\"\n  if [ \"$1\" = \"-h\" ] || [ \"$1\" = \"--help\" ]; then\ncat 1>&2 <<'EOF'\nFor usage information, visit https://github.com/hwdsl2/setup-ipsec-vpn,\nthen click on Manage VPN Users.\nEOF\n    exit 1\n  fi\n  [ -n \"$YOUR_USERNAMES\" ] && VPN_USERS=\"$YOUR_USERNAMES\"\n  [ -n \"$YOUR_PASSWORDS\" ] && VPN_PASSWORDS=\"$YOUR_PASSWORDS\"\n  VPN_USERS=$(noquotes \"$VPN_USERS\")\n  VPN_USERS=$(onespace \"$VPN_USERS\")\n  VPN_USERS=$(noquotes2 \"$VPN_USERS\")\n  VPN_PASSWORDS=$(noquotes \"$VPN_PASSWORDS\")\n  VPN_PASSWORDS=$(onespace \"$VPN_PASSWORDS\")\n  VPN_PASSWORDS=$(noquotes2 \"$VPN_PASSWORDS\")\n  if [ -z \"$VPN_USERS\" ] || [ -z \"$VPN_PASSWORDS\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_USERS $VPN_PASSWORDS\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_USERS $VPN_PASSWORDS\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n  if printf '%s' \"$VPN_USERS\" | tr ' ' '\\n' | sort | uniq -c | grep -qv '^ *1 '; then\n    exiterr \"VPN usernames must not contain duplicates.\"\n  fi\ncat <<'EOF'\n\nWelcome! Use this script to update VPN user accounts for both\nIPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nWARNING: *ALL* existing VPN users will be removed and replaced\n         with the users listed below.\n\n==================================================\n\nUpdated list of VPN users (username | password):\n\nEOF\n  count=1\n  vpn_user=$(printf '%s' \"$VPN_USERS\" | cut -d ' ' -f 1)\n  vpn_password=$(printf '%s' \"$VPN_PASSWORDS\" | cut -d ' ' -f 1)\n  while [ -n \"$vpn_user\" ] && [ -n \"$vpn_password\" ]; do\ncat <<EOF\n$vpn_user | $vpn_password\nEOF\n    count=$((count+1))\n    vpn_user=$(printf '%s' \"$VPN_USERS\" | cut -s -d ' ' -f \"$count\")\n    vpn_password=$(printf '%s' \"$VPN_PASSWORDS\" | cut -s -d ' ' -f \"$count\")\n  done\ncat <<'EOF'\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n==================================================\n\nEOF\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      echo \"Updating VPN users...\"\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n  # Backup and remove config files\n  conf_bk \"/etc/ppp/chap-secrets\"\n  conf_bk \"/etc/ipsec.d/passwd\"\n  /bin/rm -f /etc/ppp/chap-secrets /etc/ipsec.d/passwd\n  # Update VPN users\n  count=1\n  vpn_user=$(printf '%s' \"$VPN_USERS\" | cut -d ' ' -f 1)\n  vpn_password=$(printf '%s' \"$VPN_PASSWORDS\" | cut -d ' ' -f 1)\n  while [ -n \"$vpn_user\" ] && [ -n \"$vpn_password\" ]; do\n    vpn_password_enc=$(openssl passwd -1 \"$vpn_password\")\ncat >> /etc/ppp/chap-secrets <<EOF\n\"$vpn_user\" l2tpd \"$vpn_password\" *\nEOF\ncat >> /etc/ipsec.d/passwd <<EOF\n$vpn_user:$vpn_password_enc:xauth-psk\nEOF\n    count=$((count+1))\n    vpn_user=$(printf '%s' \"$VPN_USERS\" | cut -s -d ' ' -f \"$count\")\n    vpn_password=$(printf '%s' \"$VPN_PASSWORDS\" | cut -s -d ' ' -f \"$count\")\n  done\n  # Update file attributes\n  chmod 600 /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\ncat <<'EOF'\nDone!\n\nNote: All VPN users will share the same IPsec PSK.\n      If you forgot the PSK, check /etc/ipsec.secrets.\n\nEOF\n}\n\n## Defer until we have the complete script\nupdate_vpn_users \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/vpnuninstall.sh",
    "content": "#!/bin/bash\n#\n# Script to uninstall IPsec VPN\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2021-2024 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nbigecho() { echo \"## $1\"; }\n\ncheck_cidr() {\n  CIDR_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(/(3[0-2]|[1-2][0-9]|[0-9]))$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$CIDR_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if ! grep -q -E \"release (7|8|9|10)\" \"$rh_file\"; then\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n  elif grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    os_type=amzn\n  else\n    os_type=$(lsb_release -si 2>/dev/null)\n    [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n    case $os_type in\n      [Uu]buntu)\n        os_type=ubuntu\n        ;;\n      [Dd]ebian|[Kk]ali|[Rr]aspbian)\n        os_type=debian\n        ;;\n      [Aa]lpine)\n        os_type=alpine\n        ;;\n      *)\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       Ubuntu, Debian, CentOS/RHEL, Rocky Linux, AlmaLinux,\n       Oracle Linux, Amazon Linux 2 or Alpine Linux\nEOF\n        exit 1\n        ;;\n    esac\n  fi\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(ipsec --version 2>/dev/null)\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf \\\n    || ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\n    exiterr \"Cannot remove IPsec VPN because it has not been set up on this server.\"\n  fi\n}\n\ncheck_iface() {\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  if [ \"$os_type\" != \"alpine\" ]; then\n    [ -z \"$def_iface\" ] && def_iface=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n  fi\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    check_wl=0\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n      if ! uname -m | grep -qi -e '^arm' -e '^aarch64'; then\n        check_wl=1\n      fi\n    else\n      check_wl=1\n    fi\n    if [ \"$check_wl\" = 1 ]; then\n      case $def_iface in\n        wl*)\n          exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n          ;;\n      esac\n    fi\n    NET_IFACE=\"$def_iface\"\n  else\n    eth0_state=$(cat \"/sys/class/net/eth0/operstate\" 2>/dev/null)\n    if [ -z \"$eth0_state\" ] || [ \"$eth0_state\" = \"down\" ]; then\n      exiterr \"Could not detect the default network interface.\"\n    fi\n    NET_IFACE=eth0\n  fi\n}\n\nabort_and_exit() {\n  echo \"Abort. No changes were made.\" >&2\n  exit 1\n}\n\nconfirm_or_abort() {\n  printf '%s' \"$1\"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY])\n      echo\n      ;;\n    *)\n      abort_and_exit\n      ;;\n  esac\n}\n\nconfirm_remove() {\ncat <<'EOF'\n\nWARNING: This script will remove IPsec VPN from this server. All VPN configuration\n         will be *permanently deleted*, and Libreswan and xl2tpd will be removed.\n         This *cannot* be undone!\n\nEOF\n  confirm_or_abort \"Are you sure you want to remove the VPN? [y/N] \"\n}\n\nstop_services() {\n  bigecho \"Stopping services...\"\n  service ipsec stop\n  service xl2tpd stop\n}\n\nremove_ipsec() {\n  bigecho \"Removing IPsec...\"\n  /bin/rm -rf /usr/local/sbin/ipsec /usr/local/libexec/ipsec /usr/local/share/doc/libreswan\n  /bin/rm -f /etc/init/ipsec.conf /lib/systemd/system/ipsec.service /etc/init.d/ipsec \\\n    /usr/lib/systemd/system/ipsec.service /etc/logrotate.d/libreswan \\\n    /usr/lib/tmpfiles.d/libreswan.conf\n}\n\nremove_xl2tpd() {\n  bigecho \"Removing xl2tpd...\"\n  if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n    export DEBIAN_FRONTEND=noninteractive\n    apt-get -yqq purge xl2tpd >/dev/null\n  elif [ \"$os_type\" = \"alpine\" ]; then\n    apk del -q xl2tpd\n  else\n    yum -y -q remove xl2tpd >/dev/null\n  fi\n}\n\nremove_helper_scripts() {\n  bigecho \"Removing helper scripts...\"\n  for sc in ikev2.sh addvpnuser.sh delvpnuser.sh; do\n    if [ \"$(readlink -f \"/usr/bin/$sc\" 2>/dev/null)\" = \"/opt/src/$sc\" ]; then\n      /bin/rm -f \"/usr/bin/$sc\" \"/opt/src/$sc\"\n    fi\n  done\n}\n\nupdate_sysctl() {\n  if grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    bigecho \"Updating sysctl settings...\"\n    conf_bk \"/etc/sysctl.conf\"\n    count=17\n    line1=$(grep -A 18 \"hwdsl2 VPN script\" /etc/sysctl.conf | tail -n 1)\n    line2=$(grep -A 19 \"hwdsl2 VPN script\" /etc/sysctl.conf | tail -n 1)\n    line3=$(grep -A 20 \"hwdsl2 VPN script\" /etc/sysctl.conf | tail -n 1)\n    if [ \"$line1\" = \"net.core.default_qdisc = fq\" ] \\\n      && [ \"$line2\" = \"net.ipv4.tcp_congestion_control = bbr\" ]; then\n      count=19\n      if [ \"$line3\" = \"net.ipv6.conf.all.forwarding = 1\" ]; then\n        count=20\n      fi\n    elif [ \"$line1\" = \"net.ipv6.conf.all.forwarding = 1\" ]; then\n      count=18\n    fi\n    if [ \"$os_type\" = \"alpine\" ]; then\n      sed -i \"/# Added by hwdsl2 VPN script/,+${count}d\" /etc/sysctl.conf\n    else\n      sed --follow-symlinks -i \"/# Added by hwdsl2 VPN script/,+${count}d\" /etc/sysctl.conf\n    fi\n    if [ ! -f /usr/bin/wg-quick ] && [ ! -f /usr/sbin/openvpn ]; then\n      echo 0 > /proc/sys/net/ipv4/ip_forward\n    fi\n    echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter\n  fi\n}\n\nupdate_rclocal() {\n  if grep -qs \"hwdsl2 VPN script\" /etc/rc.local; then\n    bigecho \"Updating rc.local...\"\n    conf_bk \"/etc/rc.local\"\n    if [ \"$os_type\" = \"alpine\" ]; then\n      sed -i '/# Added by hwdsl2 VPN script/,/)&$/d' /etc/rc.local\n    else\n      sed --follow-symlinks -i '/# Added by hwdsl2 VPN script/,/)&$/d' /etc/rc.local\n    fi\n  fi\n}\n\nget_vpn_subnets() {\n  L2TP_NET=192.168.42.0/24\n  XAUTH_NET=192.168.43.0/24\n  if [ -s /etc/ipsec.conf ]; then\n    if ! grep -q \"$L2TP_NET\" /etc/ipsec.conf \\\n      || ! grep -q \"$XAUTH_NET\" /etc/ipsec.conf; then\n      vipr=$(grep \"virtual-private=\" /etc/ipsec.conf)\n      l2tpnet=$(printf '%s' \"$vipr\" | cut -f2 -d '!' | cut -f1 -d ',')\n      xauthnet=$(printf '%s' \"$vipr\" | cut -f3 -d '!' | cut -f1 -d ',')\n      check_cidr \"$l2tpnet\" && L2TP_NET=\"$l2tpnet\"\n      check_cidr \"$xauthnet\" && XAUTH_NET=\"$xauthnet\"\n    fi\n  fi\n}\n\nupdate_iptables_rules() {\n  use_nft=0\n  if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ] \\\n    || [ \"$os_type\" = \"alpine\" ]; then\n    IPT_FILE=/etc/iptables.rules\n    IPT_FILE2=/etc/iptables/rules.v4\n  else\n    IPT_FILE=/etc/sysconfig/iptables\n    if grep -qs \"hwdsl2 VPN script\" /etc/sysconfig/nftables.conf; then\n      use_nft=1\n      IPT_FILE=/etc/sysconfig/nftables.conf\n    fi\n  fi\n  ipt_flag=0\n  if grep -qs \"hwdsl2 VPN script\" \"$IPT_FILE\"; then\n    ipt_flag=1\n  fi\n  ipi='iptables -D INPUT'\n  ipf='iptables -D FORWARD'\n  ipp='iptables -t nat -D POSTROUTING'\n  res='RELATED,ESTABLISHED'\n  if [ \"$ipt_flag\" = 1 ]; then\n    if [ \"$use_nft\" = 0 ]; then\n      bigecho \"Updating IPTables rules...\"\n      get_vpn_subnets\n      iptables-save > \"$IPT_FILE.old-$SYS_DT\"\n      $ipi -p udp --dport 1701 -m policy --dir in --pol none -j DROP\n      $ipi -m conntrack --ctstate INVALID -j DROP\n      $ipi -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ipi -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ipi -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT\n      $ipi -p udp --dport 1701 -j DROP\n      $ipf -m conntrack --ctstate INVALID -j DROP\n      $ipf -i \"$NET_IFACE\" -o ppp+ -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ipf -i ppp+ -o \"$NET_IFACE\" -j ACCEPT\n      $ipf -i ppp+ -o ppp+ -j ACCEPT\n      $ipf -i \"$NET_IFACE\" -d \"$XAUTH_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ipf -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      $ipf -s \"$XAUTH_NET\" -o ppp+ -j ACCEPT\n      iptables -D FORWARD -j DROP\n      $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n      $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\n      iptables-save > \"$IPT_FILE\"\n      if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n        if [ -f \"$IPT_FILE2\" ]; then\n          conf_bk \"$IPT_FILE2\"\n          /bin/cp -f \"$IPT_FILE\" \"$IPT_FILE2\"\n        fi\n      fi\n      if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ] \\\n        || [ \"$os_type\" = \"alpine\" ]; then\n        IPT6_FILE=/etc/ip6tables.rules\n        IPT6_FILE2=/etc/iptables/rules.v6\n      else\n        IPT6_FILE=/etc/sysconfig/ip6tables\n        IPT6_FILE2=\"\"\n      fi\n      if grep -qs \"hwdsl2 VPN script\" \"$IPT6_FILE\" 2>/dev/null; then\n        IP6_NET=$(grep 'FORWARD.*-d ' \"$IPT6_FILE\" \\\n          | sed -n 's/.* -d \\([^ ]*\\).*/\\1/p' | head -n 1)\n        [ -z \"$IP6_NET\" ] && IP6_NET='fddd:500:500:500::/64'\n        ip6tables -D INPUT -m conntrack --ctstate INVALID -j DROP 2>/dev/null\n        ip6tables -D INPUT -m conntrack --ctstate \"$res\" -j ACCEPT 2>/dev/null\n        ip6tables -D INPUT -p udp -m multiport --dports 500,4500 -j ACCEPT 2>/dev/null\n        ip6tables -D FORWARD -m conntrack --ctstate INVALID -j DROP 2>/dev/null\n        ip6tables -D FORWARD -i \"$NET_IFACE\" -d \"$IP6_NET\" \\\n          -m conntrack --ctstate \"$res\" -j ACCEPT 2>/dev/null\n        ip6tables -D FORWARD -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT 2>/dev/null\n        ip6tables -t nat -D POSTROUTING -s \"$IP6_NET\" -o \"$NET_IFACE\" \\\n          -m policy --dir out --pol none -j MASQUERADE 2>/dev/null\n        /bin/rm -f \"$IPT6_FILE\"\n        [ -n \"$IPT6_FILE2\" ] && /bin/rm -f \"$IPT6_FILE2\"\n      fi\n    else\n      nft_bk=$(find /etc/sysconfig -maxdepth 1 -name 'nftables.conf.old-*-*-*-*_*_*' -print0 \\\n        | xargs -r -0 ls -1 -t | head -1)\n      diff_count=24\n      if grep -qs \"release 9\" /etc/redhat-release; then\n        diff_count=38\n      fi\n      if [ -f \"$nft_bk\" ] \\\n        && [ \"$(diff -y --suppress-common-lines \"$IPT_FILE\" \"$nft_bk\" | wc -l)\" = \"$diff_count\" ]; then\n        bigecho \"Restoring nftables rules...\"\n        conf_bk \"$IPT_FILE\"\n        /bin/cp -f \"$nft_bk\" \"$IPT_FILE\" && /bin/rm -f \"$nft_bk\"\n        nft flush ruleset\n        systemctl restart nftables\n      else\ncat <<'EOF'\n\nNote: This script cannot automatically remove nftables rules for the VPN.\n      To manually clean them up, edit /etc/sysconfig/nftables.conf\n      and remove unneeded rules. Your original rules are backed up as file\n      /etc/sysconfig/nftables.conf.old-date-time.\n\nEOF\n      fi\n    fi\n  fi\n}\n\nupdate_crontabs() {\n  if [ \"$os_type\" = \"alpine\" ]; then\n    cron_cmd=\"rc-service -c ipsec zap start\"\n    if grep -qs \"$cron_cmd\" /etc/crontabs/root; then\n      bigecho \"Updating crontabs...\"\n      sed -i \"/$cron_cmd/d\" /etc/crontabs/root\n      touch /etc/crontabs/cron.update\n    fi\n  fi\n}\n\nremove_config_files() {\n  bigecho \"Removing VPN configuration...\"\n  /bin/rm -f /etc/ipsec.conf* /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ppp/options.xl2tpd* \\\n      /etc/pam.d/pluto /etc/sysconfig/pluto /etc/default/pluto\n  /bin/rm -rf /etc/ipsec.d /etc/xl2tpd\n}\n\nremove_vpn() {\n  stop_services\n  remove_ipsec\n  remove_xl2tpd\n  remove_helper_scripts\n  update_sysctl\n  update_rclocal\n  update_iptables_rules\n  update_crontabs\n  remove_config_files\n}\n\nprint_vpn_removed() {\n  echo\n  echo \"IPsec VPN removed!\"\n}\n\nvpnuninstall() {\n  check_root\n  check_os\n  check_libreswan\n  check_iface\n  confirm_remove\n  remove_vpn\n  print_vpn_removed\n}\n\n## Defer until we have the complete script\nvpnuninstall \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/vpnupgrade.sh",
    "content": "#!/bin/sh\n#\n# Script to update Libreswan on Ubuntu, Debian, CentOS/RHEL, Rocky Linux,\n# AlmaLinux, Oracle Linux, Amazon Linux 2 and Alpine Linux\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2021-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# (Optional) Specify which Libreswan version to install. See: https://libreswan.org\n# If not specified, the latest supported version will be installed.\nSWAN_VER=\n\n### DO NOT edit below this line ###\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexiterr() { echo \"Error: $1\" >&2; exit 1; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo sh $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if grep -q \"release 7\" \"$rh_file\"; then\n      os_ver=7\n    elif grep -q \"release 8\" \"$rh_file\"; then\n      os_ver=8\n      grep -qi stream \"$rh_file\" && os_ver=8s\n    elif grep -q \"release 9\" \"$rh_file\"; then\n      os_ver=9\n      grep -qi stream \"$rh_file\" && os_ver=9s\n    elif grep -q \"release 10\" \"$rh_file\"; then\n      os_ver=10\n      grep -qi stream \"$rh_file\" && os_ver=10s\n    else\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n    if [ \"$os_type\" = \"centos\" ] \\\n      && { [ \"$os_ver\" = 7 ] || [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 8s ]; }; then\n      exiterr \"CentOS Linux $os_ver is EOL and not supported.\"\n    fi\n  elif grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    os_type=amzn\n    os_ver=2\n  else\n    os_type=$(lsb_release -si 2>/dev/null)\n    [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n    case $os_type in\n      [Uu]buntu)\n        os_type=ubuntu\n        ;;\n      [Dd]ebian|[Kk]ali|[Rr]aspbian)\n        os_type=debian\n        ;;\n      [Aa]lpine)\n        os_type=alpine\n        ;;\n      *)\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       Ubuntu, Debian, CentOS/RHEL, Rocky Linux, AlmaLinux,\n       Oracle Linux, Amazon Linux 2 or Alpine Linux\nEOF\n        exit 1\n        ;;\n    esac\n    if [ \"$os_type\" != \"alpine\" ]; then\n      os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n      if [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = \"stretchsid\" ] \\\n        || [ \"$os_ver\" = \"bustersid\" ] || [ -z \"$os_ver\" ]; then\ncat 1>&2 <<EOF\nError: This script requires Debian >= 10 or Ubuntu >= 20.04.\n       This version of Ubuntu/Debian is too old and not supported.\nEOF\n        exit 1\n      fi\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  if ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script requires Libreswan already installed.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\ninstall_pkgs() {\n  if ! command -v wget >/dev/null 2>&1; then\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n      export DEBIAN_FRONTEND=noninteractive\n      (\n        set -x\n        apt-get -yqq update || apt-get -yqq update\n      ) || exiterr \"'apt-get update' failed.\"\n      (\n        set -x\n        apt-get -yqq install wget >/dev/null || apt-get -yqq install wget >/dev/null\n      ) || exiterr \"'apt-get install wget' failed.\"\n    elif [ \"$os_type\" != \"alpine\" ]; then\n      (\n        set -x\n        yum -y -q install wget >/dev/null || yum -y -q install wget >/dev/null\n      ) || exiterr \"'yum install wget' failed.\"\n    fi\n  fi\n  if [ \"$os_type\" = \"alpine\" ]; then\n    (\n      set -x\n      apk add -U -q bash coreutils grep sed wget\n    ) || exiterr \"'apk add' failed.\"\n  fi\n}\n\nget_setup_url() {\n  base_url1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras\"\n  base_url2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras\"\n  sh_file=\"vpnupgrade_ubuntu.sh\"\n  if [ \"$os_type\" = \"centos\" ] || [ \"$os_type\" = \"rhel\" ] || [ \"$os_type\" = \"rocky\" ] \\\n    || [ \"$os_type\" = \"alma\" ] || [ \"$os_type\" = \"ol\" ]; then\n    sh_file=\"vpnupgrade_centos.sh\"\n  elif [ \"$os_type\" = \"amzn\" ]; then\n    sh_file=\"vpnupgrade_amzn.sh\"\n  elif [ \"$os_type\" = \"alpine\" ]; then\n    sh_file=\"vpnupgrade_alpine.sh\"\n  fi\n  setup_url1=\"$base_url1/$sh_file\"\n  setup_url2=\"$base_url2/$sh_file\"\n}\n\nrun_setup() {\n  status=0\n  if tmpdir=$(mktemp --tmpdir -d vpn.XXXXX 2>/dev/null); then\n    if ( set -x; wget -t 3 -T 30 -q -O \"$tmpdir/vpnup.sh\" \"$setup_url1\" \\\n      || wget -t 3 -T 30 -q -O \"$tmpdir/vpnup.sh\" \"$setup_url2\" \\\n      || curl -m 30 -fsL \"$setup_url1\" -o \"$tmpdir/vpnup.sh\" 2>/dev/null ); then\n      VPN_UPDATE_SWAN_VER=\"$SWAN_VER\" /bin/bash \"$tmpdir/vpnup.sh\" || status=1\n    else\n      status=1\n      echo \"Error: Could not download update script.\" >&2\n    fi\n    /bin/rm -f \"$tmpdir/vpnup.sh\"\n    /bin/rmdir \"$tmpdir\"\n  else\n    exiterr \"Could not create temporary directory.\"\n  fi\n}\n\nvpnupgrade() {\n  check_root\n  check_vz\n  check_os\n  check_libreswan\n  install_pkgs\n  get_setup_url\n  run_setup\n}\n\n## Defer setup until we have the complete script\nvpnupgrade \"$@\"\n\nexit \"$status\"\n"
  },
  {
    "path": "extras/vpnupgrade_alpine.sh",
    "content": "#!/bin/bash\n#\n# Script to update Libreswan on Alpine Linux\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2021-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# (Optional) Specify which Libreswan version to install. See: https://libreswan.org\n# If not specified, the latest supported version will be installed.\nSWAN_VER=\n\n### DO NOT edit below this line ###\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n[ -n \"$VPN_UPDATE_SWAN_VER\" ] && SWAN_VER=\"$VPN_UPDATE_SWAN_VER\"\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'apk add' failed.\"; }\nbigecho() { echo \"## $1\"; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_os() {\n  os_type=$(lsb_release -si 2>/dev/null)\n  [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n  case $os_type in\n    [Aa]lpine)\n      os_type=alpine\n      ;;\n    *)\n      exiterr \"This script only supports Alpine Linux.\"\n      ;;\n  esac\n  os_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\" | cut -d '.' -f 1,2)\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script requires Libreswan already installed.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\nget_swan_ver() {\n  swan_ver_cur=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    swan_ver_cur=\"$swan_ver_latest\"\n  fi\n  [ -z \"$SWAN_VER\" ] && SWAN_VER=\"$swan_ver_cur\"\n}\n\ncheck_swan_ver() {\n  if [ \"$SWAN_VER\" = \"4.8\" ] || [ \"$SWAN_VER\" = \"4.13\" ]; then\n    exiterr \"Libreswan version $SWAN_VER is not supported.\"\n  fi\n  if ! printf '%s\\n%s' \"4.5\" \"$SWAN_VER\" | sort -C -V \\\n    || ! printf '%s\\n%s' \"$SWAN_VER\" \"$swan_ver_cur\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$SWAN_VER' is not supported.\n       This script can install one of these versions:\n       4.5-$swan_ver_cur\nEOF\n    exit 1\n  fi\n}\n\nshow_setup_info() {\ncat <<EOF\n\nWelcome! Use this script to update Libreswan on your IPsec VPN server.\n\nCurrent version:    Libreswan $swan_ver_old\nVersion to install: Libreswan $SWAN_VER\n\nNote: This script will make the following changes to your VPN configuration:\n      - Fix obsolete ipsec.conf and/or ikev2.conf options\n      - Optimize VPN ciphers\n      - Update IKEv2 helper script\n      Your other VPN config files will not be modified.\n\nEOF\n  if [ \"$SWAN_VER\" != \"$swan_ver_cur\" ]; then\ncat <<'EOF'\nWARNING: Older versions of Libreswan could contain known security vulnerabilities.\n         See https://libreswan.org/security/ for more information.\n         Are you sure you want to install an older version?\n\nEOF\n  fi\n  if [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\ncat <<EOF\nNote: You already have Libreswan version $SWAN_VER installed!\n      If you continue, the same version will be re-installed.\n\nEOF\n  fi\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n}\n\nstart_setup() {\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_pkgs() {\n  bigecho \"Installing required packages...\"\n  (\n    set -x\n    apk add -U -q bash bind-tools coreutils openssl wget iptables ip6tables iproute2 \\\n    sed grep libcap-ng libcurl libevent linux-pam musl nspr nss nss-tools \\\n    bison flex gcc make libc-dev bsd-compat-headers linux-pam-dev nss-dev \\\n    libcap-ng-dev libevent-dev curl-dev nspr-dev uuidgen openrc\n  ) || exiterr2\n}\n\nget_libreswan() {\n  bigecho \"Downloading Libreswan...\"\n  cd /opt/src || exit 1\n  swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n  swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n  swan_url2=\"https://download.libreswan.org/$swan_file\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n  ) || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n}\n\ninstall_libreswan() {\n  bigecho \"Compiling and installing Libreswan, please wait...\"\n  cd \"libreswan-$SWAN_VER\" || exit 1\n  sed -i '1c\\#!/sbin/openrc-run' /etc/init.d/ipsec\n  service ipsec stop >/dev/null 2>&1\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n  if [ \"$SWAN_VER\" = \"4.5\" ] || [ \"$SWAN_VER\" = \"4.6\" ] \\\n    || [ \"$SWAN_VER\" = \"4.7\" ]; then\n    echo \"USE_GLIBC_KERN_FLIP_HEADERS=true\" >> Makefile.inc.local\n  fi\n  NPROCS=$(grep -c ^processor /proc/cpuinfo)\n  [ -z \"$NPROCS\" ] && NPROCS=1\n  (\n    set -x\n    make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n  )\n  cd /opt/src || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\"; then\n    service ipsec start >/dev/null 2>&1\n    exiterr \"Libreswan $SWAN_VER failed to build.\"\n  fi\n}\n\nupdate_ikev2_script() {\n  bigecho \"Updating IKEv2 script...\"\n  cd /opt/src || exit 1\n  ikev2_url=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras/ikev2setup.sh\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O ikev2.sh.new \"$ikev2_url\"\n  ) || /bin/rm -f ikev2.sh.new\n  if [ -s ikev2.sh.new ]; then\n    [ -s ikev2.sh ] && /bin/cp -f ikev2.sh \"ikev2.sh.old-$SYS_DT\"\n    /bin/cp -f ikev2.sh.new ikev2.sh && chmod +x ikev2.sh \\\n      && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n    /bin/rm -f ikev2.sh.new\n  fi\n}\n\nupdate_config() {\n  bigecho \"Updating VPN configuration...\"\n  IKE_NEW=\"  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\"\n  PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\"\n  if uname -m | grep -qi '^arm'; then\n    if ! modprobe -q sha512; then\n      PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2\"\n    fi\n  fi\n  dns_state=0\n  DNS_SRV1=$(grep \"modecfgdns1=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  DNS_SRV2=$(grep \"modecfgdns2=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  [ -n \"$DNS_SRV1\" ] && dns_state=2\n  [ -n \"$DNS_SRV1\" ] && [ -n \"$DNS_SRV2\" ] && dns_state=1\n  [ \"$(grep -c \"modecfgdns1=\" /etc/ipsec.conf)\" -gt \"1\" ] && dns_state=3\n  sed -i\".old-$SYS_DT\" \\\n      -e \"s/^[[:space:]]\\+auth=/  phase2=/\" \\\n      -e \"s/^[[:space:]]\\+forceencaps=/  encapsulation=/\" \\\n      -e \"s/^[[:space:]]\\+ike-frag=/  fragmentation=/\" \\\n      -e \"s/^[[:space:]]\\+sha2_truncbug=/  sha2-truncbug=/\" \\\n      -e \"s/^[[:space:]]\\+sha2-truncbug=yes/  sha2-truncbug=no/\" \\\n      -e \"s/^[[:space:]]\\+ike=.\\+/$IKE_NEW/\" \\\n      -e \"s/^[[:space:]]\\+phase2alg=.\\+/$PHASE2_NEW/\" /etc/ipsec.conf\n  if [ \"$dns_state\" = 1 ]; then\n    sed -i -e \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=\\\"$DNS_SRV1 $DNS_SRV2\\\"/\" \\\n        -e \"/modecfgdns2=/d\" /etc/ipsec.conf\n  elif [ \"$dns_state\" = 2 ]; then\n    sed -i \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=$DNS_SRV1/\" /etc/ipsec.conf\n  fi\n  sed -i \"/ikev2=never/d\" /etc/ipsec.conf\n  sed -i \"/conn shared/a \\  ikev2=never\" /etc/ipsec.conf\n  if ! grep -qs \"ikev1-policy\" /etc/ipsec.conf; then\n    sed -i \"/config setup/a \\  ikev1-policy=accept\" /etc/ipsec.conf\n  fi\n  if grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then\n    sed -i\".old-$SYS_DT\" 's/^[[:space:]]\\+ike-frag=/  fragmentation=/' /etc/ipsec.d/ikev2.conf\n  fi\n}\n\nrestart_ipsec() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  sed -i '1c\\#!/sbin/openrc-run' /etc/init.d/ipsec\n  service ipsec restart >/dev/null 2>&1\n}\n\nshow_setup_complete() {\ncat <<EOF\n\n================================================\n\nLibreswan $SWAN_VER has been successfully installed!\n\n================================================\n\nEOF\n  if [ \"$dns_state\" = 3 ]; then\ncat <<'EOF'\nIMPORTANT: You must edit /etc/ipsec.conf and replace\n           all occurrences of these two lines:\n             modecfgdns1=DNS_SERVER_1\n             modecfgdns2=DNS_SERVER_2\n           with a single line like this:\n             modecfgdns=\"DNS_SERVER_1 DNS_SERVER_2\"\n           Then run \"sudo service ipsec restart\".\n\nEOF\n  fi\n}\n\nvpnupgrade() {\n  check_root\n  check_vz\n  check_os\n  check_libreswan\n  get_swan_ver\n  check_swan_ver\n  show_setup_info\n  start_setup\n  install_pkgs\n  get_libreswan\n  install_libreswan\n  update_ikev2_script\n  update_config\n  restart_ipsec\n  show_setup_complete\n}\n\n## Defer setup until we have the complete script\nvpnupgrade \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/vpnupgrade_amzn.sh",
    "content": "#!/bin/bash\n#\n# Script to update Libreswan on Amazon Linux 2\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# (Optional) Specify which Libreswan version to install. See: https://libreswan.org\n# If not specified, the latest supported version will be installed.\nSWAN_VER=\n\n### DO NOT edit below this line ###\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n[ -n \"$VPN_UPDATE_SWAN_VER\" ] && SWAN_VER=\"$VPN_UPDATE_SWAN_VER\"\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'yum install' failed.\"; }\nbigecho() { echo \"## $1\"; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_os() {\n  if ! grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    exiterr \"This script only supports Amazon Linux 2.\"\n  fi\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script requires Libreswan already installed.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\nget_swan_ver() {\n  swan_ver_cur=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-v1-amzn-2-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    swan_ver_cur=\"$swan_ver_latest\"\n  fi\n  [ -z \"$SWAN_VER\" ] && SWAN_VER=\"$swan_ver_cur\"\n}\n\ncheck_swan_ver() {\n  if [ \"$SWAN_VER\" = \"4.8\" ] || [ \"$SWAN_VER\" = \"4.13\" ]; then\n    exiterr \"Libreswan version $SWAN_VER is not supported.\"\n  fi\n  if [ \"$SWAN_VER\" != \"3.32\" ] \\\n    && { ! printf '%s\\n%s' \"4.1\" \"$SWAN_VER\" | sort -C -V \\\n    || ! printf '%s\\n%s' \"$SWAN_VER\" \"$swan_ver_cur\" | sort -C -V; }; then\ncat 1>&2 <<EOF\nError: Libreswan version '$SWAN_VER' is not supported.\n       This script can install one of these versions:\n       3.32, 4.1-$swan_ver_cur\nEOF\n    exit 1\n  fi\n}\n\nshow_setup_info() {\ncat <<EOF\n\nWelcome! Use this script to update Libreswan on your IPsec VPN server.\n\nCurrent version:    Libreswan $swan_ver_old\nVersion to install: Libreswan $SWAN_VER\n\nNote: This script will make the following changes to your VPN configuration:\n      - Fix obsolete ipsec.conf and/or ikev2.conf options\n      - Optimize VPN ciphers\n      - Update IKEv2 helper script\n      Your other VPN config files will not be modified.\n\nEOF\n  if [ \"$SWAN_VER\" != \"$swan_ver_cur\" ]; then\ncat <<'EOF'\nWARNING: Older versions of Libreswan could contain known security vulnerabilities.\n         See https://libreswan.org/security/ for more information.\n         Are you sure you want to install an older version?\n\nEOF\n  fi\n  if [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\ncat <<EOF\nNote: You already have Libreswan version $SWAN_VER installed!\n      If you continue, the same version will be re-installed.\n\nEOF\n  fi\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n}\n\nstart_setup() {\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_pkgs() {\n  bigecho \"Installing required packages...\"\n  (\n    set -x\n    yum -y -q install nss-devel nspr-devel pkgconfig pam-devel \\\n      libcap-ng-devel libselinux-devel curl-devel nss-tools \\\n      flex bison gcc make wget sed tar \\\n      systemd-devel libevent-devel fipscheck-devel >/dev/null\n  ) || exiterr2\n}\n\nget_libreswan() {\n  bigecho \"Downloading Libreswan...\"\n  cd /opt/src || exit 1\n  swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n  swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n  swan_url2=\"https://download.libreswan.org/$swan_file\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n  ) || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n}\n\ninstall_libreswan() {\n  bigecho \"Compiling and installing Libreswan, please wait...\"\n  cd \"libreswan-$SWAN_VER\" || exit 1\n  service ipsec stop >/dev/null 2>&1\n  [ \"$SWAN_VER\" = \"4.1\" ] && sed -i 's/ sysv )/ sysvinit )/' programs/setup/setup.in\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nEOF\n  if [ \"$SWAN_VER\" != \"3.32\" ]; then\ncat >> Makefile.inc.local <<'EOF'\nUSE_NSS_KDF=false\nUSE_LINUX_AUDIT=false\nUSE_SECCOMP=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n  fi\n  if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n    echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n  fi\n  NPROCS=$(grep -c ^processor /proc/cpuinfo)\n  [ -z \"$NPROCS\" ] && NPROCS=1\n  (\n    set -x\n    make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n  )\n  cd /opt/src || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\"; then\n    service ipsec start >/dev/null 2>&1\n    exiterr \"Libreswan $SWAN_VER failed to build.\"\n  fi\n}\n\nrestore_selinux() {\n  restorecon /etc/ipsec.d/*db 2>/dev/null\n  restorecon /usr/local/sbin -Rv 2>/dev/null\n  restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null\n}\n\nupdate_ikev2_script() {\n  bigecho \"Updating IKEv2 script...\"\n  cd /opt/src || exit 1\n  ikev2_url=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras/ikev2setup.sh\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O ikev2.sh.new \"$ikev2_url\"\n  ) || /bin/rm -f ikev2.sh.new\n  if [ -s ikev2.sh.new ]; then\n    [ -s ikev2.sh ] && /bin/cp -f ikev2.sh \"ikev2.sh.old-$SYS_DT\"\n    /bin/cp -f ikev2.sh.new ikev2.sh && chmod +x ikev2.sh \\\n      && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n    /bin/rm -f ikev2.sh.new\n  fi\n}\n\nupdate_config() {\n  bigecho \"Updating VPN configuration...\"\n  IKE_NEW=\"  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\"\n  PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\"\n  dns_state=0\n  DNS_SRV1=$(grep \"modecfgdns1=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  DNS_SRV2=$(grep \"modecfgdns2=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  [ -n \"$DNS_SRV1\" ] && dns_state=2\n  [ -n \"$DNS_SRV1\" ] && [ -n \"$DNS_SRV2\" ] && dns_state=1\n  [ \"$(grep -c \"modecfgdns1=\" /etc/ipsec.conf)\" -gt \"1\" ] && dns_state=3\n  sed -i\".old-$SYS_DT\" \\\n      -e \"s/^[[:space:]]\\+auth=/  phase2=/\" \\\n      -e \"s/^[[:space:]]\\+forceencaps=/  encapsulation=/\" \\\n      -e \"s/^[[:space:]]\\+ike-frag=/  fragmentation=/\" \\\n      -e \"s/^[[:space:]]\\+sha2_truncbug=/  sha2-truncbug=/\" \\\n      -e \"s/^[[:space:]]\\+sha2-truncbug=yes/  sha2-truncbug=no/\" \\\n      -e \"s/^[[:space:]]\\+ike=.\\+/$IKE_NEW/\" \\\n      -e \"s/^[[:space:]]\\+phase2alg=.\\+/$PHASE2_NEW/\" /etc/ipsec.conf\n  if [ \"$dns_state\" = 1 ]; then\n    sed -i -e \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=\\\"$DNS_SRV1 $DNS_SRV2\\\"/\" \\\n        -e \"/modecfgdns2=/d\" /etc/ipsec.conf\n  elif [ \"$dns_state\" = 2 ]; then\n    sed -i \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=$DNS_SRV1/\" /etc/ipsec.conf\n  fi\n  sed -i \"/ikev2=never/d\" /etc/ipsec.conf\n  sed -i \"/conn shared/a \\  ikev2=never\" /etc/ipsec.conf\n  if ! grep -qs \"ikev1-policy\" /etc/ipsec.conf; then\n    sed -i \"/config setup/a \\  ikev1-policy=accept\" /etc/ipsec.conf\n  fi\n  if grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then\n    sed -i\".old-$SYS_DT\" 's/^[[:space:]]\\+ike-frag=/  fragmentation=/' /etc/ipsec.d/ikev2.conf\n  fi\n}\n\nrestart_ipsec() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  service ipsec restart 2>/dev/null\n}\n\nshow_setup_complete() {\ncat <<EOF\n\n================================================\n\nLibreswan $SWAN_VER has been successfully installed!\n\n================================================\n\nEOF\n  if [ \"$dns_state\" = 3 ]; then\ncat <<'EOF'\nIMPORTANT: You must edit /etc/ipsec.conf and replace\n           all occurrences of these two lines:\n             modecfgdns1=DNS_SERVER_1\n             modecfgdns2=DNS_SERVER_2\n           with a single line like this:\n             modecfgdns=\"DNS_SERVER_1 DNS_SERVER_2\"\n           Then run \"sudo service ipsec restart\".\n\nEOF\n  fi\n}\n\nvpnupgrade() {\n  check_root\n  check_os\n  check_libreswan\n  get_swan_ver\n  check_swan_ver\n  show_setup_info\n  start_setup\n  install_pkgs\n  get_libreswan\n  install_libreswan\n  restore_selinux\n  update_ikev2_script\n  update_config\n  restart_ipsec\n  show_setup_complete\n}\n\n## Defer setup until we have the complete script\nvpnupgrade \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/vpnupgrade_centos.sh",
    "content": "#!/bin/bash\n#\n# Script to update Libreswan on CentOS/RHEL, Rocky Linux, AlmaLinux and Oracle Linux\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2016-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# (Optional) Specify which Libreswan version to install. See: https://libreswan.org\n# If not specified, the latest supported version will be installed.\nSWAN_VER=\n\n### DO NOT edit below this line ###\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n[ -n \"$VPN_UPDATE_SWAN_VER\" ] && SWAN_VER=\"$VPN_UPDATE_SWAN_VER\"\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'yum install' failed.\"; }\nbigecho() { echo \"## $1\"; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if grep -q \"release 7\" \"$rh_file\"; then\n      os_ver=7\n    elif grep -q \"release 8\" \"$rh_file\"; then\n      os_ver=8\n      grep -qi stream \"$rh_file\" && os_ver=8s\n    elif grep -q \"release 9\" \"$rh_file\"; then\n      os_ver=9\n      grep -qi stream \"$rh_file\" && os_ver=9s\n    elif grep -q \"release 10\" \"$rh_file\"; then\n      os_ver=10\n      grep -qi stream \"$rh_file\" && os_ver=10s\n    else\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n    if [ \"$os_type\" = \"centos\" ] \\\n      && { [ \"$os_ver\" = 7 ] || [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 8s ]; }; then\n      exiterr \"CentOS Linux $os_ver is EOL and not supported.\"\n    fi\n  else\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       CentOS/RHEL, Rocky Linux, AlmaLinux or Oracle Linux\nEOF\n    exit 1\n  fi\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script requires Libreswan already installed.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\nget_swan_ver() {\n  swan_ver_cur=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    swan_ver_cur=\"$swan_ver_latest\"\n  fi\n  [ -z \"$SWAN_VER\" ] && SWAN_VER=\"$swan_ver_cur\"\n}\n\ncheck_swan_ver() {\n  if [ \"$SWAN_VER\" = \"4.8\" ] || [ \"$SWAN_VER\" = \"4.13\" ]; then\n    exiterr \"Libreswan version $SWAN_VER is not supported.\"\n  fi\n  if [ \"$SWAN_VER\" != \"3.32\" ] \\\n    && { ! printf '%s\\n%s' \"4.1\" \"$SWAN_VER\" | sort -C -V \\\n    || ! printf '%s\\n%s' \"$SWAN_VER\" \"$swan_ver_cur\" | sort -C -V; }; then\ncat 1>&2 <<EOF\nError: Libreswan version '$SWAN_VER' is not supported.\n       This script can install one of these versions:\n       3.32, 4.1-$swan_ver_cur\nEOF\n    exit 1\n  fi\n}\n\nshow_setup_info() {\ncat <<EOF\n\nWelcome! Use this script to update Libreswan on your IPsec VPN server.\n\nCurrent version:    Libreswan $swan_ver_old\nVersion to install: Libreswan $SWAN_VER\n\nNote: This script will make the following changes to your VPN configuration:\n      - Fix obsolete ipsec.conf and/or ikev2.conf options\n      - Optimize VPN ciphers\n      - Update IKEv2 helper script\n      Your other VPN config files will not be modified.\n\nEOF\n  if [ \"$SWAN_VER\" != \"$swan_ver_cur\" ]; then\ncat <<'EOF'\nWARNING: Older versions of Libreswan could contain known security vulnerabilities.\n         See https://libreswan.org/security/ for more information.\n         Are you sure you want to install an older version?\n\nEOF\n  fi\n  if [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\ncat <<EOF\nNote: You already have Libreswan version $SWAN_VER installed!\n      If you continue, the same version will be re-installed.\n\nEOF\n  fi\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n}\n\nstart_setup() {\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_pkgs_1() {\n  bigecho \"Installing required packages...\"\n  (\n    set -x\n    yum -y -q install nss-devel nspr-devel pkgconfig pam-devel \\\n      libcap-ng-devel libselinux-devel curl-devel nss-tools \\\n      flex bison gcc make wget sed tar >/dev/null\n  ) || exiterr2\n}\n\ninstall_pkgs_2() {\n  erp=\"--enablerepo\"\n  rp1=\"$erp=*server-*optional*\"\n  rp2=\"$erp=*releases-optional*\"\n  if [ \"$os_type$os_ver\" = \"ol7\" ]; then\n    rp2=\"$erp=ol7_optional_latest\"\n  fi\n  if [ \"$os_ver\" = 7 ]; then\n    (\n      set -x\n      yum \"$rp1\" \"$rp2\" -y -q install systemd-devel libevent-devel fipscheck-devel >/dev/null\n    ) || exiterr2\n  else\n    (\n      set -x\n      yum -y -q install systemd-devel libevent-devel >/dev/null\n    ) || exiterr2\n  fi\n}\n\nget_libreswan() {\n  bigecho \"Downloading Libreswan...\"\n  cd /opt/src || exit 1\n  swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n  swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n  swan_url2=\"https://download.libreswan.org/$swan_file\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n  ) || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n}\n\ninstall_libreswan() {\n  bigecho \"Compiling and installing Libreswan, please wait...\"\n  cd \"libreswan-$SWAN_VER\" || exit 1\n  service ipsec stop >/dev/null 2>&1\n  [ \"$SWAN_VER\" = \"4.1\" ] && sed -i 's/ sysv )/ sysvinit )/' programs/setup/setup.in\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nEOF\n  if [ \"$SWAN_VER\" != \"3.32\" ]; then\ncat >> Makefile.inc.local <<'EOF'\nUSE_NSS_KDF=false\nUSE_LINUX_AUDIT=false\nUSE_SECCOMP=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n  fi\n  if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n    echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n  fi\n  NPROCS=$(grep -c ^processor /proc/cpuinfo)\n  [ -z \"$NPROCS\" ] && NPROCS=1\n  (\n    set -x\n    make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n  )\n  cd /opt/src || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\"; then\n    service ipsec start >/dev/null 2>&1\n    exiterr \"Libreswan $SWAN_VER failed to build.\"\n  fi\n}\n\nrestore_selinux() {\n  restorecon /etc/ipsec.d/*db 2>/dev/null\n  restorecon /usr/local/sbin -Rv 2>/dev/null\n  restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null\n}\n\nupdate_ikev2_script() {\n  bigecho \"Updating IKEv2 script...\"\n  cd /opt/src || exit 1\n  ikev2_url=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras/ikev2setup.sh\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O ikev2.sh.new \"$ikev2_url\"\n  ) || /bin/rm -f ikev2.sh.new\n  if [ -s ikev2.sh.new ]; then\n    [ -s ikev2.sh ] && /bin/cp -f ikev2.sh \"ikev2.sh.old-$SYS_DT\"\n    /bin/cp -f ikev2.sh.new ikev2.sh && chmod +x ikev2.sh \\\n      && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n    /bin/rm -f ikev2.sh.new\n  fi\n}\n\nupdate_config() {\n  bigecho \"Updating VPN configuration...\"\n  IKE_NEW=\"  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\"\n  PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\"\n  dns_state=0\n  DNS_SRV1=$(grep \"modecfgdns1=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  DNS_SRV2=$(grep \"modecfgdns2=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  [ -n \"$DNS_SRV1\" ] && dns_state=2\n  [ -n \"$DNS_SRV1\" ] && [ -n \"$DNS_SRV2\" ] && dns_state=1\n  [ \"$(grep -c \"modecfgdns1=\" /etc/ipsec.conf)\" -gt \"1\" ] && dns_state=3\n  sed -i\".old-$SYS_DT\" \\\n      -e \"s/^[[:space:]]\\+auth=/  phase2=/\" \\\n      -e \"s/^[[:space:]]\\+forceencaps=/  encapsulation=/\" \\\n      -e \"s/^[[:space:]]\\+ike-frag=/  fragmentation=/\" \\\n      -e \"s/^[[:space:]]\\+sha2_truncbug=/  sha2-truncbug=/\" \\\n      -e \"s/^[[:space:]]\\+sha2-truncbug=yes/  sha2-truncbug=no/\" \\\n      -e \"s/^[[:space:]]\\+ike=.\\+/$IKE_NEW/\" \\\n      -e \"s/^[[:space:]]\\+phase2alg=.\\+/$PHASE2_NEW/\" /etc/ipsec.conf\n  if [ \"$dns_state\" = 1 ]; then\n    sed -i -e \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=\\\"$DNS_SRV1 $DNS_SRV2\\\"/\" \\\n        -e \"/modecfgdns2=/d\" /etc/ipsec.conf\n  elif [ \"$dns_state\" = 2 ]; then\n    sed -i \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=$DNS_SRV1/\" /etc/ipsec.conf\n  fi\n  sed -i \"/ikev2=never/d\" /etc/ipsec.conf\n  sed -i \"/conn shared/a \\  ikev2=never\" /etc/ipsec.conf\n  if ! grep -qs \"ikev1-policy\" /etc/ipsec.conf; then\n    sed -i \"/config setup/a \\  ikev1-policy=accept\" /etc/ipsec.conf\n  fi\n  if grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then\n    sed -i\".old-$SYS_DT\" 's/^[[:space:]]\\+ike-frag=/  fragmentation=/' /etc/ipsec.d/ikev2.conf\n  fi\n}\n\nrestart_ipsec() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  service ipsec restart 2>/dev/null\n}\n\nshow_setup_complete() {\ncat <<EOF\n\n================================================\n\nLibreswan $SWAN_VER has been successfully installed!\n\n================================================\n\nEOF\n  if [ \"$dns_state\" = 3 ]; then\ncat <<'EOF'\nIMPORTANT: You must edit /etc/ipsec.conf and replace\n           all occurrences of these two lines:\n             modecfgdns1=DNS_SERVER_1\n             modecfgdns2=DNS_SERVER_2\n           with a single line like this:\n             modecfgdns=\"DNS_SERVER_1 DNS_SERVER_2\"\n           Then run \"sudo service ipsec restart\".\n\nEOF\n  fi\n}\n\nvpnupgrade() {\n  check_root\n  check_vz\n  check_os\n  check_libreswan\n  get_swan_ver\n  check_swan_ver\n  show_setup_info\n  start_setup\n  install_pkgs_1\n  install_pkgs_2\n  get_libreswan\n  install_libreswan\n  restore_selinux\n  update_ikev2_script\n  update_config\n  restart_ipsec\n  show_setup_complete\n}\n\n## Defer setup until we have the complete script\nvpnupgrade \"$@\"\n\nexit 0\n"
  },
  {
    "path": "extras/vpnupgrade_ubuntu.sh",
    "content": "#!/bin/bash\n#\n# Script to update Libreswan on Ubuntu and Debian\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2016-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# (Optional) Specify which Libreswan version to install. See: https://libreswan.org\n# If not specified, the latest supported version will be installed.\nSWAN_VER=\n\n### DO NOT edit below this line ###\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n[ -n \"$VPN_UPDATE_SWAN_VER\" ] && SWAN_VER=\"$VPN_UPDATE_SWAN_VER\"\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'apt-get install' failed.\"; }\nbigecho() { echo \"## $1\"; }\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_os() {\n  os_type=$(lsb_release -si 2>/dev/null)\n  [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n  case $os_type in\n    [Uu]buntu)\n      os_type=ubuntu\n      ;;\n    [Dd]ebian|[Kk]ali)\n      os_type=debian\n      ;;\n    [Rr]aspbian)\n      os_type=raspbian\n      ;;\n    *)\n      exiterr \"This script only supports Ubuntu and Debian.\"\n      ;;\n  esac\n  os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n  if [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = \"stretchsid\" ] \\\n    || [ \"$os_ver\" = \"bustersid\" ] || [ -z \"$os_ver\" ]; then\ncat 1>&2 <<EOF\nError: This script requires Debian >= 10 or Ubuntu >= 20.04.\n       This version of Ubuntu/Debian is too old and not supported.\nEOF\n    exit 1\n  fi\n  [ -f /etc/os-release ] && ubuntu_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\")\n}\n\ncheck_libreswan() {\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  if ! printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan'; then\ncat 1>&2 <<'EOF'\nError: This script requires Libreswan already installed.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn\nEOF\n    exit 1\n  fi\n}\n\nget_swan_ver() {\n  swan_ver_cur=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    swan_ver_cur=\"$swan_ver_latest\"\n  fi\n  [ -z \"$SWAN_VER\" ] && SWAN_VER=\"$swan_ver_cur\"\n}\n\ncheck_swan_ver() {\n  if [ \"$SWAN_VER\" = \"4.8\" ] || [ \"$SWAN_VER\" = \"4.13\" ]; then\n    exiterr \"Libreswan version $SWAN_VER is not supported.\"\n  fi\n  if [ \"$SWAN_VER\" = \"3.32\" ] && [ \"$os_ver\" = \"11\" ]; then\n    exiterr \"Libreswan 3.32 is not supported on Debian 11.\"\n  fi\n  if [ \"$SWAN_VER\" != \"3.32\" ] \\\n    && { ! printf '%s\\n%s' \"4.1\" \"$SWAN_VER\" | sort -C -V \\\n    || ! printf '%s\\n%s' \"$SWAN_VER\" \"$swan_ver_cur\" | sort -C -V; }; then\ncat 1>&2 <<EOF\nError: Libreswan version '$SWAN_VER' is not supported.\n       This script can install one of these versions:\n       3.32, 4.1-$swan_ver_cur\nEOF\n    exit 1\n  fi\n}\n\nshow_setup_info() {\ncat <<EOF\n\nWelcome! Use this script to update Libreswan on your IPsec VPN server.\n\nCurrent version:    Libreswan $swan_ver_old\nVersion to install: Libreswan $SWAN_VER\n\nNote: This script will make the following changes to your VPN configuration:\n      - Fix obsolete ipsec.conf and/or ikev2.conf options\n      - Optimize VPN ciphers\n      - Update IKEv2 helper script\n      Your other VPN config files will not be modified.\n\nEOF\n  if [ \"$SWAN_VER\" != \"$swan_ver_cur\" ]; then\ncat <<'EOF'\nWARNING: Older versions of Libreswan could contain known security vulnerabilities.\n         See https://libreswan.org/security/ for more information.\n         Are you sure you want to install an older version?\n\nEOF\n  fi\n  if [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\ncat <<EOF\nNote: You already have Libreswan version $SWAN_VER installed!\n      If you continue, the same version will be re-installed.\n\nEOF\n  fi\n  printf \"Do you want to continue? [Y/n] \"\n  read -r response\n  case $response in\n    [yY][eE][sS]|[yY]|'')\n      echo\n      ;;\n    *)\n      echo \"Abort. No changes were made.\"\n      exit 1\n      ;;\n  esac\n}\n\nstart_setup() {\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\nupdate_apt_cache() {\n  bigecho \"Installing required packages...\"\n  export DEBIAN_FRONTEND=noninteractive\n  (\n    set -x\n    apt-get -yqq update || apt-get -yqq update\n  ) || exiterr \"'apt-get update' failed.\"\n}\n\ninstall_pkgs() {\n  p1=libcurl4-nss-dev\n  if [ \"$os_ver\" = \"trixiesid\" ] || [ \"$os_ver\" = 13 ]; then\n    p1=libcurl4-gnutls-dev\n  fi\n  (\n    set -x\n    apt-get -yqq install libnss3-dev libnspr4-dev pkg-config \\\n      libpam0g-dev libcap-ng-dev libcap-ng-utils libselinux1-dev \\\n      $p1 libnss3-tools libevent-dev libsystemd-dev \\\n      flex bison gcc make wget sed >/dev/null\n  ) || exiterr2\n  if { [ \"$os_type\" = \"ubuntu\" ] && [ -n \"$ubuntu_ver\" ] \\\n    && printf '%s\\n%s' \"24.10\" \"$ubuntu_ver\" | sort -C -V; } \\\n    || [ \"$os_ver\" = 13 ]; then\n    (\n      set -x\n      apt-get -yqq install systemd-dev >/dev/null\n    ) || exiterr2\n  fi\n}\n\nget_libreswan() {\n  bigecho \"Downloading Libreswan...\"\n  cd /opt/src || exit 1\n  swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n  swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n  swan_url2=\"https://download.libreswan.org/$swan_file\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n  ) || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n}\n\ninstall_libreswan() {\n  bigecho \"Compiling and installing Libreswan, please wait...\"\n  cd \"libreswan-$SWAN_VER\" || exit 1\n  service ipsec stop >/dev/null 2>&1\n  [ \"$SWAN_VER\" = \"4.1\" ] && sed -i 's/ sysv )/ sysvinit )/' programs/setup/setup.in\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nEOF\n  if [ \"$SWAN_VER\" = \"3.32\" ]; then\ncat >> Makefile.inc.local <<'EOF'\nUSE_DH31=false\nUSE_NSS_AVA_COPY=true\nUSE_NSS_IPSEC_PROFILE=false\nUSE_GLIBC_KERN_FLIP_HEADERS=true\nEOF\n  else\ncat >> Makefile.inc.local <<'EOF'\nUSE_NSS_KDF=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n  fi\n  if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n    echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n  fi\n  NPROCS=$(grep -c ^processor /proc/cpuinfo)\n  [ -z \"$NPROCS\" ] && NPROCS=1\n  (\n    set -x\n    make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n  )\n  cd /opt/src || exit 1\n  /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n  if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\"; then\n    service ipsec start >/dev/null 2>&1\n    exiterr \"Libreswan $SWAN_VER failed to build.\"\n  fi\n}\n\nupdate_ikev2_script() {\n  bigecho \"Updating IKEv2 script...\"\n  cd /opt/src || exit 1\n  ikev2_url=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras/ikev2setup.sh\"\n  (\n    set -x\n    wget -t 3 -T 30 -q -O ikev2.sh.new \"$ikev2_url\"\n  ) || /bin/rm -f ikev2.sh.new\n  if [ -s ikev2.sh.new ]; then\n    [ -s ikev2.sh ] && /bin/cp -f ikev2.sh \"ikev2.sh.old-$SYS_DT\"\n    /bin/cp -f ikev2.sh.new ikev2.sh && chmod +x ikev2.sh \\\n      && ln -s /opt/src/ikev2.sh /usr/bin 2>/dev/null\n    /bin/rm -f ikev2.sh.new\n  fi\n}\n\nupdate_config() {\n  bigecho \"Updating VPN configuration...\"\n  IKE_NEW=\"  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\"\n  PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\"\n  if uname -m | grep -qi '^arm'; then\n    if ! modprobe -q sha512; then\n      PHASE2_NEW=\"  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes128-sha2,aes256-sha2\"\n    fi\n  fi\n  dns_state=0\n  DNS_SRV1=$(grep \"modecfgdns1=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  DNS_SRV2=$(grep \"modecfgdns2=\" /etc/ipsec.conf | head -n 1 | cut -d '=' -f 2)\n  [ -n \"$DNS_SRV1\" ] && dns_state=2\n  [ -n \"$DNS_SRV1\" ] && [ -n \"$DNS_SRV2\" ] && dns_state=1\n  [ \"$(grep -c \"modecfgdns1=\" /etc/ipsec.conf)\" -gt \"1\" ] && dns_state=3\n  sed -i\".old-$SYS_DT\" \\\n      -e \"s/^[[:space:]]\\+auth=/  phase2=/\" \\\n      -e \"s/^[[:space:]]\\+forceencaps=/  encapsulation=/\" \\\n      -e \"s/^[[:space:]]\\+ike-frag=/  fragmentation=/\" \\\n      -e \"s/^[[:space:]]\\+sha2_truncbug=/  sha2-truncbug=/\" \\\n      -e \"s/^[[:space:]]\\+sha2-truncbug=yes/  sha2-truncbug=no/\" \\\n      -e \"s/^[[:space:]]\\+ike=.\\+/$IKE_NEW/\" \\\n      -e \"s/^[[:space:]]\\+phase2alg=.\\+/$PHASE2_NEW/\" /etc/ipsec.conf\n  if [ \"$dns_state\" = 1 ]; then\n    sed -i -e \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=\\\"$DNS_SRV1 $DNS_SRV2\\\"/\" \\\n        -e \"/modecfgdns2=/d\" /etc/ipsec.conf\n  elif [ \"$dns_state\" = 2 ]; then\n    sed -i \"s/^[[:space:]]\\+modecfgdns1=.\\+/  modecfgdns=$DNS_SRV1/\" /etc/ipsec.conf\n  fi\n  sed -i \"/ikev2=never/d\" /etc/ipsec.conf\n  sed -i \"/conn shared/a \\  ikev2=never\" /etc/ipsec.conf\n  if ! grep -qs \"ikev1-policy\" /etc/ipsec.conf; then\n    sed -i \"/config setup/a \\  ikev1-policy=accept\" /etc/ipsec.conf\n  fi\n  if grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then\n    sed -i\".old-$SYS_DT\" 's/^[[:space:]]\\+ike-frag=/  fragmentation=/' /etc/ipsec.d/ikev2.conf\n  fi\n}\n\nrestart_ipsec() {\n  bigecho \"Restarting IPsec service...\"\n  mkdir -p /run/pluto\n  service ipsec restart 2>/dev/null\n}\n\nshow_setup_complete() {\ncat <<EOF\n\n================================================\n\nLibreswan $SWAN_VER has been successfully installed!\n\n================================================\n\nEOF\n  if [ \"$dns_state\" = 3 ]; then\ncat <<'EOF'\nIMPORTANT: You must edit /etc/ipsec.conf and replace\n           all occurrences of these two lines:\n             modecfgdns1=DNS_SERVER_1\n             modecfgdns2=DNS_SERVER_2\n           with a single line like this:\n             modecfgdns=\"DNS_SERVER_1 DNS_SERVER_2\"\n           Then run \"sudo service ipsec restart\".\n\nEOF\n  fi\n}\n\nvpnupgrade() {\n  check_root\n  check_vz\n  check_os\n  check_libreswan\n  get_swan_ver\n  check_swan_ver\n  show_setup_info\n  start_setup\n  update_apt_cache\n  install_pkgs\n  get_libreswan\n  install_libreswan\n  update_ikev2_script\n  update_config\n  restart_ipsec\n  show_setup_complete\n}\n\n## Defer setup until we have the complete script\nvpnupgrade \"$@\"\n\nexit 0\n"
  },
  {
    "path": "vpnsetup.sh",
    "content": "#!/bin/sh\n#\n# Script for automatic setup of an IPsec VPN server on Ubuntu, Debian, CentOS/RHEL,\n# Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux 2 and Alpine Linux\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2021-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - IPsec pre-shared key, VPN username and password\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_IPSEC_PSK=''\nYOUR_USERNAME=''\nYOUR_PASSWORD=''\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexiterr() { echo \"Error: $1\" >&2; exit 1; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo sh $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_lxc() {\n  # shellcheck disable=SC2154\n  if [ \"$container\" = \"lxc\" ] && [ ! -e /dev/ppp ]; then\ncat 1>&2 <<'EOF'\nError: /dev/ppp is missing. LXC containers require configuration.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn/issues/1014\nEOF\n  exit 1\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if grep -q \"release 7\" \"$rh_file\"; then\n      os_ver=7\n    elif grep -q \"release 8\" \"$rh_file\"; then\n      os_ver=8\n      grep -qi stream \"$rh_file\" && os_ver=8s\n    elif grep -q \"release 9\" \"$rh_file\"; then\n      os_ver=9\n      grep -qi stream \"$rh_file\" && os_ver=9s\n    elif grep -q \"release 10\" \"$rh_file\"; then\n      os_ver=10\n      grep -qi stream \"$rh_file\" && os_ver=10s\n    else\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n    if [ \"$os_type\" = \"centos\" ] \\\n      && { [ \"$os_ver\" = 7 ] || [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 8s ]; }; then\n      exiterr \"CentOS Linux $os_ver is EOL and not supported.\"\n    fi\n  elif grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    os_type=amzn\n    os_ver=2\n  elif grep -qs \"Amazon Linux release 2023\" /etc/system-release; then\n    exiterr \"Amazon Linux 2023 is not supported.\"\n  else\n    os_type=$(lsb_release -si 2>/dev/null)\n    [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n    case $os_type in\n      [Uu]buntu)\n        os_type=ubuntu\n        ;;\n      [Dd]ebian|[Kk]ali|[Rr]aspbian)\n        os_type=debian\n        ;;\n      [Aa]lpine)\n        os_type=alpine\n        ;;\n      *)\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       Ubuntu, Debian, CentOS/RHEL, Rocky Linux, AlmaLinux,\n       Oracle Linux, Amazon Linux 2 or Alpine Linux\nEOF\n        exit 1\n        ;;\n    esac\n    if [ \"$os_type\" = \"alpine\" ]; then\n      os_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\" | cut -d '.' -f 1,2)\n      if [ \"$os_ver\" != \"3.22\" ] && [ \"$os_ver\" != \"3.23\" ]; then\n        exiterr \"This script only supports Alpine Linux 3.22/3.23.\"\n      fi\n    else\n      os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n      if [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = \"stretchsid\" ] \\\n        || [ \"$os_ver\" = \"bustersid\" ] || [ -z \"$os_ver\" ]; then\ncat 1>&2 <<EOF\nError: This script requires Debian >= 10 or Ubuntu >= 20.04.\n       This version of Ubuntu/Debian is too old and not supported.\nEOF\n        exit 1\n      fi\n    fi\n  fi\n}\n\ncheck_iface() {\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  if [ \"$os_type\" != \"alpine\" ]; then\n    [ -z \"$def_iface\" ] && def_iface=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n  fi\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  check_wl=0\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n      if ! uname -m | grep -qi -e '^arm' -e '^aarch64'; then\n        check_wl=1\n      fi\n    else\n      check_wl=1\n    fi\n  fi\n  if [ \"$check_wl\" = 1 ]; then\n    case $def_iface in\n      wl*)\n        exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n        ;;\n    esac\n  fi\n}\n\ncheck_creds() {\n  [ -n \"$YOUR_IPSEC_PSK\" ] && VPN_IPSEC_PSK=\"$YOUR_IPSEC_PSK\"\n  [ -n \"$YOUR_USERNAME\" ] && VPN_USER=\"$YOUR_USERNAME\"\n  [ -n \"$YOUR_PASSWORD\" ] && VPN_PASSWORD=\"$YOUR_PASSWORD\"\n  if [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n    return 0\n  fi\n  if [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n}\n\ncheck_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"The DNS server specified is invalid.\"\n  fi\n}\n\ncheck_server_dns() {\n  if [ -n \"$VPN_DNS_NAME\" ] && ! check_dns_name \"$VPN_DNS_NAME\"; then\n    exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    name_len=\"$(printf '%s' \"$VPN_CLIENT_NAME\" | wc -m)\"\n    if [ \"$name_len\" -gt \"64\" ] || printf '%s' \"$VPN_CLIENT_NAME\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n      || case $VPN_CLIENT_NAME in -*) true ;; *) false ;; esac; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    fi\n  fi\n}\n\nwait_for_apt() {\n  count=0\n  apt_lk=/var/lib/apt/lists/lock\n  pkg_lk=/var/lib/dpkg/lock\n  while fuser \"$apt_lk\" \"$pkg_lk\" >/dev/null 2>&1 \\\n    || lsof \"$apt_lk\" >/dev/null 2>&1 || lsof \"$pkg_lk\" >/dev/null 2>&1; do\n    [ \"$count\" = 0 ] && echo \"## Waiting for apt to be available...\"\n    [ \"$count\" -ge 200 ] && exiterr \"Could not get apt/dpkg lock.\"\n    count=$((count+1))\n    printf '%s' '.'\n    sleep 3\n  done\n}\n\ninstall_pkgs() {\n  if ! command -v wget >/dev/null 2>&1; then\n    if [ \"$os_type\" = \"ubuntu\" ] || [ \"$os_type\" = \"debian\" ]; then\n      wait_for_apt\n      export DEBIAN_FRONTEND=noninteractive\n      (\n        set -x\n        apt-get -yqq update || apt-get -yqq update\n      ) || exiterr \"'apt-get update' failed.\"\n      (\n        set -x\n        apt-get -yqq install wget >/dev/null || apt-get -yqq install wget >/dev/null\n      ) || exiterr \"'apt-get install wget' failed.\"\n    elif [ \"$os_type\" != \"alpine\" ]; then\n      (\n        set -x\n        yum -y -q install wget >/dev/null || yum -y -q install wget >/dev/null\n      ) || exiterr \"'yum install wget' failed.\"\n    fi\n  fi\n  if [ \"$os_type\" = \"alpine\" ]; then\n    (\n      set -x\n      apk add -U -q bash coreutils grep net-tools sed wget\n    ) || exiterr \"'apk add' failed.\"\n  fi\n}\n\nget_setup_url() {\n  base_url1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master\"\n  base_url2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master\"\n  sh_file=\"vpnsetup_ubuntu.sh\"\n  if [ \"$os_type\" = \"centos\" ] || [ \"$os_type\" = \"rhel\" ] || [ \"$os_type\" = \"rocky\" ] \\\n    || [ \"$os_type\" = \"alma\" ] || [ \"$os_type\" = \"ol\" ]; then\n    sh_file=\"vpnsetup_centos.sh\"\n  elif [ \"$os_type\" = \"amzn\" ]; then\n    sh_file=\"vpnsetup_amzn.sh\"\n  elif [ \"$os_type\" = \"alpine\" ]; then\n    sh_file=\"vpnsetup_alpine.sh\"\n  fi\n  setup_url1=\"$base_url1/$sh_file\"\n  setup_url2=\"$base_url2/$sh_file\"\n}\n\nrun_setup() {\n  status=0\n  if tmpdir=$(mktemp --tmpdir -d vpn.XXXXX 2>/dev/null); then\n    if ( set -x; wget -t 3 -T 30 -q -O \"$tmpdir/vpn.sh\" \"$setup_url1\" \\\n      || wget -t 3 -T 30 -q -O \"$tmpdir/vpn.sh\" \"$setup_url2\" \\\n      || curl -m 30 -fsL \"$setup_url1\" -o \"$tmpdir/vpn.sh\" 2>/dev/null ); then\n      VPN_IPSEC_PSK=\"$VPN_IPSEC_PSK\" VPN_USER=\"$VPN_USER\" \\\n      VPN_PASSWORD=\"$VPN_PASSWORD\" \\\n      VPN_PUBLIC_IP=\"$VPN_PUBLIC_IP\" VPN_L2TP_NET=\"$VPN_L2TP_NET\" \\\n      VPN_L2TP_LOCAL=\"$VPN_L2TP_LOCAL\" VPN_L2TP_POOL=\"$VPN_L2TP_POOL\" \\\n      VPN_XAUTH_NET=\"$VPN_XAUTH_NET\" VPN_XAUTH_POOL=\"$VPN_XAUTH_POOL\" \\\n      VPN_DNS_SRV1=\"$VPN_DNS_SRV1\" VPN_DNS_SRV2=\"$VPN_DNS_SRV2\" \\\n      VPN_DNS_NAME=\"$VPN_DNS_NAME\" VPN_CLIENT_NAME=\"$VPN_CLIENT_NAME\" \\\n      VPN_PROTECT_CONFIG=\"$VPN_PROTECT_CONFIG\" \\\n      VPN_CLIENT_VALIDITY=\"$VPN_CLIENT_VALIDITY\" \\\n      VPN_SKIP_IKEV2=\"$VPN_SKIP_IKEV2\" VPN_SWAN_VER=\"$VPN_SWAN_VER\" \\\n      VPN_PUBLIC_IP6=\"$VPN_PUBLIC_IP6\" VPN_IP6_NET=\"$VPN_IP6_NET\" \\\n      /bin/bash \"$tmpdir/vpn.sh\" || status=1\n    else\n      status=1\n      echo \"Error: Could not download VPN setup script.\" >&2\n    fi\n    /bin/rm -f \"$tmpdir/vpn.sh\"\n    /bin/rmdir \"$tmpdir\"\n  else\n    exiterr \"Could not create temporary directory.\"\n  fi\n}\n\nvpnsetup() {\n  check_root\n  check_vz\n  check_lxc\n  check_os\n  check_iface\n  check_creds\n  check_dns\n  check_server_dns\n  check_client_name\n  install_pkgs\n  get_setup_url\n  run_setup\n}\n\n## Defer setup until we have the complete script\nvpnsetup \"$@\"\n\nexit \"$status\"\n"
  },
  {
    "path": "vpnsetup_alpine.sh",
    "content": "#!/bin/bash\n#\n# Script for automatic setup of an IPsec VPN server on Alpine Linux\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2021-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - IPsec pre-shared key, VPN username and password\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_IPSEC_PSK=''\nYOUR_USERNAME=''\nYOUR_PASSWORD=''\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'apk add' failed.\"; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nbigecho() { echo \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_ip6() {\n  IP6_REGEX='^[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){1,7}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP6_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_os() {\n  os_type=$(lsb_release -si 2>/dev/null)\n  [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n  case $os_type in\n    [Aa]lpine)\n      os_type=alpine\n      ;;\n    *)\n      exiterr \"This script only supports Alpine Linux.\"\n      ;;\n  esac\n  os_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\" | cut -d '.' -f 1,2)\n  if [ \"$os_ver\" != \"3.22\" ] && [ \"$os_ver\" != \"3.23\" ]; then\n    exiterr \"This script only supports Alpine Linux 3.22/3.23.\"\n  fi\n}\n\ncheck_iface() {\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    if ! uname -m | grep -qi -e '^arm' -e '^aarch64'; then\n      case $def_iface in\n        wl*)\n          exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n          ;;\n      esac\n    fi\n    NET_IFACE=\"$def_iface\"\n  else\n    eth0_state=$(cat \"/sys/class/net/eth0/operstate\" 2>/dev/null)\n    if [ -z \"$eth0_state\" ] || [ \"$eth0_state\" = \"down\" ]; then\n      exiterr \"Could not detect the default network interface.\"\n    fi\n    NET_IFACE=eth0\n  fi\n}\n\ncheck_creds() {\n  [ -n \"$YOUR_IPSEC_PSK\" ] && VPN_IPSEC_PSK=\"$YOUR_IPSEC_PSK\"\n  [ -n \"$YOUR_USERNAME\" ] && VPN_USER=\"$YOUR_USERNAME\"\n  [ -n \"$YOUR_PASSWORD\" ] && VPN_PASSWORD=\"$YOUR_PASSWORD\"\n  if [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n    bigecho \"VPN credentials not set by user. Generating random PSK and password...\"\n    VPN_IPSEC_PSK=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 20)\n    VPN_USER=vpnuser\n    VPN_PASSWORD=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 16)\n  fi\n  if [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n}\n\ncheck_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"The DNS server specified is invalid.\"\n  fi\n}\n\ncheck_server_dns() {\n  if [ -n \"$VPN_DNS_NAME\" ] && ! check_dns_name \"$VPN_DNS_NAME\"; then\n    exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    name_len=\"$(printf '%s' \"$VPN_CLIENT_NAME\" | wc -m)\"\n    if [ \"$name_len\" -gt \"64\" ] || printf '%s' \"$VPN_CLIENT_NAME\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n      || case $VPN_CLIENT_NAME in -*) true ;; *) false ;; esac; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    fi\n  fi\n}\n\ncheck_subnets() {\n  if [ -s /etc/ipsec.conf ] && grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n    XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n    if ! grep -q \"$L2TP_NET\" /etc/ipsec.conf \\\n      || ! grep -q \"$XAUTH_NET\" /etc/ipsec.conf; then\n      echo \"Error: The custom VPN subnets specified do not match initial install.\" >&2\n      echo \"       See Advanced usage -> Customize VPN subnets for more information.\" >&2\n      exit 1\n    fi\n  fi\n}\n\nstart_setup() {\n  bigecho \"VPN setup in progress... Please be patient.\"\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_setup_pkgs() {\n  bigecho \"Installing packages required for setup...\"\n  (\n    set -x\n    apk add -U -q bash bind-tools coreutils openssl wget iptables ip6tables iproute2 sed grep\n  ) || exiterr2\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\ndetect_ip() {\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && return 0\n  bigecho \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n  check_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP. Define it as variable 'VPN_PUBLIC_IP' and re-run this script.\"\n}\n\ndetect_ipv6() {\n  ip6=\"\"\n  if ! printf '%s\\n%s' \"5.0\" \"$SWAN_VER\" | sort -C -V; then\n    return 0\n  fi\n  if [ -n \"$VPN_PUBLIC_IP6\" ]; then\n    ip6=\"$VPN_PUBLIC_IP6\"\n    check_ip6 \"$ip6\" || { echo \"Warning: Invalid IPv6 address in 'VPN_PUBLIC_IP6'. Detecting IPv6...\" >&2; ip6=\"\"; }\n  fi\n  [ -z \"$ip6\" ] && ip6=$(ip -6 addr 2>/dev/null | awk '/inet6 [23]/ {print $2}' | cut -d'/' -f1 | head -n1)\n  check_ip6 \"$ip6\" || ip6=\"\"\n}\n\ninstall_vpn_pkgs() {\n  bigecho \"Installing packages required for the VPN...\"\n  (\n    set -x\n    apk add -U -q libcap-ng libcurl libevent linux-pam musl nspr nss nss-tools \\\n      bison flex gcc make libc-dev bsd-compat-headers linux-pam-dev nss-dev \\\n      libcap-ng-dev libevent-dev curl-dev nspr-dev uuidgen openrc xl2tpd\n  ) || exiterr2\n}\n\ninstall_fail2ban() {\n  bigecho \"Installing Fail2Ban to protect SSH...\"\n  (\n    set -x\n    apk add -U -q fail2ban\n  )\n}\n\nlink_scripts() {\n  cd /opt/src || exit 1\n  /bin/mv -f ikev2setup.sh ikev2.sh\n  /bin/mv -f add_vpn_user.sh addvpnuser.sh\n  /bin/mv -f del_vpn_user.sh delvpnuser.sh\n  echo \"+ ikev2.sh addvpnuser.sh delvpnuser.sh\"\n  for sc in ikev2.sh addvpnuser.sh delvpnuser.sh; do\n    [ -s \"$sc\" ] && chmod +x \"$sc\" && ln -s \"/opt/src/$sc\" /usr/bin 2>/dev/null\n  done\n}\n\nget_helper_scripts() {\n  bigecho \"Downloading helper scripts...\"\n  base1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras\"\n  base2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras\"\n  sc1=ikev2setup.sh\n  sc2=add_vpn_user.sh\n  sc3=del_vpn_user.sh\n  cd /opt/src || exit 1\n  /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n  if wget -t 3 -T 30 -q \"$base1/$sc1\" \"$base1/$sc2\" \"$base1/$sc3\"; then\n    link_scripts\n  else\n    /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    if wget -t 3 -T 30 -q \"$base2/$sc1\" \"$base2/$sc2\" \"$base2/$sc3\"; then\n      link_scripts\n    else\n      echo \"Warning: Could not download helper scripts.\" >&2\n      /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    fi\n  fi\n}\n\nget_swan_ver() {\n  SWAN_VER=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  [ -z \"$swan_ver_latest\" ] && swan_ver_latest=$(curl -m 10 -fsL \"$swan_ver_url\" 2>/dev/null | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    SWAN_VER=\"$swan_ver_latest\"\n  fi\n  if [ -n \"$VPN_SWAN_VER\" ]; then\n    if ! printf '%s\\n%s' \"4.15\" \"$VPN_SWAN_VER\" | sort -C -V \\\n      || ! printf '%s\\n%s' \"$VPN_SWAN_VER\" \"$SWAN_VER\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$VPN_SWAN_VER' is not supported.\n       This script can install Libreswan 4.15+ or $SWAN_VER.\nEOF\n      exit 1\n    else\n      SWAN_VER=\"$VPN_SWAN_VER\"\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  check_result=0\n  [ ! -d /etc/ipsec.d ] && { get_swan_ver; return 0; }\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  ipsec_bin=\"/usr/local/sbin/ipsec\"\n  if [ -n \"$swan_ver_old\" ] && printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan' \\\n    && [ \"$(find \"$ipsec_bin\" -mmin -10080)\" ]; then\n    check_result=1\n    return 0\n  fi\n  get_swan_ver\n  if [ -s \"$ipsec_bin\" ] && [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\n    touch \"$ipsec_bin\"\n  fi\n  [ \"$swan_ver_old\" = \"$SWAN_VER\" ] && check_result=1\n}\n\nget_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Downloading Libreswan...\"\n    cd /opt/src || exit 1\n    swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n    swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n    swan_url2=\"https://download.libreswan.org/$swan_file\"\n    (\n      set -x\n      wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n    ) || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n  else\n    bigecho \"Libreswan $swan_ver_old is already installed, skipping...\"\n  fi\n}\n\ninstall_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Compiling and installing Libreswan, please wait...\"\n    cd \"libreswan-$SWAN_VER\" || exit 1\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n    NPROCS=$(grep -c ^processor /proc/cpuinfo)\n    [ -z \"$NPROCS\" ] && NPROCS=1\n    (\n      set -x\n      make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n    )\n    cd /opt/src || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\" \\\n      || [ ! -d /etc/ipsec.d ]; then\n      exiterr \"Libreswan $SWAN_VER failed to build.\"\n    fi\n  fi\n}\n\ncreate_vpn_config() {\n  bigecho \"Creating VPN configuration...\"\n  L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n  L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}\n  L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}\n  XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n  XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\n  DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}\n  DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}\n  DNS_SRVS=\"\\\"$DNS_SRV1 $DNS_SRV2\\\"\"\n  [ -n \"$VPN_DNS_SRV1\" ] && [ -z \"$VPN_DNS_SRV2\" ] && DNS_SRVS=\"$DNS_SRV1\"\n  IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n  vp_ip6=\"\"\n  [ -n \"$ip6\" ] && vp_ip6=\",%v6:fc00::/7,%v6:!$IP6_NET\"\n  # Create IPsec config\n  conf_bk \"/etc/ipsec.conf\"\ncat > /etc/ipsec.conf <<EOF\nversion 2.0\n\nconfig setup\n  ikev1-policy=accept\n  virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET$vp_ip6\n  uniqueids=no\n\nconn shared\n  left=%defaultroute\n  leftid=$public_ip\n  right=%any\n  encapsulation=yes\n  authby=secret\n  pfs=no\n  rekey=no\n  dpddelay=30\n  dpdtimeout=300\n  ikev2=never\n  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\n  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\n  ikelifetime=24h\n  salifetime=24h\n  sha2-truncbug=no\n\nconn l2tp-psk\n  auto=add\n  leftprotoport=17/1701\n  rightprotoport=17/%any\n  type=transport\n  also=shared\n\nconn xauth-psk\n  auto=add\n  leftsubnet=0.0.0.0/0\n  rightaddresspool=$XAUTH_POOL\n  modecfgdns=$DNS_SRVS\n  leftxauthserver=yes\n  rightxauthclient=yes\n  leftmodecfgserver=yes\n  rightmodecfgclient=yes\n  modecfgpull=yes\n  cisco-unity=yes\n  also=shared\n\ninclude /etc/ipsec.d/*.conf\nEOF\n  if uname -m | grep -qi '^arm'; then\n    if ! modprobe -q sha512; then\n      sed -i '/phase2alg/s/,aes256-sha2_512//' /etc/ipsec.conf\n    fi\n  fi\n  # Specify IPsec PSK\n  conf_bk \"/etc/ipsec.secrets\"\ncat > /etc/ipsec.secrets <<EOF\n%any  %any  : PSK \"$VPN_IPSEC_PSK\"\nEOF\n  # Create xl2tpd config\n  conf_bk \"/etc/xl2tpd/xl2tpd.conf\"\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[global]\nport = 1701\n\n[lns default]\nip range = $L2TP_POOL\nlocal ip = $L2TP_LOCAL\nrequire chap = yes\nrefuse pap = yes\nrequire authentication = yes\nname = l2tpd\npppoptfile = /etc/ppp/options.xl2tpd\nlength bit = yes\nEOF\n  # Set xl2tpd options\n  conf_bk \"/etc/ppp/options.xl2tpd\"\ncat > /etc/ppp/options.xl2tpd <<EOF\n+mschap-v2\nipcp-accept-local\nipcp-accept-remote\nnoccp\nauth\nmtu 1280\nmru 1280\nproxyarp\nlcp-echo-failure 4\nlcp-echo-interval 30\nconnect-delay 5000\nms-dns $DNS_SRV1\nEOF\n  if [ -z \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_DNS_SRV2\" ]; then\ncat >> /etc/ppp/options.xl2tpd <<EOF\nms-dns $DNS_SRV2\nEOF\n  fi\n  # Create VPN credentials\n  conf_bk \"/etc/ppp/chap-secrets\"\ncat > /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n  conf_bk \"/etc/ipsec.d/passwd\"\n  VPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat > /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n}\n\nupdate_sysctl() {\n  bigecho \"Updating sysctl settings...\"\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    conf_bk \"/etc/sysctl.conf\"\ncat >> /etc/sysctl.conf <<EOF\n\n# Added by hwdsl2 VPN script\nkernel.msgmnb = 65536\nkernel.msgmax = 65536\n\nnet.ipv4.ip_forward = 1\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.all.send_redirects = 0\nnet.ipv4.conf.all.rp_filter = 0\nnet.ipv4.conf.default.accept_redirects = 0\nnet.ipv4.conf.default.send_redirects = 0\nnet.ipv4.conf.default.rp_filter = 0\nnet.ipv4.conf.$NET_IFACE.send_redirects = 0\nnet.ipv4.conf.$NET_IFACE.rp_filter = 0\n\nnet.core.wmem_max = 16777216\nnet.core.rmem_max = 16777216\nnet.ipv4.tcp_rmem = 4096 87380 16777216\nnet.ipv4.tcp_wmem = 4096 87380 16777216\nEOF\n    if [ -n \"$ip6\" ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.ipv6.conf.all.forwarding = 1\nEOF\n    fi\n  fi\n}\n\nupdate_iptables() {\n  bigecho \"Updating IPTables rules...\"\n  IPT_FILE=/etc/iptables.rules\n  ipt_flag=0\n  if ! grep -qs \"hwdsl2 VPN script\" \"$IPT_FILE\"; then\n    ipt_flag=1\n  fi\n  ipi='iptables -I INPUT'\n  ipf='iptables -I FORWARD'\n  ipp='iptables -t nat -I POSTROUTING'\n  res='RELATED,ESTABLISHED'\n  if [ \"$ipt_flag\" = 1 ]; then\n    service fail2ban stop >/dev/null 2>&1\n    iptables-save > \"$IPT_FILE.old-$SYS_DT\"\n    $ipi 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP\n    $ipi 2 -m conntrack --ctstate INVALID -j DROP\n    $ipi 3 -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipi 4 -p udp -m multiport --dports 500,4500 -j ACCEPT\n    $ipi 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT\n    $ipi 6 -p udp --dport 1701 -j DROP\n    $ipf 1 -m conntrack --ctstate INVALID -j DROP\n    $ipf 2 -i \"$NET_IFACE\" -o ppp+ -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 3 -i ppp+ -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 4 -i ppp+ -o ppp+ -j ACCEPT\n    $ipf 5 -i \"$NET_IFACE\" -d \"$XAUTH_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 6 -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 7 -s \"$XAUTH_NET\" -o ppp+ -j ACCEPT\n    iptables -A FORWARD -j DROP\n    $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n    $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\n    echo \"# Modified by hwdsl2 VPN script\" > \"$IPT_FILE\"\n    iptables-save >> \"$IPT_FILE\"\n    if [ -n \"$ip6\" ]; then\n      IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n      IPT6_FILE=/etc/ip6tables.rules\n      ip6tables-save > \"$IPT6_FILE.old-$SYS_DT\"\n      ip6ti='ip6tables -I INPUT'\n      ip6tf='ip6tables -I FORWARD'\n      ip6tp='ip6tables -t nat -I POSTROUTING'\n      $ip6ti 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6ti 2 -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6ti 3 -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ip6tf 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6tf 2 -i \"$NET_IFACE\" -d \"$IP6_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6tf 3 -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      $ip6tp -s \"$IP6_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n      echo \"# Modified by hwdsl2 VPN script\" > \"$IPT6_FILE\"\n      ip6tables-save >> \"$IPT6_FILE\"\n    fi\n  fi\n}\n\nenable_on_boot() {\n  bigecho \"Enabling services on boot...\"\n  mkdir -p /etc/network/if-pre-up.d\ncat > /etc/network/if-pre-up.d/iptablesload <<'EOF'\n#!/bin/sh\niptables-restore < /etc/iptables.rules\n[ -f /etc/ip6tables.rules ] && ip6tables-restore < /etc/ip6tables.rules\nexit 0\nEOF\n  chmod +x /etc/network/if-pre-up.d/iptablesload\n  sed -i '1c\\#!/sbin/openrc-run' /etc/init.d/ipsec\n  for svc in fail2ban ipsec xl2tpd; do\n    rc-update add \"$svc\" default >/dev/null 2>&1\n  done\n}\n\nstart_services() {\n  bigecho \"Starting services...\"\n  sysctl -e -q -p\n  chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\n  mkdir -p /run/pluto\n  service fail2ban restart >/dev/null 2>&1\n  service ipsec restart >/dev/null 2>&1\n  service xl2tpd restart >/dev/null 2>&1\n  mkdir -p /etc/crontabs\n  cron_cmd=\"rc-service -c ipsec zap start\"\n  if ! grep -qs \"$cron_cmd\" /etc/crontabs/root; then\ncat >> /etc/crontabs/root <<EOF\n* * * * * $cron_cmd\n* * * * * sleep 15; $cron_cmd\n* * * * * sleep 30; $cron_cmd\n* * * * * sleep 45; $cron_cmd\nEOF\n    touch /etc/crontabs/cron.update\n  fi\n}\n\nshow_vpn_info() {\ncat <<EOF\n\n================================================\n\nIPsec VPN server is now ready for use!\n\nConnect to your new VPN with these details:\n\nServer IP: $public_ip\nIPsec PSK: $VPN_IPSEC_PSK\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n================================================\n\nEOF\n}\n\nset_up_ikev2() {\n  status=0\n  if [ -s /opt/src/ikev2.sh ] && [ ! -f /etc/ipsec.d/ikev2.conf ]; then\n    skip_ikev2=0\n    case $VPN_SKIP_IKEV2 in\n      [yY][eE][sS])\n        skip_ikev2=1\n        ;;\n    esac\n    if [ \"$skip_ikev2\" = 0 ]; then\n      sleep 1\n      VPN_DNS_NAME=\"$VPN_DNS_NAME\" VPN_PUBLIC_IP=\"$public_ip\" \\\n      VPN_CLIENT_NAME=\"$VPN_CLIENT_NAME\" VPN_XAUTH_POOL=\"$VPN_XAUTH_POOL\" \\\n      VPN_DNS_SRV1=\"$VPN_DNS_SRV1\" VPN_DNS_SRV2=\"$VPN_DNS_SRV2\" \\\n      VPN_PROTECT_CONFIG=\"$VPN_PROTECT_CONFIG\" \\\n      VPN_CLIENT_VALIDITY=\"$VPN_CLIENT_VALIDITY\" \\\n      VPN_PUBLIC_IP6=\"$ip6\" \\\n      /bin/bash /opt/src/ikev2.sh --auto || status=1\n    fi\n  elif [ -s /opt/src/ikev2.sh ]; then\ncat <<'EOF'\n================================================\n\nIKEv2 is already set up on this server.\n\nNext steps: Configure IKEv2 clients. See:\nhttps://vpnsetup.net/clients\n\nTo manage IKEv2 clients, run: sudo ikev2.sh\n\n================================================\n\nEOF\n  fi\n}\n\nvpnsetup() {\n  check_root\n  check_vz\n  check_os\n  check_iface\n  check_creds\n  check_dns\n  check_server_dns\n  check_client_name\n  check_subnets\n  check_libreswan\n  start_setup\n  install_setup_pkgs\n  detect_ip\n  detect_ipv6\n  install_vpn_pkgs\n  install_fail2ban\n  get_helper_scripts\n  get_libreswan\n  install_libreswan\n  create_vpn_config\n  update_sysctl\n  update_iptables\n  enable_on_boot\n  start_services\n  show_vpn_info\n  set_up_ikev2\n}\n\n## Defer setup until we have the complete script\nvpnsetup \"$@\"\n\nexit \"$status\"\n"
  },
  {
    "path": "vpnsetup_amzn.sh",
    "content": "#!/bin/bash\n#\n# Script for automatic setup of an IPsec VPN server on Amazon Linux 2\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2020-2026 Lin Song <linsongui@gmail.com>\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - IPsec pre-shared key, VPN username and password\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_IPSEC_PSK=''\nYOUR_USERNAME=''\nYOUR_PASSWORD=''\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'yum install' failed.\"; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nbigecho() { echo \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_ip6() {\n  IP6_REGEX='^[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){1,7}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP6_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_os() {\n  if ! grep -qs \"Amazon Linux release 2 \" /etc/system-release; then\n    if grep -qs \"Amazon Linux release 2023\" /etc/system-release; then\n      exiterr \"Amazon Linux 2023 is not supported.\"\n    else\n      exiterr \"This script only supports Amazon Linux 2.\"\n    fi\n  fi\n}\n\ncheck_iface() {\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  [ -z \"$def_iface\" ] && def_iface=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    case $def_iface in\n      wl*)\n        exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n        ;;\n    esac\n    NET_IFACE=\"$def_iface\"\n  else\n    eth0_state=$(cat \"/sys/class/net/eth0/operstate\" 2>/dev/null)\n    if [ -z \"$eth0_state\" ] || [ \"$eth0_state\" = \"down\" ]; then\n      exiterr \"Could not detect the default network interface.\"\n    fi\n    NET_IFACE=eth0\n  fi\n}\n\ncheck_creds() {\n  [ -n \"$YOUR_IPSEC_PSK\" ] && VPN_IPSEC_PSK=\"$YOUR_IPSEC_PSK\"\n  [ -n \"$YOUR_USERNAME\" ] && VPN_USER=\"$YOUR_USERNAME\"\n  [ -n \"$YOUR_PASSWORD\" ] && VPN_PASSWORD=\"$YOUR_PASSWORD\"\n  if [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n    bigecho \"VPN credentials not set by user. Generating random PSK and password...\"\n    VPN_IPSEC_PSK=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 20)\n    VPN_USER=vpnuser\n    VPN_PASSWORD=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 16)\n  fi\n  if [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n}\n\ncheck_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"The DNS server specified is invalid.\"\n  fi\n}\n\ncheck_server_dns() {\n  if [ -n \"$VPN_DNS_NAME\" ] && ! check_dns_name \"$VPN_DNS_NAME\"; then\n    exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    name_len=\"$(printf '%s' \"$VPN_CLIENT_NAME\" | wc -m)\"\n    if [ \"$name_len\" -gt \"64\" ] || printf '%s' \"$VPN_CLIENT_NAME\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n      || case $VPN_CLIENT_NAME in -*) true ;; *) false ;; esac; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    fi\n  fi\n}\n\ncheck_subnets() {\n  if [ -s /etc/ipsec.conf ] && grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n    XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n    if ! grep -q \"$L2TP_NET\" /etc/ipsec.conf \\\n      || ! grep -q \"$XAUTH_NET\" /etc/ipsec.conf; then\n      echo \"Error: The custom VPN subnets specified do not match initial install.\" >&2\n      echo \"       See Advanced usage -> Customize VPN subnets for more information.\" >&2\n      exit 1\n    fi\n  fi\n}\n\nstart_setup() {\n  bigecho \"VPN setup in progress... Please be patient.\"\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_setup_pkgs() {\n  bigecho \"Installing packages required for setup...\"\n  (\n    set -x\n    yum -y -q install wget bind-utils openssl tar \\\n      iptables iproute gawk grep sed net-tools >/dev/null\n  ) || exiterr2\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\ndetect_ip() {\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && return 0\n  bigecho \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n  check_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP. Define it as variable 'VPN_PUBLIC_IP' and re-run this script.\"\n}\n\ndetect_ipv6() {\n  ip6=\"\"\n  if ! printf '%s\\n%s' \"5.0\" \"$SWAN_VER\" | sort -C -V; then\n    return 0\n  fi\n  if [ -n \"$VPN_PUBLIC_IP6\" ]; then\n    ip6=\"$VPN_PUBLIC_IP6\"\n    check_ip6 \"$ip6\" || { echo \"Warning: Invalid IPv6 address in 'VPN_PUBLIC_IP6'. Detecting IPv6...\" >&2; ip6=\"\"; }\n  fi\n  [ -z \"$ip6\" ] && ip6=$(ip -6 addr 2>/dev/null | awk '/inet6 [23]/ {print $2}' | cut -d'/' -f1 | head -n1)\n  check_ip6 \"$ip6\" || ip6=\"\"\n}\n\nadd_epel_repo() {\n  bigecho \"Adding the EPEL repository...\"\n  (\n    set -x\n    amazon-linux-extras install epel -y >/dev/null\n  ) || exiterr2\n}\n\ninstall_vpn_pkgs_1() {\n  bigecho \"Installing packages required for the VPN...\"\n  (\n    set -x\n    yum -y -q install nss-devel nspr-devel pkgconfig pam-devel \\\n      libcap-ng-devel libselinux-devel curl-devel nss-tools \\\n      flex bison gcc make util-linux ppp \\\n      systemd-devel iptables-services \\\n      libevent-devel fipscheck-devel >/dev/null\n  ) || exiterr2\n}\n\ninstall_vpn_pkgs_2() {\n  (\n    set -x\n    yum --enablerepo=epel -y -q install xl2tpd >/dev/null 2>&1\n  ) || exiterr2\n}\n\ncreate_f2b_config() {\n  F2B_FILE=/etc/fail2ban/jail.local\n  if [ ! -f \"$F2B_FILE\" ]; then\n    bigecho \"Creating basic Fail2Ban rules...\"\ncat > \"$F2B_FILE\" <<'EOF'\n[ssh-iptables]\nenabled = true\nfilter = sshd\nlogpath = /var/log/secure\naction = iptables[name=SSH, port=ssh, protocol=tcp]\nEOF\n  fi\n}\n\ninstall_fail2ban() {\n  bigecho \"Installing Fail2Ban to protect SSH...\"\n  (\n    set -x\n    yum --enablerepo=epel -y -q install fail2ban >/dev/null\n  ) && create_f2b_config\n}\n\nlink_scripts() {\n  cd /opt/src || exit 1\n  /bin/mv -f ikev2setup.sh ikev2.sh\n  /bin/mv -f add_vpn_user.sh addvpnuser.sh\n  /bin/mv -f del_vpn_user.sh delvpnuser.sh\n  echo \"+ ikev2.sh addvpnuser.sh delvpnuser.sh\"\n  for sc in ikev2.sh addvpnuser.sh delvpnuser.sh; do\n    [ -s \"$sc\" ] && chmod +x \"$sc\" && ln -s \"/opt/src/$sc\" /usr/bin 2>/dev/null\n  done\n}\n\nget_helper_scripts() {\n  bigecho \"Downloading helper scripts...\"\n  base1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras\"\n  base2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras\"\n  sc1=ikev2setup.sh\n  sc2=add_vpn_user.sh\n  sc3=del_vpn_user.sh\n  cd /opt/src || exit 1\n  /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n  if wget -t 3 -T 30 -q \"$base1/$sc1\" \"$base1/$sc2\" \"$base1/$sc3\"; then\n    link_scripts\n  else\n    /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    if wget -t 3 -T 30 -q \"$base2/$sc1\" \"$base2/$sc2\" \"$base2/$sc3\"; then\n      link_scripts\n    else\n      echo \"Warning: Could not download helper scripts.\" >&2\n      /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    fi\n  fi\n}\n\nget_swan_ver() {\n  SWAN_VER=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/v1-amzn-2-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  [ -z \"$swan_ver_latest\" ] && swan_ver_latest=$(curl -m 10 -fsL \"$swan_ver_url\" 2>/dev/null | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    SWAN_VER=\"$swan_ver_latest\"\n  fi\n  if [ -n \"$VPN_SWAN_VER\" ]; then\n    if ! printf '%s\\n%s' \"4.15\" \"$VPN_SWAN_VER\" | sort -C -V \\\n      || ! printf '%s\\n%s' \"$VPN_SWAN_VER\" \"$SWAN_VER\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$VPN_SWAN_VER' is not supported.\n       This script can install Libreswan 4.15+ or $SWAN_VER.\nEOF\n      exit 1\n    else\n      SWAN_VER=\"$VPN_SWAN_VER\"\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  check_result=0\n  [ ! -d /etc/ipsec.d ] && { get_swan_ver; return 0; }\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  ipsec_bin=\"/usr/local/sbin/ipsec\"\n  if [ -n \"$swan_ver_old\" ] && printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan' \\\n    && [ \"$(find \"$ipsec_bin\" -mmin -10080)\" ]; then\n    check_result=1\n    return 0\n  fi\n  get_swan_ver\n  if [ -s \"$ipsec_bin\" ] && [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\n    touch \"$ipsec_bin\"\n  fi\n  [ \"$swan_ver_old\" = \"$SWAN_VER\" ] && check_result=1\n}\n\nget_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Downloading Libreswan...\"\n    cd /opt/src || exit 1\n    swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n    swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n    swan_url2=\"https://download.libreswan.org/$swan_file\"\n    (\n      set -x\n      wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n    ) || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n  else\n    bigecho \"Libreswan $swan_ver_old is already installed, skipping...\"\n  fi\n}\n\ninstall_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Compiling and installing Libreswan, please wait...\"\n    cd \"libreswan-$SWAN_VER\" || exit 1\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nUSE_NSS_KDF=false\nUSE_LINUX_AUDIT=false\nUSE_SECCOMP=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n    if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n      echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n    fi\n    NPROCS=$(grep -c ^processor /proc/cpuinfo)\n    [ -z \"$NPROCS\" ] && NPROCS=1\n    (\n      set -x\n      make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n    )\n    cd /opt/src || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\" \\\n      || [ ! -d /etc/ipsec.d ]; then\n      exiterr \"Libreswan $SWAN_VER failed to build.\"\n    fi\n  fi\n}\n\ncreate_vpn_config() {\n  bigecho \"Creating VPN configuration...\"\n  L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n  L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}\n  L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}\n  XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n  XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\n  DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}\n  DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}\n  DNS_SRVS=\"\\\"$DNS_SRV1 $DNS_SRV2\\\"\"\n  [ -n \"$VPN_DNS_SRV1\" ] && [ -z \"$VPN_DNS_SRV2\" ] && DNS_SRVS=\"$DNS_SRV1\"\n  IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n  vp_ip6=\"\"\n  [ -n \"$ip6\" ] && vp_ip6=\",%v6:fc00::/7,%v6:!$IP6_NET\"\n  # Create IPsec config\n  conf_bk \"/etc/ipsec.conf\"\ncat > /etc/ipsec.conf <<EOF\nversion 2.0\n\nconfig setup\n  ikev1-policy=accept\n  virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET$vp_ip6\n  uniqueids=no\n\nconn shared\n  left=%defaultroute\n  leftid=$public_ip\n  right=%any\n  encapsulation=yes\n  authby=secret\n  pfs=no\n  rekey=no\n  dpddelay=30\n  dpdtimeout=300\n  ikev2=never\n  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\n  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\n  ikelifetime=24h\n  salifetime=24h\n  sha2-truncbug=no\n\nconn l2tp-psk\n  auto=add\n  leftprotoport=17/1701\n  rightprotoport=17/%any\n  type=transport\n  also=shared\n\nconn xauth-psk\n  auto=add\n  leftsubnet=0.0.0.0/0\n  rightaddresspool=$XAUTH_POOL\n  modecfgdns=$DNS_SRVS\n  leftxauthserver=yes\n  rightxauthclient=yes\n  leftmodecfgserver=yes\n  rightmodecfgclient=yes\n  modecfgpull=yes\n  cisco-unity=yes\n  also=shared\n\ninclude /etc/ipsec.d/*.conf\nEOF\n  # Specify IPsec PSK\n  conf_bk \"/etc/ipsec.secrets\"\ncat > /etc/ipsec.secrets <<EOF\n%any  %any  : PSK \"$VPN_IPSEC_PSK\"\nEOF\n  # Create xl2tpd config\n  conf_bk \"/etc/xl2tpd/xl2tpd.conf\"\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[global]\nport = 1701\n\n[lns default]\nip range = $L2TP_POOL\nlocal ip = $L2TP_LOCAL\nrequire chap = yes\nrefuse pap = yes\nrequire authentication = yes\nname = l2tpd\npppoptfile = /etc/ppp/options.xl2tpd\nlength bit = yes\nEOF\n  # Set xl2tpd options\n  conf_bk \"/etc/ppp/options.xl2tpd\"\ncat > /etc/ppp/options.xl2tpd <<EOF\n+mschap-v2\nipcp-accept-local\nipcp-accept-remote\nnoccp\nauth\nmtu 1280\nmru 1280\nproxyarp\nlcp-echo-failure 4\nlcp-echo-interval 30\nconnect-delay 5000\nms-dns $DNS_SRV1\nEOF\n  if [ -z \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_DNS_SRV2\" ]; then\ncat >> /etc/ppp/options.xl2tpd <<EOF\nms-dns $DNS_SRV2\nEOF\n  fi\n  # Create VPN credentials\n  conf_bk \"/etc/ppp/chap-secrets\"\ncat > /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n  conf_bk \"/etc/ipsec.d/passwd\"\n  VPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat > /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n}\n\nupdate_sysctl() {\n  bigecho \"Updating sysctl settings...\"\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    conf_bk \"/etc/sysctl.conf\"\ncat >> /etc/sysctl.conf <<EOF\n\n# Added by hwdsl2 VPN script\nkernel.msgmnb = 65536\nkernel.msgmax = 65536\n\nnet.ipv4.ip_forward = 1\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.all.send_redirects = 0\nnet.ipv4.conf.all.rp_filter = 0\nnet.ipv4.conf.default.accept_redirects = 0\nnet.ipv4.conf.default.send_redirects = 0\nnet.ipv4.conf.default.rp_filter = 0\nnet.ipv4.conf.$NET_IFACE.send_redirects = 0\nnet.ipv4.conf.$NET_IFACE.rp_filter = 0\n\nnet.core.wmem_max = 16777216\nnet.core.rmem_max = 16777216\nnet.ipv4.tcp_rmem = 4096 87380 16777216\nnet.ipv4.tcp_wmem = 4096 87380 16777216\nEOF\n    if [ -n \"$ip6\" ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.ipv6.conf.all.forwarding = 1\nEOF\n    fi\n  fi\n}\n\nupdate_iptables() {\n  bigecho \"Updating IPTables rules...\"\n  IPT_FILE=/etc/sysconfig/iptables\n  ipt_flag=0\n  if ! grep -qs \"hwdsl2 VPN script\" \"$IPT_FILE\"; then\n    ipt_flag=1\n  fi\n  ipi='iptables -I INPUT'\n  ipf='iptables -I FORWARD'\n  ipp='iptables -t nat -I POSTROUTING'\n  res='RELATED,ESTABLISHED'\n  if [ \"$ipt_flag\" = 1 ]; then\n    service fail2ban stop >/dev/null 2>&1\n    iptables-save > \"$IPT_FILE.old-$SYS_DT\"\n    $ipi 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP\n    $ipi 2 -m conntrack --ctstate INVALID -j DROP\n    $ipi 3 -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipi 4 -p udp -m multiport --dports 500,4500 -j ACCEPT\n    $ipi 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT\n    $ipi 6 -p udp --dport 1701 -j DROP\n    $ipf 1 -m conntrack --ctstate INVALID -j DROP\n    $ipf 2 -i \"$NET_IFACE\" -o ppp+ -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 3 -i ppp+ -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 4 -i ppp+ -o ppp+ -j ACCEPT\n    $ipf 5 -i \"$NET_IFACE\" -d \"$XAUTH_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 6 -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 7 -s \"$XAUTH_NET\" -o ppp+ -j ACCEPT\n    iptables -A FORWARD -j DROP\n    $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n    $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\n    echo \"# Modified by hwdsl2 VPN script\" > \"$IPT_FILE\"\n    iptables-save >> \"$IPT_FILE\"\n    if [ -n \"$ip6\" ]; then\n      IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n      IPT6_FILE=/etc/sysconfig/ip6tables\n      ip6tables-save > \"$IPT6_FILE.old-$SYS_DT\"\n      ip6ti='ip6tables -I INPUT'\n      ip6tf='ip6tables -I FORWARD'\n      ip6tp='ip6tables -t nat -I POSTROUTING'\n      $ip6ti 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6ti 2 -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6ti 3 -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ip6tf 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6tf 2 -i \"$NET_IFACE\" -d \"$IP6_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6tf 3 -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      $ip6tp -s \"$IP6_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n      echo \"# Modified by hwdsl2 VPN script\" > \"$IPT6_FILE\"\n      ip6tables-save >> \"$IPT6_FILE\"\n    fi\n  fi\n}\n\nenable_on_boot() {\n  bigecho \"Enabling services on boot...\"\n  systemctl --now mask firewalld 2>/dev/null\n  systemctl enable iptables 2>/dev/null\n  systemctl enable fail2ban 2>/dev/null\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/rc.local; then\n    if [ -f /etc/rc.local ]; then\n      conf_bk \"/etc/rc.local\"\n    else\n      echo '#!/bin/sh' > /etc/rc.local\n    fi\n    ip6_fwd_rc=\"\"\n    [ -n \"$ip6\" ] && ip6_fwd_rc='\necho 1 > /proc/sys/net/ipv6/conf/all/forwarding'\ncat >> /etc/rc.local <<EOF\n\n# Added by hwdsl2 VPN script\n(sleep 15\nservice ipsec restart\nservice xl2tpd restart\necho 1 > /proc/sys/net/ipv4/ip_forward${ip6_fwd_rc})&\nEOF\n  fi\n}\n\nstart_services() {\n  bigecho \"Starting services...\"\n  sysctl -e -q -p\n  chmod +x /etc/rc.local\n  chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\n  restorecon /etc/ipsec.d/*db 2>/dev/null\n  restorecon /usr/local/sbin -Rv 2>/dev/null\n  restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null\n  iptables-restore < \"$IPT_FILE\"\n  # Fix xl2tpd if l2tp_ppp is unavailable\n  if ! modprobe -q l2tp_ppp; then\n    sed -i '/^ExecStartPre=\\//s/=/=-/' /usr/lib/systemd/system/xl2tpd.service\n    systemctl daemon-reload\n  fi\n  mkdir -p /run/pluto\n  service fail2ban restart 2>/dev/null\n  service ipsec restart 2>/dev/null\n  service xl2tpd restart 2>/dev/null\n}\n\nshow_vpn_info() {\ncat <<EOF\n\n================================================\n\nIPsec VPN server is now ready for use!\n\nConnect to your new VPN with these details:\n\nServer IP: $public_ip\nIPsec PSK: $VPN_IPSEC_PSK\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n================================================\n\nEOF\n}\n\nset_up_ikev2() {\n  status=0\n  if [ -s /opt/src/ikev2.sh ] && [ ! -f /etc/ipsec.d/ikev2.conf ]; then\n    skip_ikev2=0\n    case $VPN_SKIP_IKEV2 in\n      [yY][eE][sS])\n        skip_ikev2=1\n        ;;\n    esac\n    if [ \"$skip_ikev2\" = 0 ]; then\n      sleep 1\n      VPN_DNS_NAME=\"$VPN_DNS_NAME\" VPN_PUBLIC_IP=\"$public_ip\" \\\n      VPN_CLIENT_NAME=\"$VPN_CLIENT_NAME\" VPN_XAUTH_POOL=\"$VPN_XAUTH_POOL\" \\\n      VPN_DNS_SRV1=\"$VPN_DNS_SRV1\" VPN_DNS_SRV2=\"$VPN_DNS_SRV2\" \\\n      VPN_PROTECT_CONFIG=\"$VPN_PROTECT_CONFIG\" \\\n      VPN_CLIENT_VALIDITY=\"$VPN_CLIENT_VALIDITY\" \\\n      VPN_PUBLIC_IP6=\"$ip6\" \\\n      /bin/bash /opt/src/ikev2.sh --auto || status=1\n    fi\n  elif [ -s /opt/src/ikev2.sh ]; then\ncat <<'EOF'\n================================================\n\nIKEv2 is already set up on this server.\n\nNext steps: Configure IKEv2 clients. See:\nhttps://vpnsetup.net/clients\n\nTo manage IKEv2 clients, run: sudo ikev2.sh\n\n================================================\n\nEOF\n  fi\n}\n\nvpnsetup() {\n  check_root\n  check_os\n  check_iface\n  check_creds\n  check_dns\n  check_server_dns\n  check_client_name\n  check_subnets\n  check_libreswan\n  start_setup\n  install_setup_pkgs\n  detect_ip\n  detect_ipv6\n  add_epel_repo\n  install_vpn_pkgs_1\n  install_vpn_pkgs_2\n  install_fail2ban\n  get_helper_scripts\n  get_libreswan\n  install_libreswan\n  create_vpn_config\n  update_sysctl\n  update_iptables\n  enable_on_boot\n  start_services\n  show_vpn_info\n  set_up_ikev2\n}\n\n## Defer setup until we have the complete script\nvpnsetup \"$@\"\n\nexit \"$status\"\n"
  },
  {
    "path": "vpnsetup_centos.sh",
    "content": "#!/bin/bash\n#\n# Script for automatic setup of an IPsec VPN server on CentOS/RHEL, Rocky Linux,\n# AlmaLinux and Oracle Linux\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2015-2026 Lin Song <linsongui@gmail.com>\n# Based on the work of Thomas Sarlandie (Copyright 2012)\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - IPsec pre-shared key, VPN username and password\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_IPSEC_PSK=''\nYOUR_USERNAME=''\nYOUR_PASSWORD=''\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'yum install' failed.\"; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nbigecho() { echo \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_ip6() {\n  IP6_REGEX='^[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){1,7}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP6_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_lxc() {\n  # shellcheck disable=SC2154\n  if [ \"$container\" = \"lxc\" ] && [ ! -e /dev/ppp ]; then\ncat 1>&2 <<'EOF'\nError: /dev/ppp is missing. LXC containers require configuration.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn/issues/1014\nEOF\n  exit 1\n  fi\n}\n\ncheck_os() {\n  rh_file=\"/etc/redhat-release\"\n  if [ -f \"$rh_file\" ]; then\n    os_type=centos\n    if grep -q \"Red Hat\" \"$rh_file\"; then\n      os_type=rhel\n    fi\n    [ -f /etc/oracle-release ] && os_type=ol\n    grep -qi rocky \"$rh_file\" && os_type=rocky\n    grep -qi alma \"$rh_file\" && os_type=alma\n    if grep -q \"release 7\" \"$rh_file\"; then\n      os_ver=7\n    elif grep -q \"release 8\" \"$rh_file\"; then\n      os_ver=8\n      grep -qi stream \"$rh_file\" && os_ver=8s\n    elif grep -q \"release 9\" \"$rh_file\"; then\n      os_ver=9\n      grep -qi stream \"$rh_file\" && os_ver=9s\n    elif grep -q \"release 10\" \"$rh_file\"; then\n      os_ver=10\n      grep -qi stream \"$rh_file\" && os_ver=10s\n    else\n      exiterr \"This script only supports CentOS/RHEL 7-10.\"\n    fi\n    if [ \"$os_type\" = \"centos\" ] \\\n      && { [ \"$os_ver\" = 7 ] || [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 8s ]; }; then\n      exiterr \"CentOS Linux $os_ver is EOL and not supported.\"\n    fi\n  else\ncat 1>&2 <<'EOF'\nError: This script only supports one of the following OS:\n       CentOS/RHEL, Rocky Linux, AlmaLinux or Oracle Linux\nEOF\n    exit 1\n  fi\n}\n\ncheck_iface() {\n  if ! command -v route >/dev/null 2>&1 && ! command -v ip >/dev/null 2>&1; then\n    (\n      set -x\n      yum -y -q install iproute >/dev/null || yum -y -q install iproute >/dev/null\n    )\n  fi\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  [ -z \"$def_iface\" ] && def_iface=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    case $def_iface in\n      wl*)\n        exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n        ;;\n    esac\n    NET_IFACE=\"$def_iface\"\n  else\n    eth0_state=$(cat \"/sys/class/net/eth0/operstate\" 2>/dev/null)\n    if [ -z \"$eth0_state\" ] || [ \"$eth0_state\" = \"down\" ]; then\n      exiterr \"Could not detect the default network interface.\"\n    fi\n    NET_IFACE=eth0\n  fi\n}\n\ncheck_creds() {\n  [ -n \"$YOUR_IPSEC_PSK\" ] && VPN_IPSEC_PSK=\"$YOUR_IPSEC_PSK\"\n  [ -n \"$YOUR_USERNAME\" ] && VPN_USER=\"$YOUR_USERNAME\"\n  [ -n \"$YOUR_PASSWORD\" ] && VPN_PASSWORD=\"$YOUR_PASSWORD\"\n  if [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n    bigecho \"VPN credentials not set by user. Generating random PSK and password...\"\n    VPN_IPSEC_PSK=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 20)\n    VPN_USER=vpnuser\n    VPN_PASSWORD=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 16)\n  fi\n  if [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n}\n\ncheck_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"The DNS server specified is invalid.\"\n  fi\n}\n\ncheck_server_dns() {\n  if [ -n \"$VPN_DNS_NAME\" ] && ! check_dns_name \"$VPN_DNS_NAME\"; then\n    exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    name_len=\"$(printf '%s' \"$VPN_CLIENT_NAME\" | wc -m)\"\n    if [ \"$name_len\" -gt \"64\" ] || printf '%s' \"$VPN_CLIENT_NAME\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n      || case $VPN_CLIENT_NAME in -*) true ;; *) false ;; esac; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    fi\n  fi\n}\n\ncheck_subnets() {\n  if [ -s /etc/ipsec.conf ] && grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n    XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n    if ! grep -q \"$L2TP_NET\" /etc/ipsec.conf \\\n      || ! grep -q \"$XAUTH_NET\" /etc/ipsec.conf; then\n      echo \"Error: The custom VPN subnets specified do not match initial install.\" >&2\n      echo \"       See Advanced usage -> Customize VPN subnets for more information.\" >&2\n      exit 1\n    fi\n  fi\n}\n\nstart_setup() {\n  bigecho \"VPN setup in progress... Please be patient.\"\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\ninstall_setup_pkgs() {\n  bigecho \"Installing packages required for setup...\"\n  (\n    set -x\n    yum -y -q install wget bind-utils openssl tar \\\n      iptables iproute gawk grep sed net-tools >/dev/null \\\n    || yum -y -q install wget bind-utils openssl tar \\\n      iptables iproute gawk grep sed net-tools >/dev/null\n  ) || exiterr2\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\ndetect_ip() {\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && return 0\n  bigecho \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n  check_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP. Define it as variable 'VPN_PUBLIC_IP' and re-run this script.\"\n}\n\ndetect_ipv6() {\n  ip6=\"\"\n  if ! printf '%s\\n%s' \"5.0\" \"$SWAN_VER\" | sort -C -V; then\n    return 0\n  fi\n  if [ -n \"$VPN_PUBLIC_IP6\" ]; then\n    ip6=\"$VPN_PUBLIC_IP6\"\n    check_ip6 \"$ip6\" || { echo \"Warning: Invalid IPv6 address in 'VPN_PUBLIC_IP6'. Detecting IPv6...\" >&2; ip6=\"\"; }\n  fi\n  [ -z \"$ip6\" ] && ip6=$(ip -6 addr 2>/dev/null | awk '/inet6 [23]/ {print $2}' | cut -d'/' -f1 | head -n1)\n  check_ip6 \"$ip6\" || ip6=\"\"\n}\n\nadd_epel_repo() {\n  bigecho \"Adding the EPEL repository...\"\n  epel_url=\"https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E '%{rhel}').noarch.rpm\"\n  (\n    set -x\n    yum -y -q install epel-release >/dev/null 2>&1 || yum -y -q install \"$epel_url\" >/dev/null\n  ) || exiterr2\n}\n\ninstall_vpn_pkgs_1() {\n  bigecho \"Installing packages required for the VPN...\"\n  erp=\"--enablerepo\"\n  rp1=\"$erp=epel\"\n  rp2=\"$erp=*server-*optional*\"\n  rp3=\"$erp=*releases-optional*\"\n  if [ \"$os_type\" = \"ol\" ]; then\n    if [ \"$os_ver\" = 9 ]; then\n      rp1=\"$erp=ol9_developer_EPEL\"\n    elif [ \"$os_ver\" = 8 ]; then\n      rp1=\"$erp=ol8_developer_EPEL\"\n    else\n      rp3=\"$erp=ol7_optional_latest\"\n    fi\n  fi\n  (\n    set -x\n    yum -y -q install nss-devel nspr-devel pkgconfig pam-devel \\\n      libcap-ng-devel libselinux-devel curl-devel nss-tools \\\n      flex bison gcc make util-linux ppp >/dev/null\n  ) || exiterr2\n}\n\ninstall_vpn_pkgs_2() {\n  (\n    set -x\n    yum \"$rp1\" -y -q install xl2tpd >/dev/null 2>&1\n  ) || exiterr2\n}\n\ninstall_vpn_pkgs_3() {\n  use_nft=0\n  p1=systemd-devel\n  p2=libevent-devel\n  p3=fipscheck-devel\n  p4=iptables-services\n  if [ \"$os_ver\" = 7 ]; then\n    (\n      set -x\n      yum \"$rp2\" \"$rp3\" -y -q install $p1 $p2 $p3 $p4 >/dev/null\n    ) || exiterr2\n  else\n    (\n      set -x\n      yum -y -q install $p1 $p2 >/dev/null\n    ) || exiterr2\n    if [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = 9s ] \\\n      || [ \"$os_ver\" = 10 ] || [ \"$os_ver\" = 10s ] \\\n      || systemctl is-active --quiet firewalld \\\n      || systemctl is-active --quiet nftables \\\n      || grep -qs \"hwdsl2 VPN script\" /etc/sysconfig/nftables.conf; then\n      use_nft=1\n      p4=nftables\n    fi\n    (\n      set -x\n      yum -y -q install $p4 >/dev/null\n    ) || exiterr2\n  fi\n}\n\ncreate_f2b_config() {\n  F2B_FILE=/etc/fail2ban/jail.local\n  if [ ! -f \"$F2B_FILE\" ]; then\n    bigecho \"Creating basic Fail2Ban rules...\"\ncat > \"$F2B_FILE\" <<'EOF'\n[ssh-iptables]\nenabled = true\nfilter = sshd\nlogpath = /var/log/secure\nEOF\n\n    if [ \"$use_nft\" = 1 ]; then\ncat >> \"$F2B_FILE\" <<'EOF'\nport = ssh\nbanaction = nftables-multiport[blocktype=drop]\nEOF\n    else\ncat >> \"$F2B_FILE\" <<'EOF'\naction = iptables[name=SSH, port=ssh, protocol=tcp]\nEOF\n    fi\n  fi\n}\n\ninstall_fail2ban() {\n  bigecho \"Installing Fail2Ban to protect SSH...\"\n  (\n    set -x\n    yum \"$rp1\" -y -q install fail2ban >/dev/null\n  ) && create_f2b_config\n}\n\nlink_scripts() {\n  cd /opt/src || exit 1\n  /bin/mv -f ikev2setup.sh ikev2.sh\n  /bin/mv -f add_vpn_user.sh addvpnuser.sh\n  /bin/mv -f del_vpn_user.sh delvpnuser.sh\n  echo \"+ ikev2.sh addvpnuser.sh delvpnuser.sh\"\n  for sc in ikev2.sh addvpnuser.sh delvpnuser.sh; do\n    [ -s \"$sc\" ] && chmod +x \"$sc\" && ln -s \"/opt/src/$sc\" /usr/bin 2>/dev/null\n  done\n}\n\nget_helper_scripts() {\n  bigecho \"Downloading helper scripts...\"\n  base1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras\"\n  base2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras\"\n  sc1=ikev2setup.sh\n  sc2=add_vpn_user.sh\n  sc3=del_vpn_user.sh\n  cd /opt/src || exit 1\n  /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n  if wget -t 3 -T 30 -q \"$base1/$sc1\" \"$base1/$sc2\" \"$base1/$sc3\"; then\n    link_scripts\n  else\n    /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    if wget -t 3 -T 30 -q \"$base2/$sc1\" \"$base2/$sc2\" \"$base2/$sc3\"; then\n      link_scripts\n    else\n      echo \"Warning: Could not download helper scripts.\" >&2\n      /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    fi\n  fi\n}\n\nget_swan_ver() {\n  SWAN_VER=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  [ -z \"$swan_ver_latest\" ] && swan_ver_latest=$(curl -m 10 -fsL \"$swan_ver_url\" 2>/dev/null | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    SWAN_VER=\"$swan_ver_latest\"\n  fi\n  if [ -n \"$VPN_SWAN_VER\" ]; then\n    if ! printf '%s\\n%s' \"4.15\" \"$VPN_SWAN_VER\" | sort -C -V \\\n      || ! printf '%s\\n%s' \"$VPN_SWAN_VER\" \"$SWAN_VER\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$VPN_SWAN_VER' is not supported.\n       This script can install Libreswan 4.15+ or $SWAN_VER.\nEOF\n      exit 1\n    else\n      SWAN_VER=\"$VPN_SWAN_VER\"\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  check_result=0\n  [ ! -d /etc/ipsec.d ] && { get_swan_ver; return 0; }\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  ipsec_bin=\"/usr/local/sbin/ipsec\"\n  if [ -n \"$swan_ver_old\" ] && printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan' \\\n    && [ \"$(find \"$ipsec_bin\" -mmin -10080)\" ]; then\n    check_result=1\n    return 0\n  fi\n  get_swan_ver\n  if [ -s \"$ipsec_bin\" ] && [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\n    touch \"$ipsec_bin\"\n  fi\n  [ \"$swan_ver_old\" = \"$SWAN_VER\" ] && check_result=1\n}\n\nget_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Downloading Libreswan...\"\n    cd /opt/src || exit 1\n    swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n    swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n    swan_url2=\"https://download.libreswan.org/$swan_file\"\n    (\n      set -x\n      wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n    ) || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n  else\n    bigecho \"Libreswan $swan_ver_old is already installed, skipping...\"\n  fi\n}\n\ninstall_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Compiling and installing Libreswan, please wait...\"\n    cd \"libreswan-$SWAN_VER\" || exit 1\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nUSE_NSS_KDF=false\nUSE_LINUX_AUDIT=false\nUSE_SECCOMP=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n    if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n      echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n    fi\n    NPROCS=$(grep -c ^processor /proc/cpuinfo)\n    [ -z \"$NPROCS\" ] && NPROCS=1\n    (\n      set -x\n      make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n    )\n    cd /opt/src || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\" \\\n      || [ ! -d /etc/ipsec.d ]; then\n      exiterr \"Libreswan $SWAN_VER failed to build.\"\n    fi\n  fi\n}\n\ncreate_vpn_config() {\n  bigecho \"Creating VPN configuration...\"\n  L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n  L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}\n  L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}\n  XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n  XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\n  DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}\n  DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}\n  DNS_SRVS=\"\\\"$DNS_SRV1 $DNS_SRV2\\\"\"\n  [ -n \"$VPN_DNS_SRV1\" ] && [ -z \"$VPN_DNS_SRV2\" ] && DNS_SRVS=\"$DNS_SRV1\"\n  IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n  vp_ip6=\"\"\n  [ -n \"$ip6\" ] && vp_ip6=\",%v6:fc00::/7,%v6:!$IP6_NET\"\n  # Create IPsec config\n  conf_bk \"/etc/ipsec.conf\"\ncat > /etc/ipsec.conf <<EOF\nversion 2.0\n\nconfig setup\n  ikev1-policy=accept\n  virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET$vp_ip6\n  uniqueids=no\n\nconn shared\n  left=%defaultroute\n  leftid=$public_ip\n  right=%any\n  encapsulation=yes\n  authby=secret\n  pfs=no\n  rekey=no\n  dpddelay=30\n  dpdtimeout=300\n  ikev2=never\n  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\n  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\n  ikelifetime=24h\n  salifetime=24h\n  sha2-truncbug=no\n\nconn l2tp-psk\n  auto=add\n  leftprotoport=17/1701\n  rightprotoport=17/%any\n  type=transport\n  also=shared\n\nconn xauth-psk\n  auto=add\n  leftsubnet=0.0.0.0/0\n  rightaddresspool=$XAUTH_POOL\n  modecfgdns=$DNS_SRVS\n  leftxauthserver=yes\n  rightxauthclient=yes\n  leftmodecfgserver=yes\n  rightmodecfgclient=yes\n  modecfgpull=yes\n  cisco-unity=yes\n  also=shared\n\ninclude /etc/ipsec.d/*.conf\nEOF\n  # Specify IPsec PSK\n  conf_bk \"/etc/ipsec.secrets\"\ncat > /etc/ipsec.secrets <<EOF\n%any  %any  : PSK \"$VPN_IPSEC_PSK\"\nEOF\n  # Create xl2tpd config\n  conf_bk \"/etc/xl2tpd/xl2tpd.conf\"\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[global]\nport = 1701\n\n[lns default]\nip range = $L2TP_POOL\nlocal ip = $L2TP_LOCAL\nrequire chap = yes\nrefuse pap = yes\nrequire authentication = yes\nname = l2tpd\npppoptfile = /etc/ppp/options.xl2tpd\nlength bit = yes\nEOF\n  # Set xl2tpd options\n  conf_bk \"/etc/ppp/options.xl2tpd\"\ncat > /etc/ppp/options.xl2tpd <<EOF\n+mschap-v2\nipcp-accept-local\nipcp-accept-remote\nnoccp\nauth\nmtu 1280\nmru 1280\nproxyarp\nlcp-echo-failure 4\nlcp-echo-interval 30\nconnect-delay 5000\nms-dns $DNS_SRV1\nEOF\n  if [ -z \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_DNS_SRV2\" ]; then\ncat >> /etc/ppp/options.xl2tpd <<EOF\nms-dns $DNS_SRV2\nEOF\n  fi\n  # Create VPN credentials\n  conf_bk \"/etc/ppp/chap-secrets\"\ncat > /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n  conf_bk \"/etc/ipsec.d/passwd\"\n  VPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat > /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n}\n\nupdate_sysctl() {\n  bigecho \"Updating sysctl settings...\"\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    conf_bk \"/etc/sysctl.conf\"\ncat >> /etc/sysctl.conf <<EOF\n\n# Added by hwdsl2 VPN script\nkernel.msgmnb = 65536\nkernel.msgmax = 65536\n\nnet.ipv4.ip_forward = 1\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.all.send_redirects = 0\nnet.ipv4.conf.all.rp_filter = 0\nnet.ipv4.conf.default.accept_redirects = 0\nnet.ipv4.conf.default.send_redirects = 0\nnet.ipv4.conf.default.rp_filter = 0\nnet.ipv4.conf.$NET_IFACE.send_redirects = 0\nnet.ipv4.conf.$NET_IFACE.rp_filter = 0\n\nnet.core.wmem_max = 16777216\nnet.core.rmem_max = 16777216\nnet.ipv4.tcp_rmem = 4096 87380 16777216\nnet.ipv4.tcp_wmem = 4096 87380 16777216\nEOF\n    if modprobe -q tcp_bbr \\\n      && printf '%s\\n%s' \"4.20\" \"$(uname -r)\" | sort -C -V \\\n      && [ -f /proc/sys/net/ipv4/tcp_congestion_control ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr\nEOF\n    fi\n    if [ -n \"$ip6\" ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.ipv6.conf.all.forwarding = 1\nEOF\n    fi\n  fi\n}\n\nupdate_iptables() {\n  bigecho \"Updating IPTables rules...\"\n  IPT_FILE=/etc/sysconfig/iptables\n  [ \"$use_nft\" = 1 ] && IPT_FILE=/etc/sysconfig/nftables.conf\n  ipt_flag=0\n  if ! grep -qs \"hwdsl2 VPN script\" \"$IPT_FILE\"; then\n    ipt_flag=1\n  fi\n  ipi='iptables -I INPUT'\n  ipf='iptables -I FORWARD'\n  ipp='iptables -t nat -I POSTROUTING'\n  res='RELATED,ESTABLISHED'\n  nff='nft insert rule inet firewalld'\n  nfn='nft insert rule inet nftables_svc'\n  if [ \"$ipt_flag\" = 1 ]; then\n    service fail2ban stop >/dev/null 2>&1\n    if [ \"$use_nft\" = 1 ]; then\n      fd_conf=/etc/firewalld/firewalld.conf\n      if grep -qs '^NftablesTableOwner=yes' \"$fd_conf\"; then\n        sed -i '/NftablesTableOwner/s/yes/no/' \"$fd_conf\"\n        firewall-cmd --reload >/dev/null 2>&1\n      fi\n      nft list ruleset > \"$IPT_FILE.old-$SYS_DT\"\n      chmod 600 \"$IPT_FILE.old-$SYS_DT\"\n    else\n      iptables-save > \"$IPT_FILE.old-$SYS_DT\"\n    fi\n    $ipi 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP\n    $ipi 2 -m conntrack --ctstate INVALID -j DROP\n    $ipi 3 -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipi 4 -p udp -m multiport --dports 500,4500 -j ACCEPT\n    $ipi 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT\n    $ipi 6 -p udp --dport 1701 -j DROP\n    $ipf 1 -m conntrack --ctstate INVALID -j DROP\n    $ipf 2 -i \"$NET_IFACE\" -o ppp+ -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 3 -i ppp+ -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 4 -i ppp+ -o ppp+ -j ACCEPT\n    $ipf 5 -i \"$NET_IFACE\" -d \"$XAUTH_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 6 -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 7 -s \"$XAUTH_NET\" -o ppp+ -j ACCEPT\n    if [ \"$use_nft\" != 1 ]; then\n      iptables -A FORWARD -j DROP\n    fi\n    if [ \"$use_nft\" = 1 ]; then\n      $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" ! -d \"$XAUTH_NET\" -j MASQUERADE\n    else\n      $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n    fi\n    $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\n    if [ -n \"$ip6\" ]; then\n      IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n      ip6ti='ip6tables -I INPUT'\n      ip6tf='ip6tables -I FORWARD'\n      ip6tp='ip6tables -t nat -I POSTROUTING'\n      $ip6ti 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6ti 2 -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6ti 3 -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ip6tf 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6tf 2 -i \"$NET_IFACE\" -d \"$IP6_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6tf 3 -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      $ip6tp -s \"$IP6_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n    fi\n    echo \"# Modified by hwdsl2 VPN script\" > \"$IPT_FILE\"\n    if [ \"$use_nft\" = 1 ]; then\n      for vport in 500 4500 1701; do\n        $nff filter_INPUT udp dport \"$vport\" accept 2>/dev/null\n        $nfn allow udp dport \"$vport\" accept 2>/dev/null\n      done\n      for vnet in \"$L2TP_NET\" \"$XAUTH_NET\"; do\n        for vdir in saddr daddr; do\n          $nff filter_FORWARD ip \"$vdir\" \"$vnet\" accept 2>/dev/null\n          $nfn FORWARD ip \"$vdir\" \"$vnet\" accept 2>/dev/null\n        done\n      done\n      echo \"flush ruleset\" >> \"$IPT_FILE\"\n      nft list ruleset >> \"$IPT_FILE\"\n    else\n      iptables-save >> \"$IPT_FILE\"\n      if [ -n \"$ip6\" ]; then\n        IPT6_FILE=/etc/sysconfig/ip6tables\n        ip6tables-save > \"$IPT6_FILE.old-$SYS_DT\"\n        echo \"# Modified by hwdsl2 VPN script\" > \"$IPT6_FILE\"\n        ip6tables-save >> \"$IPT6_FILE\"\n      fi\n    fi\n  fi\n}\n\nfix_nss_config() {\n  nss_conf=\"/etc/crypto-policies/back-ends/nss.config\"\n  if [ -s \"$nss_conf\" ]; then\n    if ! grep -q \":SHA1:\" \"$nss_conf\" \\\n      && ! grep -q \" allow=SHA1:\" \"$nss_conf\"; then\n      sed -i \"/ALL allow=/s/ allow=/ allow=SHA1:/\" \"$nss_conf\"\n    fi\n  fi\n}\n\napply_gcp_mtu_fix() {\n  if dmidecode -s system-product-name 2>/dev/null | grep -qi 'Google Compute Engine' \\\n    && ifconfig 2>/dev/null | grep \"$NET_IFACE\" | head -n 1 | grep -qi 'mtu 1460'; then\n    bigecho \"Applying fix for MTU size...\"\n    ifconfig \"$NET_IFACE\" mtu 1500\n    dh_file=\"/etc/dhcp/dhclient.conf\"\n    if grep -qs \"send host-name\" \"$dh_file\" \\\n      && ! grep -qs \"interface-mtu 1500\" \"$dh_file\"; then\n      sed -i\".old-$SYS_DT\" \\\n        \"/send host-name/a \\interface \\\"$NET_IFACE\\\" {\\ndefault interface-mtu 1500;\\nsupersede interface-mtu 1500;\\n}\" \\\n        \"$dh_file\"\n    fi\n  fi\n}\n\nenable_on_boot() {\n  bigecho \"Enabling services on boot...\"\n  systemctl --now mask firewalld 2>/dev/null\n  if [ \"$use_nft\" = 1 ]; then\n    systemctl enable nftables 2>/dev/null\n    systemctl enable fail2ban 2>/dev/null\n  else\n    systemctl enable iptables 2>/dev/null\n    systemctl enable fail2ban 2>/dev/null\n  fi\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/rc.local; then\n    if [ -f /etc/rc.local ]; then\n      conf_bk \"/etc/rc.local\"\n    else\n      echo '#!/bin/sh' > /etc/rc.local\n    fi\n    ip6_fwd_rc=\"\"\n    [ -n \"$ip6\" ] && ip6_fwd_rc='\necho 1 > /proc/sys/net/ipv6/conf/all/forwarding'\ncat >> /etc/rc.local <<EOF\n\n# Added by hwdsl2 VPN script\n(sleep 15\nservice ipsec restart\nservice xl2tpd restart\necho 1 > /proc/sys/net/ipv4/ip_forward${ip6_fwd_rc})&\nEOF\n  fi\n}\n\nstart_services() {\n  bigecho \"Starting services...\"\n  sysctl -e -q -p\n  chmod +x /etc/rc.local\n  chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\n  restorecon /etc/ipsec.d/*db 2>/dev/null\n  restorecon /usr/local/sbin -Rv 2>/dev/null\n  restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null\n  if [ \"$use_nft\" = 1 ]; then\n    if ! nft -c -f \"$IPT_FILE\" >/dev/null 2>&1; then\n      sed -i '/ip6 saddr fddd:\\(2c4\\|1194\\):/s/xt target \"MASQUERADE\"/masquerade/' \"$IPT_FILE\"\n    fi\n    nft -f \"$IPT_FILE\"\n  else\n    iptables-restore < \"$IPT_FILE\"\n  fi\n  # Fix xl2tpd if l2tp_ppp is unavailable\n  if ! modprobe -q l2tp_ppp; then\n    sed -i '/^ExecStartPre=\\//s/=/=-/' /usr/lib/systemd/system/xl2tpd.service\n    systemctl daemon-reload\n  fi\n  mkdir -p /run/pluto\n  service fail2ban restart 2>/dev/null\n  service ipsec restart 2>/dev/null\n  service xl2tpd restart 2>/dev/null\n}\n\nshow_vpn_info() {\ncat <<EOF\n\n================================================\n\nIPsec VPN server is now ready for use!\n\nConnect to your new VPN with these details:\n\nServer IP: $public_ip\nIPsec PSK: $VPN_IPSEC_PSK\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n================================================\n\nEOF\n}\n\nset_up_ikev2() {\n  status=0\n  if [ -s /opt/src/ikev2.sh ] && [ ! -f /etc/ipsec.d/ikev2.conf ]; then\n    skip_ikev2=0\n    case $VPN_SKIP_IKEV2 in\n      [yY][eE][sS])\n        skip_ikev2=1\n        ;;\n    esac\n    if [ \"$skip_ikev2\" = 0 ]; then\n      sleep 1\n      VPN_DNS_NAME=\"$VPN_DNS_NAME\" VPN_PUBLIC_IP=\"$public_ip\" \\\n      VPN_CLIENT_NAME=\"$VPN_CLIENT_NAME\" VPN_XAUTH_POOL=\"$VPN_XAUTH_POOL\" \\\n      VPN_DNS_SRV1=\"$VPN_DNS_SRV1\" VPN_DNS_SRV2=\"$VPN_DNS_SRV2\" \\\n      VPN_PROTECT_CONFIG=\"$VPN_PROTECT_CONFIG\" \\\n      VPN_CLIENT_VALIDITY=\"$VPN_CLIENT_VALIDITY\" \\\n      VPN_PUBLIC_IP6=\"$ip6\" \\\n      /bin/bash /opt/src/ikev2.sh --auto || status=1\n    fi\n  elif [ -s /opt/src/ikev2.sh ]; then\ncat <<'EOF'\n================================================\n\nIKEv2 is already set up on this server.\n\nNext steps: Configure IKEv2 clients. See:\nhttps://vpnsetup.net/clients\n\nTo manage IKEv2 clients, run: sudo ikev2.sh\n\n================================================\n\nEOF\n  fi\n}\n\nvpnsetup() {\n  check_root\n  check_vz\n  check_lxc\n  check_os\n  check_iface\n  check_creds\n  check_dns\n  check_server_dns\n  check_client_name\n  check_subnets\n  check_libreswan\n  start_setup\n  install_setup_pkgs\n  detect_ip\n  detect_ipv6\n  add_epel_repo\n  install_vpn_pkgs_1\n  install_vpn_pkgs_2\n  install_vpn_pkgs_3\n  install_fail2ban\n  get_helper_scripts\n  get_libreswan\n  install_libreswan\n  create_vpn_config\n  update_sysctl\n  update_iptables\n  fix_nss_config\n  apply_gcp_mtu_fix\n  enable_on_boot\n  start_services\n  show_vpn_info\n  set_up_ikev2\n}\n\n## Defer setup until we have the complete script\nvpnsetup \"$@\"\n\nexit \"$status\"\n"
  },
  {
    "path": "vpnsetup_ubuntu.sh",
    "content": "#!/bin/bash\n#\n# Script for automatic setup of an IPsec VPN server on Ubuntu and Debian\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC!\n#\n# The latest version of this script is available at:\n# https://github.com/hwdsl2/setup-ipsec-vpn\n#\n# Copyright (C) 2014-2026 Lin Song <linsongui@gmail.com>\n# Based on the work of Thomas Sarlandie (Copyright 2012)\n#\n# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0\n# Unported License: http://creativecommons.org/licenses/by-sa/3.0/\n#\n# Attribution required: please include my name in any derivative and let me\n# know how you have improved it!\n\n# =====================================================\n\n# Define your own values for these variables\n# - IPsec pre-shared key, VPN username and password\n# - All values MUST be placed inside 'single quotes'\n# - DO NOT use these special characters within values: \\ \" '\n\nYOUR_IPSEC_PSK=''\nYOUR_USERNAME=''\nYOUR_PASSWORD=''\n\n# =====================================================\n\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nSYS_DT=$(date +%F-%T | tr ':' '_')\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nexiterr2() { exiterr \"'apt-get install' failed.\"; }\nconf_bk() { /bin/cp -f \"$1\" \"$1.old-$SYS_DT\" 2>/dev/null; }\nbigecho() { echo \"## $1\"; }\n\ncheck_ip() {\n  IP_REGEX='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP_REGEX\"\n}\n\ncheck_ip6() {\n  IP6_REGEX='^[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){1,7}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$IP6_REGEX\"\n}\n\ncheck_dns_name() {\n  FQDN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$'\n  printf '%s' \"$1\" | tr -d '\\n' | grep -Eq \"$FQDN_REGEX\"\n}\n\ncheck_root() {\n  if [ \"$(id -u)\" != 0 ]; then\n    exiterr \"Script must be run as root. Try 'sudo bash $0'\"\n  fi\n}\n\ncheck_vz() {\n  if [ -f /proc/user_beancounters ]; then\n    exiterr \"OpenVZ VPS is not supported.\"\n  fi\n}\n\ncheck_lxc() {\n  # shellcheck disable=SC2154\n  if [ \"$container\" = \"lxc\" ] && [ ! -e /dev/ppp ]; then\ncat 1>&2 <<'EOF'\nError: /dev/ppp is missing. LXC containers require configuration.\n       See: https://github.com/hwdsl2/setup-ipsec-vpn/issues/1014\nEOF\n  exit 1\n  fi\n}\n\ncheck_os() {\n  os_type=$(lsb_release -si 2>/dev/null)\n  [ -z \"$os_type\" ] && [ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n  case $os_type in\n    [Uu]buntu)\n      os_type=ubuntu\n      ;;\n    [Dd]ebian|[Kk]ali)\n      os_type=debian\n      ;;\n    [Rr]aspbian)\n      os_type=raspbian\n      ;;\n    *)\n      exiterr \"This script only supports Ubuntu and Debian.\"\n      ;;\n  esac\n  os_ver=$(sed 's/\\..*//' /etc/debian_version | tr -dc 'A-Za-z0-9')\n  if [ \"$os_ver\" = 8 ] || [ \"$os_ver\" = 9 ] || [ \"$os_ver\" = \"stretchsid\" ] \\\n    || [ \"$os_ver\" = \"bustersid\" ] || [ -z \"$os_ver\" ]; then\ncat 1>&2 <<EOF\nError: This script requires Debian >= 10 or Ubuntu >= 20.04.\n       This version of Ubuntu/Debian is too old and not supported.\nEOF\n    exit 1\n  fi\n  [ -f /etc/os-release ] && ubuntu_ver=$(. /etc/os-release && printf '%s' \"$VERSION_ID\")\n}\n\ncheck_iface() {\n  if ! command -v route >/dev/null 2>&1 && ! command -v ip >/dev/null 2>&1; then\n    wait_for_apt\n    export DEBIAN_FRONTEND=noninteractive\n    (\n      set -x\n      apt-get -yqq update || apt-get -yqq update\n      apt-get -yqq install iproute2 >/dev/null\n    )\n  fi\n  def_iface=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n  [ -z \"$def_iface\" ] && def_iface=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n  def_state=$(cat \"/sys/class/net/$def_iface/operstate\" 2>/dev/null)\n  if [ -n \"$def_state\" ] && [ \"$def_state\" != \"down\" ]; then\n    if ! uname -m | grep -qi -e '^arm' -e '^aarch64'; then\n      case $def_iface in\n        wl*)\n          exiterr \"Wireless interface '$def_iface' detected. DO NOT run this script on your PC or Mac!\"\n          ;;\n      esac\n    fi\n    NET_IFACE=\"$def_iface\"\n  else\n    eth0_state=$(cat \"/sys/class/net/eth0/operstate\" 2>/dev/null)\n    if [ -z \"$eth0_state\" ] || [ \"$eth0_state\" = \"down\" ]; then\n      exiterr \"Could not detect the default network interface.\"\n    fi\n    NET_IFACE=eth0\n  fi\n}\n\ncheck_creds() {\n  [ -n \"$YOUR_IPSEC_PSK\" ] && VPN_IPSEC_PSK=\"$YOUR_IPSEC_PSK\"\n  [ -n \"$YOUR_USERNAME\" ] && VPN_USER=\"$YOUR_USERNAME\"\n  [ -n \"$YOUR_PASSWORD\" ] && VPN_PASSWORD=\"$YOUR_PASSWORD\"\n  if [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n    bigecho \"VPN credentials not set by user. Generating random PSK and password...\"\n    VPN_IPSEC_PSK=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 20)\n    VPN_USER=vpnuser\n    VPN_PASSWORD=$(LC_CTYPE=C tr -dc 'A-HJ-NPR-Za-km-z2-9' </dev/urandom 2>/dev/null | head -c 16)\n  fi\n  if [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n    exiterr \"All VPN credentials must be specified. Edit the script and re-enter them.\"\n  fi\n  if printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n    exiterr \"VPN credentials must not contain non-ASCII characters.\"\n  fi\n  case \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD\" in\n    *[\\\\\\\"\\']*)\n      exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n      ;;\n  esac\n}\n\ncheck_dns() {\n  if { [ -n \"$VPN_DNS_SRV1\" ] && ! check_ip \"$VPN_DNS_SRV1\"; } \\\n    || { [ -n \"$VPN_DNS_SRV2\" ] && ! check_ip \"$VPN_DNS_SRV2\"; }; then\n    exiterr \"The DNS server specified is invalid.\"\n  fi\n}\n\ncheck_server_dns() {\n  if [ -n \"$VPN_DNS_NAME\" ] && ! check_dns_name \"$VPN_DNS_NAME\"; then\n    exiterr \"Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\"\n  fi\n}\n\ncheck_client_name() {\n  if [ -n \"$VPN_CLIENT_NAME\" ]; then\n    name_len=\"$(printf '%s' \"$VPN_CLIENT_NAME\" | wc -m)\"\n    if [ \"$name_len\" -gt \"64\" ] || printf '%s' \"$VPN_CLIENT_NAME\" | LC_ALL=C grep -q '[^A-Za-z0-9_-]\\+' \\\n      || case $VPN_CLIENT_NAME in -*) true ;; *) false ;; esac; then\n      exiterr \"Invalid client name. Use one word only, no special characters except '-' and '_'.\"\n    fi\n  fi\n}\n\ncheck_subnets() {\n  if [ -s /etc/ipsec.conf ] && grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n    XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n    if ! grep -q \"$L2TP_NET\" /etc/ipsec.conf \\\n      || ! grep -q \"$XAUTH_NET\" /etc/ipsec.conf; then\n      echo \"Error: The custom VPN subnets specified do not match initial install.\" >&2\n      echo \"       See Advanced usage -> Customize VPN subnets for more information.\" >&2\n      exit 1\n    fi\n  fi\n}\n\ncheck_iptables() {\n  if [ -x /sbin/iptables ] && ! iptables -nL INPUT >/dev/null 2>&1; then\n    exiterr \"IPTables check failed. Reboot and re-run this script.\"\n  fi\n}\n\nstart_setup() {\n  bigecho \"VPN setup in progress... Please be patient.\"\n  mkdir -p /opt/src\n  cd /opt/src || exit 1\n}\n\nwait_for_apt() {\n  count=0\n  apt_lk=/var/lib/apt/lists/lock\n  pkg_lk=/var/lib/dpkg/lock\n  while fuser \"$apt_lk\" \"$pkg_lk\" >/dev/null 2>&1 \\\n    || lsof \"$apt_lk\" >/dev/null 2>&1 || lsof \"$pkg_lk\" >/dev/null 2>&1; do\n    [ \"$count\" = 0 ] && echo \"## Waiting for apt to be available...\"\n    [ \"$count\" -ge 200 ] && exiterr \"Could not get apt/dpkg lock.\"\n    count=$((count+1))\n    printf '%s' '.'\n    sleep 3\n  done\n}\n\nupdate_apt_cache() {\n  bigecho \"Installing packages required for setup...\"\n  export DEBIAN_FRONTEND=noninteractive\n  (\n    set -x\n    apt-get -yqq update || apt-get -yqq update\n  ) || exiterr \"'apt-get update' failed.\"\n}\n\ninstall_setup_pkgs() {\n  (\n    set -x\n    apt-get -yqq install wget dnsutils openssl \\\n      iptables iproute2 gawk grep sed net-tools >/dev/null \\\n    || apt-get -yqq install wget dnsutils openssl \\\n      iptables iproute2 gawk grep sed net-tools >/dev/null\n  ) || exiterr2\n}\n\nget_default_ip() {\n  def_ip=$(ip -4 route get 1 | sed 's/ uid .*//' | awk '{print $NF;exit}' 2>/dev/null)\n  if check_ip \"$def_ip\" \\\n    && ! printf '%s' \"$def_ip\" | grep -Eq '^(10|127|172\\.(1[6-9]|2[0-9]|3[0-1])|192\\.168|169\\.254)\\.'; then\n    public_ip=\"$def_ip\"\n  fi\n}\n\ndetect_ip() {\n  public_ip=${VPN_PUBLIC_IP:-''}\n  check_ip \"$public_ip\" || get_default_ip\n  check_ip \"$public_ip\" && return 0\n  bigecho \"Trying to auto discover IP of this server...\"\n  check_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\n  check_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\n  check_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP. Define it as variable 'VPN_PUBLIC_IP' and re-run this script.\"\n}\n\ndetect_ipv6() {\n  ip6=\"\"\n  if ! printf '%s\\n%s' \"5.0\" \"$SWAN_VER\" | sort -C -V; then\n    return 0\n  fi\n  if [ -n \"$VPN_PUBLIC_IP6\" ]; then\n    ip6=\"$VPN_PUBLIC_IP6\"\n    check_ip6 \"$ip6\" || { echo \"Warning: Invalid IPv6 address in 'VPN_PUBLIC_IP6'. Detecting IPv6...\" >&2; ip6=\"\"; }\n  fi\n  [ -z \"$ip6\" ] && ip6=$(ip -6 addr 2>/dev/null | awk '/inet6 [23]/ {print $2}' | cut -d'/' -f1 | head -n1)\n  check_ip6 \"$ip6\" || ip6=\"\"\n}\n\ninstall_vpn_pkgs() {\n  bigecho \"Installing packages required for the VPN...\"\n  p1=libcurl4-nss-dev\n  if [ \"$os_ver\" = \"trixiesid\" ] || [ \"$os_ver\" = 13 ]; then\n    p1=libcurl4-gnutls-dev\n  fi\n  (\n    set -x\n    apt-get -yqq install libnss3-dev libnspr4-dev pkg-config \\\n      libpam0g-dev libcap-ng-dev libcap-ng-utils libselinux1-dev \\\n      $p1 flex bison gcc make libnss3-tools \\\n      libevent-dev libsystemd-dev uuid-runtime ppp xl2tpd >/dev/null\n  ) || exiterr2\n  if { [ \"$os_type\" = \"ubuntu\" ] && [ -n \"$ubuntu_ver\" ] \\\n    && printf '%s\\n%s' \"24.10\" \"$ubuntu_ver\" | sort -C -V; } \\\n    || [ \"$os_ver\" = 13 ]; then\n    (\n      set -x\n      apt-get -yqq install systemd-dev >/dev/null\n    ) || exiterr2\n  fi\n  if [ \"$os_type\" = \"debian\" ] && printf '%s\\n%s' \"12\" \"$os_ver\" | sort -C -V; then\n    (\n      set -x\n      apt-get -yqq install rsyslog >/dev/null\n    ) || exiterr2\n  fi\n}\n\ninstall_fail2ban() {\n  bigecho \"Installing Fail2Ban to protect SSH...\"\n  (\n    set -x\n    apt-get -yqq install fail2ban >/dev/null\n  )\n}\n\nlink_scripts() {\n  cd /opt/src || exit 1\n  /bin/mv -f ikev2setup.sh ikev2.sh\n  /bin/mv -f add_vpn_user.sh addvpnuser.sh\n  /bin/mv -f del_vpn_user.sh delvpnuser.sh\n  echo \"+ ikev2.sh addvpnuser.sh delvpnuser.sh\"\n  for sc in ikev2.sh addvpnuser.sh delvpnuser.sh; do\n    [ -s \"$sc\" ] && chmod +x \"$sc\" && ln -s \"/opt/src/$sc\" /usr/bin 2>/dev/null\n  done\n}\n\nget_helper_scripts() {\n  bigecho \"Downloading helper scripts...\"\n  base1=\"https://raw.githubusercontent.com/hwdsl2/setup-ipsec-vpn/master/extras\"\n  base2=\"https://gitlab.com/hwdsl2/setup-ipsec-vpn/-/raw/master/extras\"\n  sc1=ikev2setup.sh\n  sc2=add_vpn_user.sh\n  sc3=del_vpn_user.sh\n  cd /opt/src || exit 1\n  /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n  if wget -t 3 -T 30 -q \"$base1/$sc1\" \"$base1/$sc2\" \"$base1/$sc3\"; then\n    link_scripts\n  else\n    /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    if wget -t 3 -T 30 -q \"$base2/$sc1\" \"$base2/$sc2\" \"$base2/$sc3\"; then\n      link_scripts\n    else\n      echo \"Warning: Could not download helper scripts.\" >&2\n      /bin/rm -f \"$sc1\" \"$sc2\" \"$sc3\"\n    fi\n  fi\n}\n\nget_swan_ver() {\n  SWAN_VER=5.3\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/v1-$os_type-$os_ver-swanver\"\n  swan_ver_latest=$(wget -t 2 -T 10 -qO- \"$swan_ver_url\" | head -n 1)\n  [ -z \"$swan_ver_latest\" ] && swan_ver_latest=$(curl -m 10 -fsL \"$swan_ver_url\" 2>/dev/null | head -n 1)\n  if printf '%s' \"$swan_ver_latest\" | grep -Eq '^([3-9]|[1-9][0-9]{1,2})(\\.([0-9]|[1-9][0-9]{1,2})){1,2}$'; then\n    SWAN_VER=\"$swan_ver_latest\"\n  fi\n  if [ -n \"$VPN_SWAN_VER\" ]; then\n    if ! printf '%s\\n%s' \"4.15\" \"$VPN_SWAN_VER\" | sort -C -V \\\n      || ! printf '%s\\n%s' \"$VPN_SWAN_VER\" \"$SWAN_VER\" | sort -C -V; then\ncat 1>&2 <<EOF\nError: Libreswan version '$VPN_SWAN_VER' is not supported.\n       This script can install Libreswan 4.15+ or $SWAN_VER.\nEOF\n      exit 1\n    else\n      SWAN_VER=\"$VPN_SWAN_VER\"\n    fi\n  fi\n}\n\ncheck_libreswan() {\n  check_result=0\n  [ ! -d /etc/ipsec.d ] && { get_swan_ver; return 0; }\n  ipsec_ver=$(/usr/local/sbin/ipsec --version 2>/dev/null)\n  swan_ver_old=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  ipsec_bin=\"/usr/local/sbin/ipsec\"\n  if [ -n \"$swan_ver_old\" ] && printf '%s' \"$ipsec_ver\" | grep -qi 'libreswan' \\\n    && [ \"$(find \"$ipsec_bin\" -mmin -10080)\" ]; then\n    check_result=1\n    return 0\n  fi\n  get_swan_ver\n  if [ -s \"$ipsec_bin\" ] && [ \"$swan_ver_old\" = \"$SWAN_VER\" ]; then\n    touch \"$ipsec_bin\"\n  fi\n  [ \"$swan_ver_old\" = \"$SWAN_VER\" ] && check_result=1\n}\n\nget_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Downloading Libreswan...\"\n    cd /opt/src || exit 1\n    swan_file=\"libreswan-$SWAN_VER.tar.gz\"\n    swan_url1=\"https://github.com/libreswan/libreswan/archive/v$SWAN_VER.tar.gz\"\n    swan_url2=\"https://download.libreswan.org/$swan_file\"\n    (\n      set -x\n      wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url1\" || wget -t 3 -T 30 -q -O \"$swan_file\" \"$swan_url2\"\n    ) || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    tar xzf \"$swan_file\" && /bin/rm -f \"$swan_file\"\n  else\n    bigecho \"Libreswan $swan_ver_old is already installed, skipping...\"\n  fi\n}\n\ninstall_libreswan() {\n  if [ \"$check_result\" = 0 ]; then\n    bigecho \"Compiling and installing Libreswan, please wait...\"\n    cd \"libreswan-$SWAN_VER\" || exit 1\ncat > Makefile.inc.local <<'EOF'\nWERROR_CFLAGS=-w -s\nUSE_DNSSEC=false\nUSE_DH2=true\nUSE_NSS_KDF=false\nFINALNSSDIR=/etc/ipsec.d\nNSSDIR=/etc/ipsec.d\nEOF\n    if ! grep -qs IFLA_XFRM_LINK /usr/include/linux/if_link.h; then\n      echo \"USE_XFRM_INTERFACE_IFLA_HEADER=true\" >> Makefile.inc.local\n    fi\n    NPROCS=$(grep -c ^processor /proc/cpuinfo)\n    [ -z \"$NPROCS\" ] && NPROCS=1\n    (\n      set -x\n      make \"-j$((NPROCS+1))\" -s base >/dev/null 2>&1 && make -s install-base >/dev/null 2>&1\n    )\n    cd /opt/src || exit 1\n    /bin/rm -rf \"/opt/src/libreswan-$SWAN_VER\"\n    if ! /usr/local/sbin/ipsec --version 2>/dev/null | grep -qF \"$SWAN_VER\" \\\n      || [ ! -d /etc/ipsec.d ]; then\n      exiterr \"Libreswan $SWAN_VER failed to build.\"\n    fi\n  fi\n}\n\ncreate_vpn_config() {\n  bigecho \"Creating VPN configuration...\"\n  L2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\n  L2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}\n  L2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}\n  XAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\n  XAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\n  DNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}\n  DNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}\n  DNS_SRVS=\"\\\"$DNS_SRV1 $DNS_SRV2\\\"\"\n  [ -n \"$VPN_DNS_SRV1\" ] && [ -z \"$VPN_DNS_SRV2\" ] && DNS_SRVS=\"$DNS_SRV1\"\n  IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n  vp_ip6=\"\"\n  [ -n \"$ip6\" ] && vp_ip6=\",%v6:fc00::/7,%v6:!$IP6_NET\"\n  # Create IPsec config\n  conf_bk \"/etc/ipsec.conf\"\ncat > /etc/ipsec.conf <<EOF\nversion 2.0\n\nconfig setup\n  ikev1-policy=accept\n  virtual-private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!$L2TP_NET,%v4:!$XAUTH_NET$vp_ip6\n  uniqueids=no\n\nconn shared\n  left=%defaultroute\n  leftid=$public_ip\n  right=%any\n  encapsulation=yes\n  authby=secret\n  pfs=no\n  rekey=no\n  dpddelay=30\n  dpdtimeout=300\n  ikev2=never\n  ike=aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\n  phase2alg=aes_gcm-null,aes128-sha1,aes256-sha1,aes256-sha2_512,aes128-sha2,aes256-sha2\n  ikelifetime=24h\n  salifetime=24h\n  sha2-truncbug=no\n\nconn l2tp-psk\n  auto=add\n  leftprotoport=17/1701\n  rightprotoport=17/%any\n  type=transport\n  also=shared\n\nconn xauth-psk\n  auto=add\n  leftsubnet=0.0.0.0/0\n  rightaddresspool=$XAUTH_POOL\n  modecfgdns=$DNS_SRVS\n  leftxauthserver=yes\n  rightxauthclient=yes\n  leftmodecfgserver=yes\n  rightmodecfgclient=yes\n  modecfgpull=yes\n  cisco-unity=yes\n  also=shared\n\ninclude /etc/ipsec.d/*.conf\nEOF\n  if uname -m | grep -qi '^arm'; then\n    if ! modprobe -q sha512; then\n      sed -i '/phase2alg/s/,aes256-sha2_512//' /etc/ipsec.conf\n    fi\n  fi\n  # Specify IPsec PSK\n  conf_bk \"/etc/ipsec.secrets\"\ncat > /etc/ipsec.secrets <<EOF\n%any  %any  : PSK \"$VPN_IPSEC_PSK\"\nEOF\n  # Create xl2tpd config\n  conf_bk \"/etc/xl2tpd/xl2tpd.conf\"\ncat > /etc/xl2tpd/xl2tpd.conf <<EOF\n[global]\nport = 1701\n\n[lns default]\nip range = $L2TP_POOL\nlocal ip = $L2TP_LOCAL\nrequire chap = yes\nrefuse pap = yes\nrequire authentication = yes\nname = l2tpd\npppoptfile = /etc/ppp/options.xl2tpd\nlength bit = yes\nEOF\n  # Set xl2tpd options\n  conf_bk \"/etc/ppp/options.xl2tpd\"\ncat > /etc/ppp/options.xl2tpd <<EOF\n+mschap-v2\nipcp-accept-local\nipcp-accept-remote\nnoccp\nauth\nmtu 1280\nmru 1280\nproxyarp\nlcp-echo-failure 4\nlcp-echo-interval 30\nconnect-delay 5000\nms-dns $DNS_SRV1\nEOF\n  if [ -z \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_DNS_SRV2\" ]; then\ncat >> /etc/ppp/options.xl2tpd <<EOF\nms-dns $DNS_SRV2\nEOF\n  fi\n  # Create VPN credentials\n  conf_bk \"/etc/ppp/chap-secrets\"\ncat > /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n  conf_bk \"/etc/ipsec.d/passwd\"\n  VPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat > /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n}\n\nupdate_sysctl() {\n  bigecho \"Updating sysctl settings...\"\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/sysctl.conf; then\n    conf_bk \"/etc/sysctl.conf\"\ncat >> /etc/sysctl.conf <<EOF\n\n# Added by hwdsl2 VPN script\nkernel.msgmnb = 65536\nkernel.msgmax = 65536\n\nnet.ipv4.ip_forward = 1\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.all.send_redirects = 0\nnet.ipv4.conf.all.rp_filter = 0\nnet.ipv4.conf.default.accept_redirects = 0\nnet.ipv4.conf.default.send_redirects = 0\nnet.ipv4.conf.default.rp_filter = 0\nnet.ipv4.conf.$NET_IFACE.send_redirects = 0\nnet.ipv4.conf.$NET_IFACE.rp_filter = 0\n\nnet.core.wmem_max = 16777216\nnet.core.rmem_max = 16777216\nnet.ipv4.tcp_rmem = 4096 87380 16777216\nnet.ipv4.tcp_wmem = 4096 87380 16777216\nEOF\n    if modprobe -q tcp_bbr \\\n      && printf '%s\\n%s' \"4.20\" \"$(uname -r)\" | sort -C -V \\\n      && [ -f /proc/sys/net/ipv4/tcp_congestion_control ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr\nEOF\n    fi\n    if [ -n \"$ip6\" ]; then\ncat >> /etc/sysctl.conf <<'EOF'\nnet.ipv6.conf.all.forwarding = 1\nEOF\n    fi\n  fi\n}\n\nupdate_iptables() {\n  bigecho \"Updating IPTables rules...\"\n  IPT_FILE=/etc/iptables.rules\n  IPT_FILE2=/etc/iptables/rules.v4\n  ipt_flag=0\n  if ! grep -qs \"hwdsl2 VPN script\" \"$IPT_FILE\"; then\n    ipt_flag=1\n  fi\n  ipi='iptables -I INPUT'\n  ipf='iptables -I FORWARD'\n  ipp='iptables -t nat -I POSTROUTING'\n  res='RELATED,ESTABLISHED'\n  if [ \"$ipt_flag\" = 1 ]; then\n    service fail2ban stop >/dev/null 2>&1\n    iptables-save > \"$IPT_FILE.old-$SYS_DT\"\n    $ipi 1 -p udp --dport 1701 -m policy --dir in --pol none -j DROP\n    $ipi 2 -m conntrack --ctstate INVALID -j DROP\n    $ipi 3 -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipi 4 -p udp -m multiport --dports 500,4500 -j ACCEPT\n    $ipi 5 -p udp --dport 1701 -m policy --dir in --pol ipsec -j ACCEPT\n    $ipi 6 -p udp --dport 1701 -j DROP\n    $ipf 1 -m conntrack --ctstate INVALID -j DROP\n    $ipf 2 -i \"$NET_IFACE\" -o ppp+ -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 3 -i ppp+ -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 4 -i ppp+ -o ppp+ -j ACCEPT\n    $ipf 5 -i \"$NET_IFACE\" -d \"$XAUTH_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n    $ipf 6 -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -j ACCEPT\n    $ipf 7 -s \"$XAUTH_NET\" -o ppp+ -j ACCEPT\n    iptables -A FORWARD -j DROP\n    $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n    $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\n    echo \"# Modified by hwdsl2 VPN script\" > \"$IPT_FILE\"\n    iptables-save >> \"$IPT_FILE\"\n    if [ -f \"$IPT_FILE2\" ]; then\n      conf_bk \"$IPT_FILE2\"\n      /bin/cp -f \"$IPT_FILE\" \"$IPT_FILE2\"\n    fi\n    if [ -n \"$ip6\" ]; then\n      IP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\n      IPT6_FILE=/etc/ip6tables.rules\n      IPT6_FILE2=/etc/iptables/rules.v6\n      ip6tables-save > \"$IPT6_FILE.old-$SYS_DT\"\n      ip6ti='ip6tables -I INPUT'\n      ip6tf='ip6tables -I FORWARD'\n      ip6tp='ip6tables -t nat -I POSTROUTING'\n      $ip6ti 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6ti 2 -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6ti 3 -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ip6tf 1 -m conntrack --ctstate INVALID -j DROP\n      $ip6tf 2 -i \"$NET_IFACE\" -d \"$IP6_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ip6tf 3 -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      $ip6tp -s \"$IP6_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE\n      echo \"# Modified by hwdsl2 VPN script\" > \"$IPT6_FILE\"\n      ip6tables-save >> \"$IPT6_FILE\"\n      if [ -f \"$IPT6_FILE2\" ]; then\n        conf_bk \"$IPT6_FILE2\"\n        /bin/cp -f \"$IPT6_FILE\" \"$IPT6_FILE2\"\n      fi\n    fi\n  fi\n}\n\napply_gcp_mtu_fix() {\n  if dmidecode -s system-product-name 2>/dev/null | grep -qi 'Google Compute Engine' \\\n    && ifconfig 2>/dev/null | grep \"$NET_IFACE\" | head -n 1 | grep -qi 'mtu 1460'; then\n    bigecho \"Applying fix for MTU size...\"\n    ifconfig \"$NET_IFACE\" mtu 1500\n    dh_file=\"/etc/dhcp/dhclient.conf\"\n    if grep -qs \"send host-name\" \"$dh_file\" \\\n      && ! grep -qs \"interface-mtu 1500\" \"$dh_file\"; then\n      sed -i\".old-$SYS_DT\" \\\n        \"/send host-name/a \\interface \\\"$NET_IFACE\\\" {\\ndefault interface-mtu 1500;\\nsupersede interface-mtu 1500;\\n}\" \\\n        \"$dh_file\"\n    fi\n  fi\n}\n\nenable_on_boot() {\n  bigecho \"Enabling services on boot...\"\n  IPT_PST=/etc/init.d/iptables-persistent\n  IPT_PST2=/usr/share/netfilter-persistent/plugins.d/15-ip4tables\n  ipt_load=1\n  if [ -f \"$IPT_FILE2\" ] && { [ -f \"$IPT_PST\" ] || [ -f \"$IPT_PST2\" ]; }; then\n    ipt_load=0\n  fi\n  if [ \"$ipt_load\" = 1 ]; then\n    mkdir -p /etc/network/if-pre-up.d\ncat > /etc/network/if-pre-up.d/iptablesload <<'EOF'\n#!/bin/sh\niptables-restore < /etc/iptables.rules\n[ -f /etc/ip6tables.rules ] && ip6tables-restore < /etc/ip6tables.rules\nexit 0\nEOF\n    chmod +x /etc/network/if-pre-up.d/iptablesload\n    if [ -f /usr/sbin/netplan ]; then\n      mkdir -p /etc/systemd/system\ncat > /etc/systemd/system/load-iptables-rules.service <<'EOF'\n[Unit]\nDescription = Load /etc/iptables.rules\nDefaultDependencies=no\n\nBefore=network-pre.target\nWants=network-pre.target\n\nWants=systemd-modules-load.service local-fs.target\nAfter=systemd-modules-load.service local-fs.target\n\n[Service]\nType=oneshot\nExecStart=/etc/network/if-pre-up.d/iptablesload\n\n[Install]\nWantedBy=multi-user.target\nEOF\n      systemctl enable load-iptables-rules 2>/dev/null\n    fi\n  fi\n  for svc in fail2ban ipsec xl2tpd; do\n    update-rc.d \"$svc\" enable >/dev/null 2>&1\n    systemctl enable \"$svc\" 2>/dev/null\n  done\n  if ! grep -qs \"hwdsl2 VPN script\" /etc/rc.local; then\n    if [ -f /etc/rc.local ]; then\n      conf_bk \"/etc/rc.local\"\n      sed --follow-symlinks -i '/^exit 0/d' /etc/rc.local\n    else\n      echo '#!/bin/sh' > /etc/rc.local\n    fi\n    rc_delay=15\n    if uname -m | grep -qi '^arm'; then\n      rc_delay=60\n    fi\n    ip6_fwd_rc=\"\"\n    [ -n \"$ip6\" ] && ip6_fwd_rc='\necho 1 > /proc/sys/net/ipv6/conf/all/forwarding'\ncat >> /etc/rc.local <<EOF\n\n# Added by hwdsl2 VPN script\n(sleep $rc_delay\nservice ipsec restart\nservice xl2tpd restart\necho 1 > /proc/sys/net/ipv4/ip_forward${ip6_fwd_rc})&\nexit 0\nEOF\n  fi\n}\n\nstart_services() {\n  bigecho \"Starting services...\"\n  sysctl -e -q -p\n  chmod +x /etc/rc.local\n  chmod 600 /etc/ipsec.secrets* /etc/ppp/chap-secrets* /etc/ipsec.d/passwd*\n  mkdir -p /run/pluto\n  service fail2ban restart 2>/dev/null\n  service ipsec restart 2>/dev/null\n  service xl2tpd restart 2>/dev/null\n}\n\nshow_vpn_info() {\ncat <<EOF\n\n================================================\n\nIPsec VPN server is now ready for use!\n\nConnect to your new VPN with these details:\n\nServer IP: $public_ip\nIPsec PSK: $VPN_IPSEC_PSK\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients\n\n================================================\n\nEOF\n  if [ ! -e /dev/ppp ]; then\ncat <<'EOF'\nWarning: /dev/ppp is missing, and IPsec/L2TP mode may not work.\n         Please use IKEv2 or IPsec/XAuth mode to connect.\n         Debian 11/10 users, see https://vpnsetup.net/debian10\n\nEOF\n  fi\n}\n\nset_up_ikev2() {\n  status=0\n  if [ -s /opt/src/ikev2.sh ] && [ ! -f /etc/ipsec.d/ikev2.conf ]; then\n    skip_ikev2=0\n    case $VPN_SKIP_IKEV2 in\n      [yY][eE][sS])\n        skip_ikev2=1\n        ;;\n    esac\n    if [ \"$skip_ikev2\" = 0 ]; then\n      sleep 1\n      VPN_DNS_NAME=\"$VPN_DNS_NAME\" VPN_PUBLIC_IP=\"$public_ip\" \\\n      VPN_CLIENT_NAME=\"$VPN_CLIENT_NAME\" VPN_XAUTH_POOL=\"$VPN_XAUTH_POOL\" \\\n      VPN_DNS_SRV1=\"$VPN_DNS_SRV1\" VPN_DNS_SRV2=\"$VPN_DNS_SRV2\" \\\n      VPN_PROTECT_CONFIG=\"$VPN_PROTECT_CONFIG\" \\\n      VPN_CLIENT_VALIDITY=\"$VPN_CLIENT_VALIDITY\" \\\n      VPN_PUBLIC_IP6=\"$ip6\" \\\n      /bin/bash /opt/src/ikev2.sh --auto || status=1\n    fi\n  elif [ -s /opt/src/ikev2.sh ]; then\ncat <<'EOF'\n================================================\n\nIKEv2 is already set up on this server.\n\nNext steps: Configure IKEv2 clients. See:\nhttps://vpnsetup.net/clients\n\nTo manage IKEv2 clients, run: sudo ikev2.sh\n\n================================================\n\nEOF\n  fi\n}\n\nvpnsetup() {\n  check_root\n  check_vz\n  check_lxc\n  check_os\n  check_iface\n  check_creds\n  check_dns\n  check_server_dns\n  check_client_name\n  check_subnets\n  check_iptables\n  check_libreswan\n  start_setup\n  wait_for_apt\n  update_apt_cache\n  install_setup_pkgs\n  detect_ip\n  detect_ipv6\n  install_vpn_pkgs\n  install_fail2ban\n  get_helper_scripts\n  get_libreswan\n  install_libreswan\n  create_vpn_config\n  update_sysctl\n  update_iptables\n  apply_gcp_mtu_fix\n  enable_on_boot\n  start_services\n  show_vpn_info\n  set_up_ikev2\n}\n\n## Defer setup until we have the complete script\nvpnsetup \"$@\"\n\nexit \"$status\"\n"
  }
]