[
  {
    "path": ".dockerignore",
    "content": ".git\n.github\n.gitignore\ndocker-compose.yml\nLICENSE.md\nREADME.md\nREADME-zh.md\nvpn.env\nvpn.env.example\n"
  },
  {
    "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/docker-ipsec-vpn-server/blob/master/README.md)\n- [ ] I read the [Important notes](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md#important-notes)\n- [ ] I followed instructions to [configure VPN clients](https://github.com/hwdsl2/docker-ipsec-vpn-server/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), [enabled logs](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage.md#enable-libreswan-logs) and checked [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/docker-ipsec-vpn-server/issues?q=is%3Aissue)\n- [ ] This bug is about the IPsec VPN server Docker image, 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[Enable logs](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage.md#enable-libreswan-logs), check [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- Docker host OS: [e.g. Ubuntu 24.04]\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/docker-ipsec-vpn-server/blob/master/README-zh.md)\n- [ ] 我已阅读[重要提示](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#重要提示)\n- [ ] 我已按照说明[配置 VPN 客户端](https://github.com/hwdsl2/docker-ipsec-vpn-server/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-故障排除)，[启用日志](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage-zh.md#启用-libreswan-日志)并查看了 [VPN 状态](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#检查日志及-vpn-状态)\n- [ ] 我搜索了已有的 [Issues](https://github.com/hwdsl2/docker-ipsec-vpn-server/issues?q=is%3Aissue)\n- [ ] 这个 bug 是关于 IPsec VPN 服务器 Docker 镜像，而不是 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[启用日志](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage-zh.md#启用-libreswan-日志)，检查 [VPN 状态](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#检查日志及-vpn-状态)，并且添加错误日志以帮助解释该问题（如果适用）。\n\n**服务器信息（请填写以下信息）**\n- Docker 主机操作系统: [比如 Ubuntu 24.04]\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/docker-ipsec-vpn-server/issues?q=is%3Aissue), and did not find a similar enhancement request\n- [ ] This enhancement request is about the IPsec VPN server Docker image, and not IPsec VPN itself\n- [ ] I read the [README](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md)\n- [ ] I read the [Important notes](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README.md#important-notes)\n- [ ] I followed instructions to [configure VPN clients](https://github.com/hwdsl2/docker-ipsec-vpn-server/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), [enabled logs](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage.md#enable-libreswan-logs) and checked [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/docker-ipsec-vpn-server/issues?q=is%3Aissue)，没有找到类似的改进建议\n- [ ] 这个改进建议是关于 IPsec VPN 服务器 Docker 镜像，而不是 IPsec VPN 本身\n- [ ] 我已阅读[自述文件](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md)\n- [ ] 我已阅读[重要提示](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/README-zh.md#重要提示)\n- [ ] 我已按照说明[配置 VPN 客户端](https://github.com/hwdsl2/docker-ipsec-vpn-server/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-故障排除)，[启用日志](https://github.com/hwdsl2/docker-ipsec-vpn-server/blob/master/docs/advanced-usage-zh.md#启用-libreswan-日志)并查看了 [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/buildx.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: buildx\n\non:\n  workflow_call:\n    inputs:\n      os_type:\n        required: true\n        type: string\n    secrets:\n      CACHE_NAME:\n        required: true\n      DOCKER_TOKEN:\n        required: true\n      QUAY_USER:\n        required: true\n      QUAY_TOKEN:\n        required: true\n      BUILD_ONLY:\n        required: true\n\njobs:\n  buildx:\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: Cache\n        uses: actions/cache@v5\n        with:\n          path: |\n            ${{ runner.temp }}/.buildx-bin\n            ${{ runner.temp }}/.buildx-cache\n            ${{ runner.temp }}/.docker-images\n          key: ${{ secrets.CACHE_NAME }}-${{ github.sha }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ secrets.CACHE_NAME }}-\n      - name: Set up Buildx\n        env:\n          RUNNER_TEMP: ${{ runner.temp }}\n        run: |\n          [ ! -x /usr/bin/docker ] && exit 1\n          if [ ! -x /usr/bin/wget ] || [ ! -x /usr/bin/jq ]; then\n            export DEBIAN_FRONTEND=noninteractive\n            sudo apt-get -yq update\n            sudo apt-get -yq install wget jq\n          fi\n\n          BUILDX_VER=$(wget -t 3 -T 30 -qO- \"https://api.github.com/repos/docker/buildx/releases/latest\" | jq -r \".tag_name\")\n          [ -z \"${BUILDX_VER}\" ] && exit 1\n          echo \"Buildx version: ${BUILDX_VER}\"\n\n          DOCKER_DIR=\"${HOME}/.docker/cli-plugins\"\n          CACHE_DIR=\"${RUNNER_TEMP}/.buildx-bin\"\n          mkdir -p \"${DOCKER_DIR}\"\n          if [ -s \"${CACHE_DIR}/docker-buildx-${BUILDX_VER}\" ]; then\n            echo \"Using buildx binary from cache...\"\n            cp -f \"${CACHE_DIR}/docker-buildx-${BUILDX_VER}\" \"${DOCKER_DIR}/docker-buildx\"\n          else\n            echo \"Downloading buildx...\"\n            BUILDX_URL=\"https://github.com/docker/buildx/releases/download/${BUILDX_VER}/buildx-${BUILDX_VER}.linux-amd64\"\n            wget -t 3 -T 30 -nv -O \"${DOCKER_DIR}/docker-buildx\" \"${BUILDX_URL}\"\n            [ ! -s \"${DOCKER_DIR}/docker-buildx\" ] && exit 1\n            /bin/rm -rf \"${CACHE_DIR}\"\n            mkdir -p \"${CACHE_DIR}\"\n            /bin/cp -f \"${DOCKER_DIR}/docker-buildx\" \"${CACHE_DIR}/docker-buildx-${BUILDX_VER}\"\n          fi\n          chmod a+x \"${DOCKER_DIR}/docker-buildx\"\n\n          docker info\n          docker buildx version\n\n          image_cache_dir=\"${RUNNER_TEMP}/.docker-images\"\n          for image in \"quay.io/hwdsl2/qemu-user-static:latest\" \"moby/buildkit:buildx-stable-1\"; do\n            image_file=$(printf '%s' \"${image}.tar.gz\" | tr '/' '-' | tr ':' '-')\n            if [ -s \"${image_cache_dir}/${image_file}\" ]; then\n              echo \"Using ${image} from cache...\"\n              docker load -i \"${image_cache_dir}/${image_file}\"\n            else\n              echo \"Downloading ${image}...\"\n              docker pull -q \"${image}\"\n              mkdir -p \"${image_cache_dir}\"\n              docker save \"${image}\" | gzip > \"${image_cache_dir}/${image_file}\"\n            fi\n          done\n\n          docker run --rm --privileged quay.io/hwdsl2/qemu-user-static:latest --reset -p yes --credential yes\n          docker buildx create --name \"builder-${GITHUB_SHA::8}\" --driver docker-container --use\n          docker buildx inspect --bootstrap\n      - name: Docker Hub Login\n        env:\n          DOCKER_USER: ${{ github.repository_owner }}\n          DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}\n        run: echo \"$DOCKER_TOKEN\" | docker login --username \"$DOCKER_USER\" --password-stdin 2>&1\n      - name: Quay.io Login\n        env:\n          QUAY_USER: ${{ secrets.QUAY_USER }}\n          QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}\n        run: echo \"$QUAY_TOKEN\" | docker login quay.io --username \"$QUAY_USER\" --password-stdin 2>&1\n      - name: Docker Buildx\n        env:\n          DOCKER_USER: ${{ github.repository_owner }}\n          BUILD_ONLY: ${{ secrets.BUILD_ONLY }}\n          RUNNER_TEMP: ${{ runner.temp }}\n          OS_TYPE: ${{ inputs.os_type }}\n        run: |\n          cd \"$GITHUB_WORKSPACE\"\n          pwd\n          ls -ld vpn.env.example\n\n          [ \"$BUILD_ONLY\" = \"true\" ] && BUILD_ONLY=\"\"\n          ts_now=$(date -u +'%Y-%m-%dT%H:%M:%SZ')\n\n          if [ \"$OS_TYPE\" = \"alpine\" ]; then\n            docker buildx build \\\n              --progress plain \\\n              --platform=linux/amd64,linux/arm64,linux/arm/v7 \\\n              --build-arg BUILD_DATE=$ts_now \\\n              --build-arg VCS_REF=${GITHUB_SHA::8} \\\n              --build-arg VERSION=alpine-latest \\\n              --cache-from type=local,src=\"${RUNNER_TEMP}/.buildx-cache\" \\\n              --cache-to type=local,dest=\"${RUNNER_TEMP}/.buildx-cache-new\" \\\n              -t \"$DOCKER_USER/ipsec-vpn-server:latest\" \\\n              --pull \\\n              ${BUILD_ONLY:+--push} \\\n              .\n\n            docker buildx build \\\n              --progress plain \\\n              --platform=linux/amd64,linux/arm64,linux/arm/v7 \\\n              --build-arg BUILD_DATE=$ts_now \\\n              --build-arg VCS_REF=${GITHUB_SHA::8} \\\n              --build-arg VERSION=alpine-latest \\\n              --cache-from type=local,src=\"${RUNNER_TEMP}/.buildx-cache-new\" \\\n              -t \"quay.io/$DOCKER_USER/ipsec-vpn-server:latest\" \\\n              --pull \\\n              ${BUILD_ONLY:+--push} \\\n              .\n          elif [ \"$OS_TYPE\" = \"debian\" ]; then\n            docker buildx build \\\n              --progress plain \\\n              --platform=linux/amd64,linux/arm64,linux/arm/v7 \\\n              --build-arg BUILD_DATE=$ts_now \\\n              --build-arg VCS_REF=${GITHUB_SHA::8} \\\n              --build-arg VERSION=debian-latest \\\n              --cache-from type=local,src=\"${RUNNER_TEMP}/.buildx-cache\" \\\n              --cache-to type=local,dest=\"${RUNNER_TEMP}/.buildx-cache-new\" \\\n              -f Dockerfile.debian \\\n              -t \"$DOCKER_USER/ipsec-vpn-server:debian\" \\\n              --pull \\\n              ${BUILD_ONLY:+--push} \\\n              .\n\n            docker buildx build \\\n              --progress plain \\\n              --platform=linux/amd64,linux/arm64,linux/arm/v7 \\\n              --build-arg BUILD_DATE=$ts_now \\\n              --build-arg VCS_REF=${GITHUB_SHA::8} \\\n              --build-arg VERSION=debian-latest \\\n              --cache-from type=local,src=\"${RUNNER_TEMP}/.buildx-cache-new\" \\\n              -f Dockerfile.debian \\\n              -t \"quay.io/$DOCKER_USER/ipsec-vpn-server:debian\" \\\n              --pull \\\n              ${BUILD_ONLY:+--push} \\\n              .\n          else\n            exit 1\n          fi\n\n          /bin/rm -rf \"${RUNNER_TEMP}/.buildx-cache\"\n          /bin/mv -f \"${RUNNER_TEMP}/.buildx-cache-new\" \"${RUNNER_TEMP}/.buildx-cache\"\n      - name: Clear\n        if: always()\n        run: |\n          shred -u \"${HOME}/.docker/config.json\"\n          rm -f \"${HOME}/.docker/config.json\"\n          docker buildx rm \"builder-${GITHUB_SHA::8}\" || true\n"
  },
  {
    "path": ".github/workflows/check_update.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_update\n\non:\n  workflow_call:\n    inputs:\n      os_type:\n        required: true\n        type: string\n    secrets:\n      CACHE_NAME:\n        required: true\n    outputs:\n      should_test:\n        value: ${{ jobs.check_update.outputs.should_test }}\n      should_update:\n        value: ${{ jobs.check_update.outputs.should_update }}\n\njobs:\n  check_update:\n    runs-on: ubuntu-24.04\n    if: github.repository_owner == 'hwdsl2'\n    env:\n      DOCKER_USER: ${{ github.repository_owner }}\n      OS_TYPE: ${{ inputs.os_type }}\n    outputs:\n      should_test: ${{ steps.check.outputs.should_test }}\n      should_update: ${{ steps.check.outputs.should_update }}\n    steps:\n      - name: Cache\n        uses: actions/cache@v5\n        with:\n          path: |\n            ${{ runner.temp }}/.buildx-bin\n            ${{ runner.temp }}/.buildx-cache\n            ${{ runner.temp }}/.docker-images\n          key: ${{ secrets.CACHE_NAME }}-${{ github.sha }}-${{ github.run_id }}-check\n          restore-keys: |\n            ${{ secrets.CACHE_NAME }}-\n      - name: Prepare\n        run: |\n          if [ \"$OS_TYPE\" = \"alpine\" ]; then\n            docker pull alpine:3.23\n            docker pull \"$DOCKER_USER/ipsec-vpn-server\"\n          elif [ \"$OS_TYPE\" = \"debian\" ]; then\n            docker pull debian:bookworm-slim\n            docker pull \"$DOCKER_USER/ipsec-vpn-server:debian\"\n          else\n            exit 1\n          fi\n      - name: Check\n        id: check\n        run: |\n          BASE_UPDATED=false\n\n          if [ \"$OS_TYPE\" = \"alpine\" ]; then\n            base_ts=$(docker inspect --format='{{.Created}}' alpine:3.23)\n            image_ts=$(docker inspect --format='{{.Created}}' \"$DOCKER_USER/ipsec-vpn-server\")\n          elif [ \"$OS_TYPE\" = \"debian\" ]; then\n            base_ts=$(docker inspect --format='{{.Created}}' debian:bookworm-slim)\n            image_ts=$(docker inspect --format='{{.Created}}' \"$DOCKER_USER/ipsec-vpn-server:debian\")\n          else\n            exit 1\n          fi\n\n          if [ -n \"$base_ts\" ] && [ -n \"$image_ts\" ]; then\n            base_ts_s=$(date -d \"$base_ts\" +%s)\n            image_ts_s=$(date -d \"$image_ts\" +%s)\n            ts_now=$(date -u +'%Y-%m-%dT%H:%M:%SZ')\n            ts_now_s=$(date -d \"$ts_now\" +%s)\n            diff_s=$((ts_now_s - base_ts_s))\n            diff=$(printf '%dd %dh:%dm:%ds\\n' $(($diff_s/86400)) $(($diff_s%86400/3600)) $(($diff_s%3600/60)) $(($diff_s%60)))\n\n            echo \"Base update time:  $base_ts\"\n            echo \"Image update time: $image_ts\"\n            echo \"Current time:      $ts_now\"\n            echo \"Time diff (cur-base): $diff (${diff_s}s)\"\n\n            if [ -n \"$base_ts_s\" ] && [ -n \"$image_ts_s\" ] \\\n              && [ \"$base_ts_s\" -ge \"$image_ts_s\" ] \\\n              && [ \"$diff_s\" -ge 14400 ]; then\n              echo \"Starting build...\"\n              BASE_UPDATED=true\n            else\n              echo \"Not starting build.\"\n            fi\n          fi\n          echo \"should_test=${BASE_UPDATED}\" >> \"$GITHUB_OUTPUT\"\n          echo \"should_update=${BASE_UPDATED}\" >> \"$GITHUB_OUTPUT\"\n"
  },
  {
    "path": ".github/workflows/cron-alpine.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: '40 2,14 * * *'\n\njobs:\n  check_update:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/check_update.yml\n    with:\n      os_type: alpine\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME2 }}\n\n  vpn_test:\n    needs: check_update\n    if: needs.check_update.outputs.should_test == 'true'\n    uses: ./.github/workflows/vpn_test.yml\n    with:\n      os_type: alpine\n\n  buildx:\n    needs: [check_update, vpn_test]\n    if: needs.check_update.outputs.should_update == 'true'\n    uses: ./.github/workflows/buildx.yml\n    with:\n      os_type: alpine\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME2 }}\n      DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}\n      QUAY_USER: ${{ secrets.QUAY_USER }}\n      QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}\n      BUILD_ONLY: ${{ secrets.BUILD_ONLY }}\n"
  },
  {
    "path": ".github/workflows/cron-debian.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 debian cron\n\non:\n  schedule:\n    - cron: '25 2,14 * * *'\n\njobs:\n  check_update:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/check_update.yml\n    with:\n      os_type: debian\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME }}\n\n  vpn_test:\n    needs: check_update\n    if: needs.check_update.outputs.should_test == 'true'\n    uses: ./.github/workflows/vpn_test.yml\n    with:\n      os_type: debian\n\n  buildx:\n    needs: [check_update, vpn_test]\n    if: needs.check_update.outputs.should_update == 'true'\n    uses: ./.github/workflows/buildx.yml\n    with:\n      os_type: debian\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME }}\n      DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}\n      QUAY_USER: ${{ secrets.QUAY_USER }}\n      QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}\n      BUILD_ONLY: ${{ secrets.BUILD_ONLY }}\n"
  },
  {
    "path": ".github/workflows/main-alpine.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      - '.github/workflows/main-alpine.yml'\n      - '.github/workflows/buildx.yml'\n      - '.github/workflows/shellcheck.yml'\n      - '.github/workflows/vpn_test.yml'\n      - '.dockerignore'\n      - 'Dockerfile'\n      - 'run.sh'\n\njobs:\n  shellcheck:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/shellcheck.yml\n\n  vpn_test:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/vpn_test.yml\n    with:\n      os_type: alpine\n\n  buildx:\n    needs: [shellcheck, vpn_test]\n    uses: ./.github/workflows/buildx.yml\n    with:\n      os_type: alpine\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME2 }}\n      DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}\n      QUAY_USER: ${{ secrets.QUAY_USER }}\n      QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}\n      BUILD_ONLY: ${{ secrets.BUILD_ONLY }}\n"
  },
  {
    "path": ".github/workflows/main-debian.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 debian\n\non:\n  push:\n    branches: [master]\n    paths:\n      - '.github/workflows/main-debian.yml'\n      - '.github/workflows/buildx.yml'\n      - '.github/workflows/shellcheck.yml'\n      - '.github/workflows/vpn_test.yml'\n      - '.dockerignore'\n      - 'Dockerfile.debian'\n      - 'run.sh'\n\njobs:\n  shellcheck:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/shellcheck.yml\n\n  vpn_test:\n    if: github.repository_owner == 'hwdsl2'\n    uses: ./.github/workflows/vpn_test.yml\n    with:\n      os_type: debian\n\n  buildx:\n    needs: [shellcheck, vpn_test]\n    uses: ./.github/workflows/buildx.yml\n    with:\n      os_type: debian\n    secrets:\n      CACHE_NAME: ${{ secrets.CACHE_NAME }}\n      DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}\n      QUAY_USER: ${{ secrets.QUAY_USER }}\n      QUAY_TOKEN: ${{ secrets.QUAY_TOKEN }}\n      BUILD_ONLY: ${{ secrets.BUILD_ONLY }}\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 vpn.env.example\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/vpn_test.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: vpn_test\n\non:\n  workflow_call:\n    inputs:\n      os_type:\n        required: true\n        type: string\n\njobs:\n  vpn_test:\n    runs-on: ubuntu-24.04\n    if: github.repository_owner == 'hwdsl2'\n    strategy:\n      matrix:\n        test_id: [no-env, with-env]\n      fail-fast: false\n    env:\n      OS_TYPE: ${{ inputs.os_type }}\n      TEST_ID: ${{ matrix.test_id }}\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Test\n        run: |\n          [ ! -x /usr/bin/docker ] && exit 1\n\n          cd \"$GITHUB_WORKSPACE\"\n          pwd\n          ls -ld vpn.env.example\n          sed -i '/ swan_ver_latest=/s/^/#/' run.sh\n          sed -i \\\n            -e '/VPN_IPSEC_PSK/s/# //' \\\n            -e '/VPN_USER/s/# //' \\\n            -e '/VPN_PASSWORD/s/# //' \\\n            -e '/VPN_DNS_NAME/s/# //' \\\n            -e '/VPN_CLIENT_NAME/s/# //' \\\n            -e '/VPN_DNS_SRV1/s/# //' \\\n            -e '/VPN_DNS_SRV2/s/# //' \\\n            vpn.env.example\n\n          set -x\n\n          if [ \"$OS_TYPE\" = \"alpine\" ]; then\n            docker build -t vpn-test .\n          elif [ \"$OS_TYPE\" = \"debian\" ]; then\n            docker build -f Dockerfile.debian -t vpn-test .\n          else\n            exit 1\n          fi\n\n          if [ \"$TEST_ID\" = \"with-env\" ]; then\n            docker run \\\n            --name \"$TEST_ID\" \\\n            --env-file ./vpn.env.example \\\n            --restart=always \\\n            -v ikev2-vpn-data:/etc/ipsec.d \\\n            -p 500:500/udp \\\n            -p 4500:4500/udp \\\n            -d --cap-add=NET_ADMIN \\\n            --device=/dev/ppp \\\n            --sysctl net.ipv4.ip_forward=1 \\\n            --sysctl net.ipv4.conf.all.accept_redirects=0 \\\n            --sysctl net.ipv4.conf.all.send_redirects=0 \\\n            --sysctl net.ipv4.conf.all.rp_filter=0 \\\n            --sysctl net.ipv4.conf.default.accept_redirects=0 \\\n            --sysctl net.ipv4.conf.default.send_redirects=0 \\\n            --sysctl net.ipv4.conf.default.rp_filter=0 \\\n            vpn-test\n          elif [ \"$TEST_ID\" = \"no-env\" ]; then\n            docker run \\\n            --name \"$TEST_ID\" \\\n            --restart=always \\\n            -p 500:500/udp \\\n            -p 4500:4500/udp \\\n            -d --privileged \\\n            vpn-test\n          fi\n\n          sleep 30\n          docker ps | grep \"$TEST_ID\"\n          docker logs \"$TEST_ID\"\n          docker exec \"$TEST_ID\" netstat -anpu | grep pluto\n          docker exec \"$TEST_ID\" netstat -anpu | grep xl2tpd\n          docker exec \"$TEST_ID\" iptables -nvL\n          docker exec \"$TEST_ID\" iptables -nvL | grep -q 'ppp+'\n          docker exec \"$TEST_ID\" iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n          docker exec \"$TEST_ID\" iptables -nvL -t nat\n          docker exec \"$TEST_ID\" iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n          docker exec \"$TEST_ID\" iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          docker exec \"$TEST_ID\" ipsec status\n          docker exec \"$TEST_ID\" ipsec status | grep -q l2tp-psk\n          docker exec \"$TEST_ID\" ipsec status | grep -q xauth-psk\n          if [ \"$TEST_ID\" = \"with-env\" ]; then\n            source ./vpn.env.example\n            docker exec \"$TEST_ID\" grep \"$VPN_IPSEC_PSK\" /etc/ipsec.secrets\n            docker exec \"$TEST_ID\" grep \"$VPN_USER\" /etc/ppp/chap-secrets\n            docker exec \"$TEST_ID\" grep \"$VPN_PASSWORD\" /etc/ppp/chap-secrets\n            docker exec \"$TEST_ID\" grep \"$VPN_USER\" /etc/ipsec.d/passwd\n            docker exec \"$TEST_ID\" ipsec status | grep -q ikev2-cp\n            docker exec \"$TEST_ID\" grep 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.conf\n            docker exec \"$TEST_ID\" grep 'ms-dns 1.1.1.1' /etc/ppp/options.xl2tpd\n            docker exec \"$TEST_ID\" grep 'ms-dns 1.0.0.1' /etc/ppp/options.xl2tpd\n            docker exec \"$TEST_ID\" grep 'leftid=@vpn.example.com' /etc/ipsec.d/ikev2.conf\n            docker exec \"$TEST_ID\" grep 'modecfgdns=\"1.1.1.1 1.0.0.1\"' /etc/ipsec.d/ikev2.conf\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/your_client_name.mobileconfig\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/your_client_name.sswan\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/your_client_name.p12\n            docker exec \"$TEST_ID\" grep 'vpn.example.com' /etc/ipsec.d/your_client_name.mobileconfig\n            docker exec \"$TEST_ID\" grep 'vpn.example.com' /etc/ipsec.d/your_client_name.sswan\n            docker exec \"$TEST_ID\" ikev2.sh --addclient vpnclient2\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.sswan\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.p12\n            docker exec \"$TEST_ID\" rm -f /etc/ipsec.d/vpnclient2*\n            docker exec \"$TEST_ID\" ikev2.sh --exportclient vpnclient2\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.mobileconfig\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.sswan\n            docker exec \"$TEST_ID\" ls -ld /etc/ipsec.d/vpnclient2.p12\n            docker exec \"$TEST_ID\" ikev2.sh --listclients\n            echo \"y\" | docker exec -i \"$TEST_ID\" ikev2.sh --revokeclient vpnclient2\n          else\n            docker exec \"$TEST_ID\" ipsec status | grep -q ikev2-cp && exit 1\n          fi\n\n          docker restart \"$TEST_ID\"\n\n          sleep 10\n          docker ps | grep \"$TEST_ID\"\n          docker logs \"$TEST_ID\"\n          docker exec \"$TEST_ID\" netstat -anpu | grep pluto\n          docker exec \"$TEST_ID\" netstat -anpu | grep xl2tpd\n          docker exec \"$TEST_ID\" iptables -nvL\n          docker exec \"$TEST_ID\" iptables -nvL | grep -q 'ppp+'\n          docker exec \"$TEST_ID\" iptables -nvL | grep -q '192\\.168\\.43\\.0/24'\n          docker exec \"$TEST_ID\" iptables -nvL -t nat\n          docker exec \"$TEST_ID\" iptables -nvL -t nat | grep -q '192\\.168\\.42\\.0/24'\n          docker exec \"$TEST_ID\" iptables -nvL -t nat | grep -q '192\\.168\\.43\\.0/24'\n          docker exec \"$TEST_ID\" ipsec status\n          docker exec \"$TEST_ID\" ipsec status | grep -q l2tp-psk\n          docker exec \"$TEST_ID\" ipsec status | grep -q xauth-psk\n          if [ \"$TEST_ID\" = \"with-env\" ]; then\n            docker exec \"$TEST_ID\" ipsec status | grep -q ikev2-cp\n            echo \"y\" | docker exec -i \"$TEST_ID\" ikev2.sh --removeikev2\n            sleep 3\n          fi\n          docker exec \"$TEST_ID\" ipsec status | grep -q ikev2-cp && exit 1\n\n          exit 0\n      - name: Clear\n        if: always()\n        run: |\n          docker rm -f \"$TEST_ID\" || true\n          docker rmi vpn-test || true\n"
  },
  {
    "path": ".gitignore",
    "content": "vpn.env\n"
  },
  {
    "path": "Dockerfile",
    "content": "#\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\nFROM alpine:3.23\n\nENV SWAN_VER=5.3\nWORKDIR /opt/src\n\nRUN set -x \\\n    && apk add --no-cache \\\n         bash bind-tools coreutils openssl uuidgen wget xl2tpd iptables iptables-legacy ip6tables \\\n         iproute2 libcap-ng libcurl libevent linux-pam musl nspr nss nss-tools openrc \\\n         bison flex gcc make libc-dev bsd-compat-headers linux-pam-dev \\\n         nss-dev libcap-ng-dev libevent-dev curl-dev nspr-dev \\\n    && cd /sbin \\\n    && for fn in iptables iptables-save iptables-restore \\\n                 ip6tables ip6tables-save ip6tables-restore; do \\\n         ln -fs xtables-legacy-multi \"$fn\"; done \\\n    && cd /opt/src \\\n    && wget -t 3 -T 30 -nv -O libreswan.tar.gz \"https://github.com/libreswan/libreswan/archive/v${SWAN_VER}.tar.gz\" \\\n    || wget -t 3 -T 30 -nv -O libreswan.tar.gz \"https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz\" \\\n    && tar xzf libreswan.tar.gz \\\n    && rm -f libreswan.tar.gz \\\n    && cd \"libreswan-${SWAN_VER}\" \\\n    && printf 'WERROR_CFLAGS=-w -s\\nUSE_DNSSEC=false\\nUSE_DH2=true\\n' > Makefile.inc.local \\\n    && printf 'FINALNSSDIR=/etc/ipsec.d\\nNSSDIR=/etc/ipsec.d\\n' >> Makefile.inc.local \\\n    && make -s base \\\n    && make -s install-base \\\n    && cd /opt/src \\\n    && mkdir -p /run/openrc \\\n    && touch /run/openrc/softlevel \\\n    && rm -rf \"/opt/src/libreswan-${SWAN_VER}\" \\\n    && apk del --no-cache \\\n         bison flex gcc make libc-dev bsd-compat-headers linux-pam-dev \\\n         nss-dev libcap-ng-dev libevent-dev curl-dev nspr-dev\n\nRUN wget -t 3 -T 30 -nv -O /opt/src/ikev2.sh https://github.com/hwdsl2/setup-ipsec-vpn/raw/5414cdfb71b0d02aea04c124ba71e3d7916fa984/extras/ikev2setup.sh \\\n    && chmod +x /opt/src/ikev2.sh \\\n    && ln -s /opt/src/ikev2.sh /usr/bin\n\nCOPY ./run.sh /opt/src/run.sh\nRUN chmod 755 /opt/src/run.sh\nEXPOSE 500/udp 4500/udp\nCMD [\"/opt/src/run.sh\"]\n\nARG BUILD_DATE\nARG VERSION\nARG VCS_REF\nENV IMAGE_VER=$BUILD_DATE\n\nLABEL maintainer=\"Lin Song <linsongui@gmail.com>\" \\\n    org.opencontainers.image.created=\"$BUILD_DATE\" \\\n    org.opencontainers.image.version=\"$VERSION\" \\\n    org.opencontainers.image.revision=\"$VCS_REF\" \\\n    org.opencontainers.image.authors=\"Lin Song <linsongui@gmail.com>\" \\\n    org.opencontainers.image.title=\"IPsec VPN Server on Docker\" \\\n    org.opencontainers.image.description=\"Docker image to run an IPsec VPN server, with IPsec/L2TP, Cisco IPsec and IKEv2.\" \\\n    org.opencontainers.image.url=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\" \\\n    org.opencontainers.image.source=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\" \\\n    org.opencontainers.image.documentation=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\"\n"
  },
  {
    "path": "Dockerfile.debian",
    "content": "#\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\nFROM debian:bookworm-slim\n\nENV SWAN_VER=5.3\nWORKDIR /opt/src\n\nRUN apt-get -yqq update \\\n    && DEBIAN_FRONTEND=noninteractive \\\n       apt-get -yqq --no-install-recommends install \\\n         wget dnsutils openssl ca-certificates kmod iproute2 \\\n         gawk net-tools iptables bsdmainutils libcurl3-nss \\\n         libnss3-tools libevent-dev uuid-runtime xl2tpd \\\n         libnss3-dev libnspr4-dev pkg-config libpam0g-dev \\\n         libcap-ng-dev libcap-ng-utils libselinux1-dev \\\n         libcurl4-nss-dev flex bison gcc make \\\n    && wget -t 3 -T 30 -nv -O libreswan.tar.gz \"https://github.com/libreswan/libreswan/archive/v${SWAN_VER}.tar.gz\" \\\n    || wget -t 3 -T 30 -nv -O libreswan.tar.gz \"https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz\" \\\n    && tar xzf libreswan.tar.gz \\\n    && rm -f libreswan.tar.gz \\\n    && cd \"libreswan-${SWAN_VER}\" \\\n    && printf 'WERROR_CFLAGS=-w -s\\nUSE_DNSSEC=false\\nUSE_SYSTEMD_WATCHDOG=false\\n' > Makefile.inc.local \\\n    && printf 'USE_DH2=true\\nUSE_NSS_KDF=false\\nFINALNSSDIR=/etc/ipsec.d\\nNSSDIR=/etc/ipsec.d\\n' >> Makefile.inc.local \\\n    && make -s base \\\n    && make -s install-base \\\n    && cd /opt/src \\\n    && rm -rf \"/opt/src/libreswan-${SWAN_VER}\" \\\n    && apt-get -yqq remove \\\n         libnss3-dev libnspr4-dev pkg-config libpam0g-dev \\\n         libcap-ng-dev libcap-ng-utils libselinux1-dev \\\n         libcurl4-nss-dev flex bison gcc make \\\n    && apt-get -yqq autoremove \\\n    && apt-get -y clean \\\n    && rm -rf /var/lib/apt/lists/* \\\n    && rm -rf /var/log/* \\\n    && update-alternatives --set iptables /usr/sbin/iptables-legacy \\\n    && update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy\n\nRUN wget -t 3 -T 30 -nv -O /opt/src/ikev2.sh https://github.com/hwdsl2/setup-ipsec-vpn/raw/5414cdfb71b0d02aea04c124ba71e3d7916fa984/extras/ikev2setup.sh \\\n    && chmod +x /opt/src/ikev2.sh \\\n    && ln -s /opt/src/ikev2.sh /usr/bin\n\nCOPY ./run.sh /opt/src/run.sh\nRUN chmod 755 /opt/src/run.sh\nEXPOSE 500/udp 4500/udp\nCMD [\"/opt/src/run.sh\"]\n\nARG BUILD_DATE\nARG VERSION\nARG VCS_REF\nENV IMAGE_VER=$BUILD_DATE\n\nLABEL maintainer=\"Lin Song <linsongui@gmail.com>\" \\\n    org.opencontainers.image.created=\"$BUILD_DATE\" \\\n    org.opencontainers.image.version=\"$VERSION\" \\\n    org.opencontainers.image.revision=\"$VCS_REF\" \\\n    org.opencontainers.image.authors=\"Lin Song <linsongui@gmail.com>\" \\\n    org.opencontainers.image.title=\"IPsec VPN Server on Docker\" \\\n    org.opencontainers.image.description=\"Docker image to run an IPsec VPN server, with IPsec/L2TP, Cisco IPsec and IKEv2.\" \\\n    org.opencontainers.image.url=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\" \\\n    org.opencontainers.image.source=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\" \\\n    org.opencontainers.image.documentation=\"https://github.com/hwdsl2/docker-ipsec-vpn-server\"\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) 2016-2026 [Lin Song](https://github.com/hwdsl2)   \nBased on [the work of Thomas Sarlandie](https://github.com/sarfata/voodooprivacy) (Copyright 2012)\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-ru.md",
    "content": "[English](README.md) | [简体中文](README-zh.md) | [繁體中文](README-zh-Hant.md) | [Русский](README-ru.md)\n\n# IPsec VPN сервер на Docker\n\n[![Build Status](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml/badge.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/)\n\nDocker-образ для запуска сервера IPsec VPN с поддержкой IPsec/L2TP, Cisco IPsec и IKEv2.\n\nОснован на Alpine 3.23 или Debian 12 с использованием [Libreswan](https://libreswan.org) (программное обеспечение IPsec VPN) и [xl2tpd](https://github.com/xelerance/xl2tpd) (демон L2TP).\n\nIPsec VPN шифрует сетевой трафик, поэтому никто между вами и VPN-сервером не сможет перехватывать ваши данные во время их передачи через Интернет. Это особенно полезно при использовании незащищённых сетей, например в кофейнях, аэропортах или гостиничных номерах.\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Используйте эту команду для настройки сервера IPsec VPN в Docker:\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\nДанные для входа в VPN будут сгенерированы случайным образом. См. раздел [Получение данных для входа в VPN](#получение-данных-для-входа-в-vpn).\n\nВ качестве альтернативы вы можете [настроить IPsec VPN без Docker](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-ru.md). Чтобы узнать больше о том, как использовать этот образ, прочитайте разделы ниже.\n\n## Возможности\n\n- Поддержка IKEv2 с мощными и быстрыми шифрами (например, AES-GCM)\n- Генерация VPN-профилей для автоматической настройки устройств iOS, macOS и Android\n- Поддержка Windows, macOS, iOS, Android, Chrome OS и Linux в качестве VPN-клиентов\n- Включает вспомогательный скрипт для управления пользователями и сертификатами IKEv2\n\n## Установка Docker\n\nСначала [установите Docker](https://docs.docker.com/engine/install/) на ваш Linux-сервер. Вы также можете использовать [Podman](https://podman.io) для запуска этого образа после [создания псевдонима](https://podman.io/whatis.html) для `docker`.\n\nПродвинутые пользователи могут использовать этот образ на macOS с помощью [Docker for Mac](https://docs.docker.com/docker-for-mac/). Перед использованием режима IPsec/L2TP может потребоваться один раз перезапустить контейнер Docker с помощью `docker restart ipsec-vpn-server`. Этот образ не поддерживает Docker for Windows.\n\n## Загрузка\n\nПолучите доверенную сборку из [реестра Docker Hub](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/):\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\nВ качестве альтернативы можно скачать из [Quay.io](https://quay.io/repository/hwdsl2/ipsec-vpn-server):\n\n```\ndocker pull quay.io/hwdsl2/ipsec-vpn-server\ndocker image tag quay.io/hwdsl2/ipsec-vpn-server hwdsl2/ipsec-vpn-server\n```\n\nПоддерживаемые платформы: `linux/amd64`, `linux/arm64` и `linux/arm/v7`.\n\nПродвинутые пользователи могут [собрать образ из исходного кода](docs/advanced-usage.md#build-from-source-code) на GitHub.\n\n### Сравнение образов\n\nДоступны два предварительно собранных образа. Образ на базе Alpine используется по умолчанию и имеет размер всего около ~19 MB.\n\n|                   | На базе Alpine            | На базе Debian                 |\n| ----------------- | ------------------------- | ------------------------------ |\n| Имя образа        | hwdsl2/ipsec-vpn-server   | hwdsl2/ipsec-vpn-server:debian |\n| Сжатый размер     | ~ 19 MB                   | ~ 62 MB                        |\n| Базовый образ     | Alpine Linux 3.23         | Debian Linux 12                |\n| Платформы         | amd64, arm64, arm/v7      | amd64, arm64, arm/v7           |\n| Версия Libreswan  | 5.3                       | 5.3                            |\n| IPsec/L2TP        | ✅                         | ✅                              |\n| Cisco IPsec       | ✅                         | ✅                              |\n| IKEv2             | ✅                         | ✅                              |\n\n**Примечание:** Чтобы использовать образ на базе Debian, замените каждое `hwdsl2/ipsec-vpn-server` на `hwdsl2/ipsec-vpn-server:debian` в этом README. В настоящее время эти образы несовместимы с системами Synology NAS.\n\n<details>\n<summary>\nЯ хочу использовать более старую версию Libreswan 4.\n</summary>\n\nОбычно рекомендуется использовать последнюю версию [Libreswan](https://libreswan.org/) 5, которая является версией по умолчанию в этом проекте. Однако если вы хотите использовать более старую версию Libreswan 4, вы можете собрать Docker-образ из исходного кода:\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# Указать версию Libreswan 4\nsed -i 's/SWAN_VER=5\\..*/SWAN_VER=4.15/' Dockerfile Dockerfile.debian\n# Сборка образа на базе Alpine\ndocker build -t hwdsl2/ipsec-vpn-server .\n# Сборка образа на базе Debian\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n</details>\n\n## Как использовать этот образ\n\n### Переменные окружения\n\n**Примечание:** Все переменные для этого образа являются необязательными, что означает, что вам не нужно указывать ни одну переменную — и вы сможете получить работающий сервер IPsec VPN «из коробки»! Для этого создайте пустой файл `env` с помощью `touch vpn.env`, а затем перейдите к следующему разделу.\n\nЭтот Docker-образ использует следующие переменные, которые можно объявить в файле `env` (см. [пример](vpn.env.example)):\n\n```\nVPN_IPSEC_PSK=your_ipsec_pre_shared_key\nVPN_USER=your_vpn_username\nVPN_PASSWORD=your_vpn_password\n```\n\nЭто создаст учетную запись пользователя для входа в VPN, которую можно использовать на нескольких ваших устройствах[\\*](#важные-замечания). IPsec PSK (предварительно общий ключ) задаётся переменной окружения `VPN_IPSEC_PSK`. Имя пользователя VPN задаётся в `VPN_USER`, а пароль VPN указывается в `VPN_PASSWORD`.\n\nПоддерживаются дополнительные пользователи VPN, и их можно при желании объявить в вашем файле `env` следующим образом. Имена пользователей и пароли должны быть разделены пробелами, а имена пользователей не могут повторяться. Все пользователи VPN будут использовать один и тот же IPsec PSK.\n\n```\nVPN_ADDL_USERS=additional_username_1 additional_username_2\nVPN_ADDL_PASSWORDS=additional_password_1 additional_password_2\n```\n\nПеременные выше используются только для режимов IPsec/L2TP и IPsec/XAuth («Cisco IPsec»). Для IKEv2 см. [Настройка и использование IKEv2 VPN](#настройка-и-использование-ikev2-vpn).\n\n**Примечание:** В файле `env` НЕ помещайте `\"\"` или `''` вокруг значений и не добавляйте пробелы вокруг `=`. НЕ используйте внутри значений следующие специальные символы: `\\ \" '`. Надёжный IPsec PSK должен состоять как минимум из 20 случайных символов.\n\n**Примечание:** Если вы измените файл `env` после того, как Docker-контейнер уже создан, необходимо удалить и создать контейнер заново, чтобы изменения вступили в силу. См. раздел [Обновление Docker-образа](#обновление-docker-образа).\n\n### Дополнительные переменные окружения\n\nПродвинутые пользователи могут при желании указать DNS-имя, имя клиента и/или собственные DNS-серверы.\n\n<details>\n<summary>\nУзнайте, как указать DNS-имя, имя клиента и/или собственные DNS-серверы.\n</summary>\n\nПродвинутые пользователи могут при желании указать DNS-имя для адреса сервера IKEv2. DNS-имя должно быть полным доменным именем (FQDN). Пример:\n\n```\nVPN_DNS_NAME=vpn.example.com\n```\n\nВы можете указать имя для первого клиента IKEv2. Используйте только одно слово, без специальных символов, кроме `-` и `_`. По умолчанию используется `vpnclient`, если имя не указано.\n\n```\nVPN_CLIENT_NAME=your_client_name\n```\n\nПо умолчанию клиенты используют [Google Public DNS](https://developers.google.com/speed/public-dns/) при активном VPN. Вы можете указать собственные DNS-серверы для всех режимов VPN. Пример:\n\n```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\nДля получения дополнительных сведений и списка популярных публичных DNS-провайдеров см. [Использование альтернативных DNS-серверов](docs/advanced-usage.md).\n\nПо умолчанию пароль не требуется при импорте конфигурации клиента IKEv2. Вы можете защитить файлы конфигурации клиента случайным паролем.\n\n```\nVPN_PROTECT_CONFIG=yes\n```\n\n**Примечание:** Переменные выше не влияют на режим IKEv2, если IKEv2 уже настроен в Docker-контейнере. В этом случае вы можете удалить IKEv2 и настроить его снова с пользовательскими параметрами. См. [Настройка и использование IKEv2 VPN](#настройка-и-использование-ikev2-vpn).\n</details>\n\n### Запуск сервера IPsec VPN\n\nСоздайте новый Docker-контейнер из этого образа (замените `./vpn.env` на ваш собственный файл `env`):\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\nВ этой команде используется параметр `-v` команды `docker run`, чтобы создать новый [Docker volume](https://docs.docker.com/storage/volumes/) с именем `ikev2-vpn-data` и смонтировать его в `/etc/ipsec.d` внутри контейнера. Данные, связанные с IKEv2 (такие как сертификаты и ключи), будут сохраняться в этом томе. Позже, если вам потребуется заново создать Docker-контейнер, просто укажите тот же том снова.\n\nРекомендуется включить IKEv2 при использовании этого образа. Однако если вы предпочитаете не использовать IKEv2 и подключаться к VPN только через режимы IPsec/L2TP и IPsec/XAuth («Cisco IPsec»), удалите первый параметр `-v` из команды `docker run`, приведённой выше.\n\n**Примечание:** Продвинутые пользователи также могут [запускать контейнер без привилегированного режима](docs/advanced-usage.md#run-without-privileged-mode).\n\n### Получение данных для входа в VPN\n\nЕсли вы не указали файл `env` в команде `docker run` выше, значение `VPN_USER` по умолчанию будет `vpnuser`, а `VPN_IPSEC_PSK` и `VPN_PASSWORD` будут сгенерированы случайным образом. Чтобы получить их, просмотрите журналы контейнера:\n\n```\ndocker logs ipsec-vpn-server\n```\n\nНайдите в выводе следующие строки:\n\n```\nConnect to your new VPN with these details:\n\nServer IP: your_vpn_server_ip\nIPsec PSK: your_ipsec_pre_shared_key\nUsername: your_vpn_username\nPassword: your_vpn_password\n```\n\nВывод также будет содержать сведения для режима IKEv2, если он включён.\n\n(Необязательно) Сохраните сгенерированные данные для входа в VPN (если они есть) в текущий каталог:\n\n```\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpn-gen.env ./\n```\n\n## Следующие шаги\n\n*Прочитать на других языках: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [Русский](README-ru.md#следующие-шаги).*\n\nНастройте ваш компьютер или устройство для использования VPN. Пожалуйста, обратитесь к следующим инструкциям (на английском языке):\n\n**[Настройка и использование IKEv2 VPN (рекомендуется)](#настройка-и-использование-ikev2-vpn)**\n\n**[Настройка клиентов IPsec/L2TP VPN](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md)**\n\n**[Настройка клиентов IPsec/XAuth («Cisco IPsec»)](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/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 требуется [одноразовое изменение реестра](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#windows-error-809), если VPN-сервер или клиент находится за NAT (например, домашним роутером).\n\nОдна и та же учетная запись VPN может использоваться на нескольких ваших устройствах. Однако из-за ограничения IPsec/L2TP, если вы хотите подключить несколько устройств из-за одного NAT (например, домашнего роутера), необходимо использовать режим [IKEv2](#настройка-и-использование-ikev2-vpn) или [IPsec/XAuth](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth.md).\n\nЕсли вы хотите добавить, изменить или удалить учетные записи пользователей VPN, сначала обновите файл `env`, затем удалите и заново создайте Docker-контейнер, следуя инструкциям из [следующего раздела](#обновление-docker-образа). Продвинутые пользователи могут использовать [bind mount](docs/advanced-usage.md#bind-mount-the-env-file) для файла `env`.\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#use-alternative-dns-servers).\n\n## Обновление Docker-образа\n\nЧтобы обновить Docker-образ и контейнер, сначала [загрузите](#загрузка) последнюю версию:\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\nЕсли Docker-образ уже обновлён, вы увидите:\n\n```\nStatus: Image is up to date for hwdsl2/ipsec-vpn-server:latest\n```\n\nВ противном случае будет загружена последняя версия. Чтобы обновить Docker-контейнер, сначала запишите все ваши [данные для входа в VPN](#получение-данных-для-входа-в-vpn). Затем удалите контейнер Docker с помощью `docker rm -f ipsec-vpn-server`. После этого создайте его заново, следуя инструкциям из раздела [Как использовать этот образ](#как-использовать-этот-образ).\n\n## Настройка и использование IKEv2 VPN\n\nРежим IKEv2 имеет преимущества по сравнению с IPsec/L2TP и IPsec/XAuth («Cisco IPsec») и не требует IPsec PSK, имени пользователя или пароля. Подробнее можно прочитать [здесь](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md).\n\nСначала проверьте журналы контейнера, чтобы увидеть сведения о IKEv2:\n\n```bash\ndocker logs ipsec-vpn-server\n```\n\n**Примечание:** Если вы не можете найти сведения о IKEv2, возможно, IKEv2 не включён в контейнере. Попробуйте обновить Docker-образ и контейнер, следуя инструкциям из раздела [Обновление Docker-образа](#обновление-docker-образа).\n\nВо время настройки IKEv2 создаётся клиент IKEv2 (с именем по умолчанию `vpnclient`), а его конфигурация экспортируется в `/etc/ipsec.d` **внутри контейнера**. Чтобы скопировать файл(ы) конфигурации на Docker-хост:\n\n```\n# Проверить содержимое /etc/ipsec.d в контейнере\ndocker exec -it ipsec-vpn-server ls -l /etc/ipsec.d\n# Пример: копирование файла конфигурации клиента из контейнера\n# в текущий каталог на Docker-хосте\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpnclient.p12 ./\n```\n\n**Следующие шаги:** [Настройте ваши устройства](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md) для использования IKEv2 VPN.\n\n<details>\n<summary>\nУзнайте, как управлять клиентами IKEv2.\n</summary>\n\nВы можете управлять клиентами IKEv2 с помощью вспомогательного скрипта. Ниже приведены примеры. Чтобы настроить параметры клиента, запустите скрипт без аргументов.\n\n```bash\n# Добавить нового клиента (с параметрами по умолчанию)\ndocker exec -it ipsec-vpn-server ikev2.sh --addclient [имя клиента]\n# Экспортировать конфигурацию для существующего клиента\ndocker exec -it ipsec-vpn-server ikev2.sh --exportclient [имя клиента]\n# Показать список существующих клиентов\ndocker exec -it ipsec-vpn-server ikev2.sh --listclients\n# Показать справку\ndocker exec -it ipsec-vpn-server ikev2.sh -h\n```\n\n**Примечание:** Если возникает ошибка «executable file not found», замените `ikev2.sh` выше на `/opt/src/ikev2.sh`.\n</details>\n<details>\n<summary>\nУзнайте, как изменить адрес сервера IKEv2.\n</summary>\n\nВ некоторых случаях может потребоваться изменить адрес сервера IKEv2. Например, чтобы перейти на использование DNS-имени или после изменения IP-адреса сервера. Чтобы изменить адрес сервера IKEv2, сначала [откройте bash-оболочку внутри контейнера](docs/advanced-usage.md#bash-shell-inside-container), затем [следуйте этим инструкциям](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md#change-ikev2-server-address). Обратите внимание, что журналы контейнера не будут показывать новый адрес сервера IKEv2, пока вы не перезапустите Docker-контейнер.\n</details>\n<details>\n<summary>\nУдаление IKEv2 и повторная настройка с пользовательскими параметрами.\n</summary>\n\nВ некоторых случаях может потребоваться удалить IKEv2 и настроить его заново с пользовательскими параметрами.\n\n**Предупреждение:** Вся конфигурация IKEv2, включая сертификаты и ключи, будет **безвозвратно удалена**. Это **нельзя отменить**!\n\n**Вариант 1:** Удалить IKEv2 и настроить его снова с помощью вспомогательного скрипта.\n\nОбратите внимание, что это переопределит переменные, указанные в файле `env`, такие как `VPN_DNS_NAME` и `VPN_CLIENT_NAME`, а журналы контейнера больше не будут показывать актуальную информацию для IKEv2.\n\n```bash\n# Удалить IKEv2 и удалить всю конфигурацию IKEv2\ndocker exec -it ipsec-vpn-server ikev2.sh --removeikev2\n# Настроить IKEv2 снова с пользовательскими параметрами\ndocker exec -it ipsec-vpn-server ikev2.sh\n```\n\n**Вариант 2:** Удалить `ikev2-vpn-data` и создать контейнер заново.\n\n1. Запишите все ваши [данные для входа в VPN](#получение-данных-для-входа-в-vpn).\n1. Удалите Docker-контейнер: `docker rm -f ipsec-vpn-server`.\n1. Удалите том `ikev2-vpn-data`: `docker volume rm ikev2-vpn-data`.\n1. Обновите файл `env` и добавьте пользовательские параметры IKEv2, такие как `VPN_DNS_NAME` и `VPN_CLIENT_NAME`, затем создайте контейнер заново. См. раздел [Как использовать этот образ](#как-использовать-этот-образ).\n</details>\n\n## Расширенное использование\n\nСм. [Расширенное использование](docs/advanced-usage.md) (на английском языке).\n\n- [Использование альтернативных DNS-серверов](docs/advanced-usage.md#use-alternative-dns-servers)\n- [Запуск без привилегированного режима](docs/advanced-usage.md#run-without-privileged-mode)\n- [Выбор режимов VPN](docs/advanced-usage.md#select-vpn-modes)\n- [Доступ к другим контейнерам на Docker-хосте](docs/advanced-usage.md#access-other-containers-on-the-docker-host)\n- [Указание публичного IP-адреса VPN-сервера](docs/advanced-usage.md#specify-vpn-servers-public-ip)\n- [Назначение статических IP-адресов клиентам VPN](docs/advanced-usage.md#assign-static-ips-to-vpn-clients)\n- [Настройка подсетей VPN](docs/advanced-usage.md#customize-vpn-subnets)\n- [Поддержка IPv6](docs/advanced-usage.md#ipv6-support)\n- [Раздельная маршрутизация (Split tunneling)](docs/advanced-usage.md#split-tunneling)\n- [О режиме сетевого хоста](docs/advanced-usage.md#about-host-network-mode)\n- [Включение журналов Libreswan](docs/advanced-usage.md#enable-libreswan-logs)\n- [Проверка состояния сервера](docs/advanced-usage.md#check-server-status)\n- [Сборка из исходного кода](docs/advanced-usage.md#build-from-source-code)\n- [Bash-оболочка внутри контейнера](docs/advanced-usage.md#bash-shell-inside-container)\n- [Bind mount файла env](docs/advanced-usage.md#bind-mount-the-env-file)\n- [Развёртывание алгоритма управления перегрузкой Google BBR](docs/advanced-usage.md#deploy-google-bbr-congestion-control)\n\n## Технические детали\n\nЗапущены два сервиса: `Libreswan (pluto)` для IPsec VPN и `xl2tpd` для поддержки L2TP.\n\nКонфигурация IPsec по умолчанию поддерживает:\n\n* IPsec/L2TP с PSK\n* IKEv1 с PSK и XAuth («Cisco IPsec»)\n* IKEv2\n\nПорты, которые должны быть открыты для работы контейнера:\n\n* 4500/udp и 500/udp для IPsec\n\n## Лицензия\n\n**Примечание:** Компоненты программного обеспечения внутри предварительно собранного образа (например, Libreswan и xl2tpd) распространяются по лицензиям, выбранным их правообладателями. Как и в случае использования любого готового образа, пользователь образа несёт ответственность за то, чтобы использование этого образа соответствовало всем применимым лицензиям для программного обеспечения, содержащегося внутри.\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Основано на [работе 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-ru.md)\n\n# Docker 上的 IPsec VPN 伺服器\n\n[![Build Status](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml/badge.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/)\n\n使用此 Docker 映像快速架設 IPsec VPN 伺服器。支援 IPsec/L2TP、Cisco IPsec 和 IKEv2 協議。\n\n本映像以 Alpine 3.23 或 Debian 12 為基礎，並使用 [Libreswan](https://libreswan.org)（IPsec VPN 軟體）和 [xl2tpd](https://github.com/xelerance/xl2tpd)（L2TP 服務程序）。\n\nIPsec VPN 可以加密你的網路流量，以防止在透過網際網路傳送時，你與 VPN 伺服器之間的任何人未經授權存取你的資料。在使用不安全的網路時，這一點特別有用，例如在咖啡廳、機場或旅館房間。\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使用以下命令在 Docker 上快速架設 IPsec VPN 伺服器：\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\n你的 VPN 登入憑證將會自動隨機生成。請參見[取得 VPN 登入資訊](#取得-vpn-登入資訊)。\n\n另外，你也可以在不使用 Docker 的情況下[安裝 IPsec VPN](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh-Hant.md)。若要了解更多關於如何使用本映像的資訊，請繼續閱讀以下部分。\n\n## 功能特性\n\n- 支援具有強大且快速加密演算法（例如 AES-GCM）的 IKEv2 模式\n- 生成 VPN 設定檔以自動設定 iOS、macOS 和 Android 裝置\n- 支援 Windows、macOS、iOS、Android、Chrome OS 和 Linux 客戶端\n- 包含輔助腳本以管理 IKEv2 使用者與憑證\n\n## 安裝 Docker\n\n首先在你的 Linux 伺服器上[安裝 Docker](https://docs.docker.com/engine/install/)。另外你也可以使用 [Podman](https://podman.io) 執行本映像，需要先為 `docker` 命令[建立一個別名](https://podman.io/whatis.html)。\n\n進階使用者可以在 macOS 上透過安裝 [Docker for Mac](https://docs.docker.com/docker-for-mac/) 使用本映像。在使用 IPsec/L2TP 模式之前，你可能需要執行 `docker restart ipsec-vpn-server` 重新啟動一次 Docker 容器。本映像不支援 Docker for Windows。\n\n## 下載\n\n預先建構的可信任映像可在 [Docker Hub registry](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) 下載：\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\n或者，你也可以從 [Quay.io](https://quay.io/repository/hwdsl2/ipsec-vpn-server) 下載：\n\n```\ndocker pull quay.io/hwdsl2/ipsec-vpn-server\ndocker image tag quay.io/hwdsl2/ipsec-vpn-server hwdsl2/ipsec-vpn-server\n```\n\n支援以下架構系統：`linux/amd64`、`linux/arm64` 和 `linux/arm/v7`。\n\n進階使用者可以自行從 GitHub [編譯原始碼](docs/advanced-usage-zh.md#从源代码构建)。\n\n### 映像對照表\n\n有兩個預先建構的映像可用。預設的基於 Alpine 的映像大小僅約 ~19 MB。\n\n|                 | 基於 Alpine               | 基於 Debian                     |\n| --------------- | ------------------------ | ------------------------------ |\n| 映像名稱          | hwdsl2/ipsec-vpn-server  | hwdsl2/ipsec-vpn-server:debian |\n| 壓縮後大小        | ~ 19 MB                  | ~ 62 MB                        |\n| 基礎映像          | Alpine Linux 3.23        | Debian Linux 12                |\n| 系統架構          | amd64, arm64, arm/v7     | amd64, arm64, arm/v7           |\n| Libreswan 版本   | 5.3                      | 5.3                            |\n| IPsec/L2TP      | ✅                       | ✅                              |\n| Cisco IPsec     | ✅                       | ✅                              |\n| IKEv2           | ✅                       | ✅                              |\n\n**註：** 若要使用基於 Debian 的映像，請將本自述文件中所有的 `hwdsl2/ipsec-vpn-server` 替換為 `hwdsl2/ipsec-vpn-server:debian`。這些映像目前與 Synology NAS 系統不相容。\n\n<details>\n<summary>\n我需要使用較舊版本的 Libreswan 版本 4。\n</summary>\n\n一般建議使用最新的 [Libreswan](https://libreswan.org/) 版本 5，它是本專案的預設版本。不過，如果你想要使用較舊版本的 Libreswan 版本 4，你可以從原始碼建構 Docker 映像：\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# Specify Libreswan version 4\nsed -i 's/SWAN_VER=5\\..*/SWAN_VER=4.15/' Dockerfile Dockerfile.debian\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server .\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n</details>\n\n## 如何使用本映像\n\n### 環境變數\n\n**註：** 所有這些變數對於本映像都是可選的，也就是說即使不定義它們也可以架設 IPsec VPN 伺服器。你可以執行 `touch vpn.env` 建立一個空的 `env` 檔案，然後跳到下一節。\n\n此 Docker 映像使用以下幾個變數，可以在一個 `env` 檔案中定義（參見[範例](vpn.env.example)）：\n\n```\nVPN_IPSEC_PSK=your_ipsec_pre_shared_key\nVPN_USER=your_vpn_username\nVPN_PASSWORD=your_vpn_password\n```\n\n這將建立一個用於 VPN 登入的使用者帳戶，它可以在你的多個裝置上使用[\\*](#重要提示)。IPsec PSK（預共享金鑰）由 `VPN_IPSEC_PSK` 環境變數指定。VPN 使用者名稱與密碼分別在 `VPN_USER` 和 `VPN_PASSWORD` 中定義。\n\n支援建立額外的 VPN 使用者，如果需要，可以像下面這樣在你的 `env` 檔案中定義。使用者名稱與密碼必須分別使用空格分隔，並且使用者名稱不能重複。所有 VPN 使用者將共用同一個 IPsec PSK。\n\n```\nVPN_ADDL_USERS=additional_username_1 additional_username_2\nVPN_ADDL_PASSWORDS=additional_password_1 additional_password_2\n```\n\n以上變數僅適用於 IPsec/L2TP 和 IPsec/XAuth（\"Cisco IPsec\"）模式。對於 IKEv2，請參見[設定並使用 IKEv2 VPN](#設定並使用-ikev2-vpn)。\n\n**註：** 在你的 `env` 檔案中，**不要**為變數值加入 `\"\"` 或 `''`，或在 `=` 兩側加入空格。**不要**在值中使用這些字元： `\\ \" '`。一個安全的 IPsec PSK 應至少包含 20 個隨機字元。\n\n**註：** 如果在建立 Docker 容器後修改 `env` 檔案，則必須刪除並重新建立容器才能讓變更生效。請參見[更新 Docker 映像](#更新-docker-映像)。\n\n### 其他環境變數\n\n進階使用者可以指定一個網域名稱、客戶端名稱和/或其他 DNS 伺服器。這是可選的。\n\n<details>\n<summary>\n了解如何指定一個網域名稱、客戶端名稱和/或其他 DNS 伺服器。\n</summary>\n\n進階使用者可以指定一個網域名稱作為 IKEv2 伺服器位址。這是可選的。該網域名稱必須是完整網域名稱 (FQDN)。示例如下：\n\n```\nVPN_DNS_NAME=vpn.example.com\n```\n\n你可以指定第一個 IKEv2 客戶端的名稱。該名稱不能包含空格或除 `-` `_` 之外的任何特殊字元。如果未指定，則使用預設值 `vpnclient`。\n\n```\nVPN_CLIENT_NAME=your_client_name\n```\n\n在 VPN 已連線時，客戶端預設設定為使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。你可以為所有 VPN 模式指定其他 DNS 伺服器。示例如下：\n\n```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\n有關詳細資訊以及一些常見的公共 DNS 提供商列表，請參見[使用其他 DNS 伺服器](docs/advanced-usage-zh.md)。\n\n預設情況下，匯入 IKEv2 客戶端設定時不需要密碼。你可以選擇使用隨機密碼保護客戶端設定檔。\n\n```\nVPN_PROTECT_CONFIG=yes\n```\n\n**註：** 如果在 Docker 容器中已經設定 IKEv2，則以上變數對 IKEv2 模式無效。在這種情況下，你可以移除 IKEv2 並使用自訂選項重新設定它。請參見[設定並使用 IKEv2 VPN](#設定並使用-ikev2-vpn)。\n</details>\n\n### 執行 IPsec VPN 伺服器\n\n使用本映像建立一個新的 Docker 容器（將 `./vpn.env` 替換為你自己的 `env` 檔案）：\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\n在此命令中，我們使用 `docker run` 的 `-v` 選項來建立一個名為 `ikev2-vpn-data` 的新 [Docker 卷](https://docs.docker.com/storage/volumes/)，並將它掛載到容器內的 `/etc/ipsec.d` 目錄下。IKEv2 的相關資料（例如憑證與金鑰）會保存在該卷中，之後當你需要重新建立 Docker 容器時，只需指定同一個卷。\n\n建議在使用本映像時啟用 IKEv2。如果你不想啟用 IKEv2，而只使用 IPsec/L2TP 和 IPsec/XAuth（\"Cisco IPsec\"）模式連線到 VPN，可以移除上面 `docker run` 命令中的第一個 `-v` 選項。\n\n**註：** 進階使用者也可以[在不啟用 privileged 模式下執行](docs/advanced-usage-zh.md#不启用-privileged-模式运行)。\n\n### 取得 VPN 登入資訊\n\n如果你在上述 `docker run` 命令中沒有指定 `env` 檔案，`VPN_USER` 會預設為 `vpnuser`，並且 `VPN_IPSEC_PSK` 和 `VPN_PASSWORD` 會自動隨機生成。要取得這些登入資訊，可以查看容器的日誌：\n\n```\ndocker logs ipsec-vpn-server\n```\n\n在命令輸出中尋找以下幾行：\n\n```\nConnect to your new VPN with these details:\n\nServer IP: 你的VPN伺服器IP\nIPsec PSK: 你的IPsec預共享金鑰\nUsername: 你的VPN使用者名稱\nPassword: 你的VPN密碼\n```\n\n命令輸出中也會包含 IKEv2 設定資訊（如果已啟用）。\n\n（可選步驟）將自動生成的 VPN 登入資訊（如果有）備份到目前目錄：\n\n```\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpn-gen.env ./\n```\n\n## 下一步\n\n*其他語言版本: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [Русский](README-ru.md#следующие-шаги)。*\n\n設定你的電腦或其他裝置使用 VPN。請參見以下連結（簡體中文）：\n\n**[設定並使用 IKEv2 VPN（推薦）](#設定並使用-ikev2-vpn)**\n\n**[設定 IPsec/L2TP VPN 客戶端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md)**\n\n**[設定 IPsec/XAuth (\"Cisco IPsec\") VPN 客戶端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/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 模式，在首次連線之前需要[修改登錄檔](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#windows-错误-809)，以解決 VPN 伺服器或客戶端與 NAT（例如家用路由器）的相容問題。\n\n同一個 VPN 帳戶可以在你的多個裝置上使用。但由於 IPsec/L2TP 的限制，如果需要連線到同一個 NAT（例如家用路由器）後面的多個裝置，你必須使用 [IKEv2](#設定並使用-ikev2-vpn) 或 [IPsec/XAuth](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth-zh.md) 模式。\n\n如需新增、修改或刪除 VPN 使用者帳戶，請先更新你的 `env` 檔案，然後必須依照[下一節](#更新-docker-映像)的說明刪除並重新建立 Docker 容器。進階使用者可以[綁定掛載](docs/advanced-usage-zh.md#绑定挂载-env-文件) `env` 檔案。\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#使用其他的-dns-服务器)。\n\n## 更新 Docker 映像\n\n要更新 Docker 映像與容器，請先[下載](#下載)最新版本：\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\n如果 Docker 映像已經是最新版本，你會看到提示：\n\n```\nStatus: Image is up to date for hwdsl2/ipsec-vpn-server:latest\n```\n\n否則將會下載最新版本。要更新你的 Docker 容器，請先在紙上記下所有的 [VPN 登入資訊](#取得-vpn-登入資訊)。然後刪除 Docker 容器：`docker rm -f ipsec-vpn-server`。最後依照[如何使用本映像](#如何使用本映像)的說明重新建立它。\n\n## 設定並使用 IKEv2 VPN\n\nIKEv2 模式是比 IPsec/L2TP 和 IPsec/XAuth（\"Cisco IPsec\"）更好的連線模式，該模式不需要 IPsec PSK、使用者名稱或密碼。更多資訊請參見[這裡](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md)。\n\n首先，查看容器的日誌以取得 IKEv2 設定資訊：\n\n```bash\ndocker logs ipsec-vpn-server\n```\n\n**註：** 如果你找不到 IKEv2 設定資訊，IKEv2 可能未在容器中啟用。請嘗試依照[更新 Docker 映像](#更新-docker-映像)一節的說明更新 Docker 映像與容器。\n\n在 IKEv2 安裝過程中會建立一個 IKEv2 客戶端（預設名稱為 `vpnclient`），並將其設定匯出到 **容器內** 的 `/etc/ipsec.d` 目錄下。你可以將設定檔複製到 Docker 主機：\n\n```bash\n# 查看容器內的 /etc/ipsec.d 目錄檔案\ndocker exec -it ipsec-vpn-server ls -l /etc/ipsec.d\n# 範例：將一個客戶端設定檔從容器複製到 Docker 主機目前目錄\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpnclient.p12 ./\n```\n\n**下一步：** [設定你的裝置](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md)以使用 IKEv2 VPN。\n\n<details>\n<summary>\n了解如何管理 IKEv2 客戶端。\n</summary>\n\n你可以使用輔助腳本管理 IKEv2 客戶端。示例如下。如需自訂客戶端選項，可以在不加入參數的情況下執行腳本。\n\n```bash\n# 新增一個客戶端（使用預設選項）\ndocker exec -it ipsec-vpn-server ikev2.sh --addclient [client name]\n# 匯出一個已有客戶端的設定\ndocker exec -it ipsec-vpn-server ikev2.sh --exportclient [client name]\n# 列出已有的客戶端\ndocker exec -it ipsec-vpn-server ikev2.sh --listclients\n# 顯示使用說明\ndocker exec -it ipsec-vpn-server ikev2.sh -h\n```\n\n**註：** 如果你遇到錯誤 \"executable file not found\"，將上面的 `ikev2.sh` 改成 `/opt/src/ikev2.sh`。\n</details>\n<details>\n<summary>\n了解如何更改 IKEv2 伺服器位址。\n</summary>\n\n在某些情況下，你可能需要更改 IKEv2 伺服器位址。例如切換為使用網域名稱，或是在伺服器 IP 變更之後。要更改 IKEv2 伺服器位址，請先[在容器中執行 Bash shell](docs/advanced-usage-zh.md#在容器中运行-bash-shell)，然後[依照這裡的說明操作](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md#更改-ikev2-服务器地址)。請注意，在你重新啟動 Docker 容器之前，容器日誌不會顯示新的 IKEv2 伺服器位址。\n</details>\n<details>\n<summary>\n移除 IKEv2 並使用自訂選項重新設定。\n</summary>\n\n在某些情況下，你可能需要移除 IKEv2 並使用自訂選項重新設定它。\n\n**警告：** 這將**永久刪除**所有 IKEv2 設定（包括憑證與金鑰），並且**無法復原**！\n\n**選項 1：** 使用輔助腳本移除 IKEv2 並重新設定。\n\n請注意，這將覆蓋你在 `env` 檔案中指定的變數，例如 `VPN_DNS_NAME` 和 `VPN_CLIENT_NAME`，而且容器日誌將不再顯示 IKEv2 的最新資訊。\n\n```bash\n# 移除 IKEv2 並刪除所有 IKEv2 設定\ndocker exec -it ipsec-vpn-server ikev2.sh --removeikev2\n# 使用自訂選項重新設定 IKEv2\ndocker exec -it ipsec-vpn-server ikev2.sh\n```\n\n**選項 2：** 移除 `ikev2-vpn-data` 並重新建立容器。\n\n1. 在紙上記下所有的 [VPN 登入資訊](#取得-vpn-登入資訊)。\n1. 刪除 Docker 容器：`docker rm -f ipsec-vpn-server`。\n1. 刪除 `ikev2-vpn-data` 卷：`docker volume rm ikev2-vpn-data`。\n1. 更新你的 `env` 檔案並加入自訂 IKEv2 選項，例如 `VPN_DNS_NAME` 和 `VPN_CLIENT_NAME`，然後重新建立容器。請參見[如何使用本映像](#如何使用本映像)。\n</details>\n\n## 進階用法\n\n請參見[進階用法](docs/advanced-usage-zh.md)（簡體中文）。\n\n- [使用其他 DNS 伺服器](docs/advanced-usage-zh.md#使用其他的-dns-服务器)\n- [不啟用 privileged 模式執行](docs/advanced-usage-zh.md#不启用-privileged-模式运行)\n- [選擇 VPN 模式](docs/advanced-usage-zh.md#选择-vpn-模式)\n- [存取 Docker 主機上的其他容器](docs/advanced-usage-zh.md#访问-docker-主机上的其它容器)\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- [關於 host network 模式](docs/advanced-usage-zh.md#关于-host-network-模式)\n- [啟用 Libreswan 日誌](docs/advanced-usage-zh.md#启用-libreswan-日志)\n- [查看伺服器狀態](docs/advanced-usage-zh.md#查看服务器状态)\n- [從原始碼建構](docs/advanced-usage-zh.md#从源代码构建)\n- [在容器中執行 Bash shell](docs/advanced-usage-zh.md#在容器中运行-bash-shell)\n- [綁定掛載 env 檔案](docs/advanced-usage-zh.md#绑定挂载-env-文件)\n- [部署 Google BBR 壅塞控制](docs/advanced-usage-zh.md#部署-google-bbr-拥塞控制)\n\n## 技術細節\n\n需要執行以下兩個服務：`Libreswan (pluto)` 提供 IPsec VPN，`xl2tpd` 提供 L2TP 支援。\n\n預設的 IPsec 設定支援以下協定：\n\n* IPsec/L2TP with PSK\n* IKEv1 with PSK and XAuth (\"Cisco IPsec\")\n* IKEv2\n\n為了讓 VPN 伺服器正常運作，將會開啟以下連接埠：\n\n* 4500/udp 和 500/udp 用於 IPsec\n\n## 授權條款\n\n**註：** 預先建構映像中的軟體元件（例如 Libreswan 和 xl2tpd）依其各自版權持有人所選擇的授權條款發布。對於任何預先建構映像的使用，使用者有責任確保其使用方式符合映像中所有軟體的相關授權條款。\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基於 [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-ru.md)\n\n# Docker 上的 IPsec VPN 服务器\n\n[![Build Status](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml/badge.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/)\n\n使用这个 Docker 镜像快速搭建 IPsec VPN 服务器。支持 IPsec/L2TP，Cisco IPsec 和 IKEv2 协议。\n\n本镜像以 Alpine 3.23 或 Debian 12 为基础，并使用 [Libreswan](https://libreswan.org) (IPsec VPN 软件) 和 [xl2tpd](https://github.com/xelerance/xl2tpd) (L2TP 服务进程)。\n\nIPsec VPN 可以加密你的网络流量，以防止在通过因特网传送时，你和 VPN 服务器之间的任何人对你的数据的未经授权的访问。在使用不安全的网络时，这是特别有用的，例如在咖啡厅，机场或旅馆房间。\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使用以下命令在 Docker 上快速搭建 IPsec VPN 服务器：\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\n你的 VPN 登录凭证将会被自动随机生成。请参见[获取 VPN 登录信息](#获取-vpn-登录信息)。\n\n另外，你也可以在不使用 Docker 的情况下[安装 IPsec VPN](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/README-zh.md)。要了解更多有关如何使用本镜像的信息，请继续阅读以下部分。\n\n## 功能特性\n\n- 支持具有强大和快速加密算法（例如 AES-GCM）的 IKEv2 模式\n- 生成 VPN 配置文件以自动配置 iOS, macOS 和 Android 设备\n- 支持 Windows, macOS, iOS, Android, Chrome OS 和 Linux 客户端\n- 包括辅助脚本以管理 IKEv2 用户和证书\n\n## 安装 Docker\n\n首先在你的 Linux 服务器上[安装 Docker](https://docs.docker.com/engine/install/)。另外你也可以使用 [Podman](https://podman.io) 运行本镜像，需要首先为 `docker` 命令[创建一个别名](https://podman.io/whatis.html)。\n\n高级用户可以在 macOS 上通过安装 [Docker for Mac](https://docs.docker.com/docker-for-mac/) 使用本镜像。在使用 IPsec/L2TP 模式之前，你可能需要运行 `docker restart ipsec-vpn-server` 重启一次 Docker 容器。本镜像不支持 Docker for Windows。\n\n## 下载\n\n预构建的可信任镜像可在 [Docker Hub registry](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) 下载：\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\n或者，你也可以从 [Quay.io](https://quay.io/repository/hwdsl2/ipsec-vpn-server) 下载：\n\n```\ndocker pull quay.io/hwdsl2/ipsec-vpn-server\ndocker image tag quay.io/hwdsl2/ipsec-vpn-server hwdsl2/ipsec-vpn-server\n```\n\n支持以下架构系统：`linux/amd64`, `linux/arm64` 和 `linux/arm/v7`。\n\n高级用户可以自己从 GitHub [编译源代码](docs/advanced-usage-zh.md#从源代码构建)。\n\n### 镜像对照表\n\n有两个预构建的镜像可用。默认的基于 Alpine 的镜像大小仅 ~19 MB。\n\n|                 | 基于 Alpine               | 基于 Debian                     |\n| --------------- | ------------------------ | ------------------------------ |\n| 镜像名称          | hwdsl2/ipsec-vpn-server  | hwdsl2/ipsec-vpn-server:debian |\n| 压缩后大小        | ~ 19 MB                  | ~ 62 MB                        |\n| 基础镜像          | Alpine Linux 3.23        | Debian Linux 12                |\n| 系统架构          | amd64, arm64, arm/v7     | amd64, arm64, arm/v7           |\n| Libreswan 版本   | 5.3                      | 5.3                            |\n| IPsec/L2TP      | ✅                       | ✅                              |\n| Cisco IPsec     | ✅                       | ✅                              |\n| IKEv2           | ✅                       | ✅                              |\n\n**注：** 要使用基于 Debian 的镜像，请将本自述文件中所有的 `hwdsl2/ipsec-vpn-server` 替换为 `hwdsl2/ipsec-vpn-server:debian`。这些镜像当前与 Synology NAS 系统不兼容。\n\n<details>\n<summary>\n我需要使用较旧版本的 Libreswan 版本 4。\n</summary>\n\n一般建议使用最新的 [Libreswan](https://libreswan.org/) 版本 5，它是本项目的默认版本。但是，如果你想要使用较旧版本的 Libreswan 版本 4，你可以从源代码构建 Docker 镜像：\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# Specify Libreswan version 4\nsed -i 's/SWAN_VER=5\\..*/SWAN_VER=4.15/' Dockerfile Dockerfile.debian\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server .\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n</details>\n\n## 如何使用本镜像\n\n### 环境变量\n\n**注：** 所有这些变量对于本镜像都是可选的，也就是说无需定义它们就可以搭建 IPsec VPN 服务器。你可以运行 `touch vpn.env` 创建一个空的 `env` 文件，然后跳到下一节。\n\n这个 Docker 镜像使用以下几个变量，可以在一个 `env` 文件中定义（参见[示例](vpn.env.example)）：\n\n```\nVPN_IPSEC_PSK=your_ipsec_pre_shared_key\nVPN_USER=your_vpn_username\nVPN_PASSWORD=your_vpn_password\n```\n\n这将创建一个用于 VPN 登录的用户账户，它可以在你的多个设备上使用[\\*](#重要提示)。 IPsec PSK (预共享密钥) 由 `VPN_IPSEC_PSK` 环境变量指定。 VPN 用户名和密码分别在 `VPN_USER` 和 `VPN_PASSWORD` 中定义。\n\n支持创建额外的 VPN 用户，如果需要，可以像下面这样在你的 `env` 文件中定义。用户名和密码必须分别使用空格进行分隔，并且用户名不能有重复。所有的 VPN 用户将共享同一个 IPsec PSK。\n\n```\nVPN_ADDL_USERS=additional_username_1 additional_username_2\nVPN_ADDL_PASSWORDS=additional_password_1 additional_password_2\n```\n\n以上变量仅适用于 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式。对于 IKEv2，参见[配置并使用 IKEv2 VPN](#配置并使用-ikev2-vpn)。\n\n**注：** 在你的 `env` 文件中，**不要**为变量值添加 `\"\"` 或者 `''`，或在 `=` 两边添加空格。**不要**在值中使用这些字符： `\\ \" '`。一个安全的 IPsec PSK 应该至少包含 20 个随机字符。\n\n**注：** 如果在创建 Docker 容器后修改 `env` 文件，则必须删除并重新创建容器才能使更改生效。参见[更新 Docker 镜像](#更新-docker-镜像)。\n\n### 其他环境变量\n\n高级用户可以指定一个域名，客户端名称和/或另外的 DNS 服务器。这是可选的。\n\n<details>\n<summary>\n了解如何指定一个域名，客户端名称和/或另外的 DNS 服务器。\n</summary>\n\n高级用户可以指定一个域名作为 IKEv2 服务器地址。这是可选的。该域名必须是一个全称域名 (FQDN)。示例如下：\n\n```\nVPN_DNS_NAME=vpn.example.com\n```\n\n你可以指定第一个 IKEv2 客户端的名称。该名称不能包含空格或者除 `-` `_` 之外的任何特殊字符。如果未指定，则使用默认值 `vpnclient`。\n\n```\nVPN_CLIENT_NAME=your_client_name\n```\n\n在 VPN 已连接时，客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。你可以为所有的 VPN 模式指定另外的 DNS 服务器。示例如下：\n\n```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\n有关详细信息以及一些流行的公共 DNS 提供商的列表，参见[使用其他的 DNS 服务器](docs/advanced-usage-zh.md)。\n\n默认情况下，导入 IKEv2 客户端配置时不需要密码。你可以选择使用随机密码保护客户端配置文件。\n\n```\nVPN_PROTECT_CONFIG=yes\n```\n\n**注：** 如果在 Docker 容器中已经配置了 IKEv2，则以上变量对 IKEv2 模式无效。在这种情况下，你可以移除 IKEv2 并使用自定义选项重新配置它。参见[配置并使用 IKEv2 VPN](#配置并使用-ikev2-vpn)。\n</details>\n\n### 运行 IPsec VPN 服务器\n\n使用本镜像创建一个新的 Docker 容器（将 `./vpn.env` 替换为你自己的 `env` 文件）：\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\n在该命令中，我们使用 `docker run` 的 `-v` 选项来创建一个名为 `ikev2-vpn-data` 的新 [Docker 卷](https://docs.docker.com/storage/volumes/)，并且将它挂载到容器内的 `/etc/ipsec.d` 目录下。IKEv2 的相关数据（比如证书和密钥）在该卷中保存，之后当你需要重新创建 Docker 容器的时候，只需指定同一个卷。\n\n推荐在使用本镜像时启用 IKEv2。如果你不想启用 IKEv2 而仅使用 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式连接到 VPN，可以去掉上面 `docker run` 命令中的第一个 `-v` 选项。\n\n**注：** 高级用户也可以[不启用 privileged 模式运行](docs/advanced-usage-zh.md#不启用-privileged-模式运行)。\n\n### 获取 VPN 登录信息\n\n如果你在上述 `docker run` 命令中没有指定 `env` 文件，`VPN_USER` 会默认为 `vpnuser`，并且 `VPN_IPSEC_PSK` 和 `VPN_PASSWORD` 会被自动随机生成。要获取这些登录信息，可以查看容器的日志：\n\n```\ndocker logs ipsec-vpn-server\n```\n\n在命令输出中查找这些行：\n\n```\nConnect to your new VPN with these details:\n\nServer IP: 你的VPN服务器IP\nIPsec PSK: 你的IPsec预共享密钥\nUsername: 你的VPN用户名\nPassword: 你的VPN密码\n```\n\n在命令输出中也会包含 IKEv2 配置信息（如果已启用）。\n\n（可选步骤）备份自动生成的 VPN 登录信息（如果有）到当前目录：\n\n```\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpn-gen.env ./\n```\n\n## 下一步\n\n*其他语言版本: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [Русский](README-ru.md#следующие-шаги)。*\n\n配置你的计算机或其它设备使用 VPN。请参见：\n\n**[配置并使用 IKEv2 VPN（推荐）](#配置并使用-ikev2-vpn)**\n\n**[配置 IPsec/L2TP VPN 客户端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md)**\n\n**[配置 IPsec/XAuth (\"Cisco IPsec\") VPN 客户端](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/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 模式，在首次连接之前需要[修改注册表](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#windows-错误-809)，以解决 VPN 服务器或客户端与 NAT（比如家用路由器）的兼容问题。\n\n同一个 VPN 账户可以在你的多个设备上使用。但是由于 IPsec/L2TP 的局限性，如果需要连接在同一个 NAT（比如家用路由器）后面的多个设备，你必须使用 [IKEv2](#配置并使用-ikev2-vpn) 或者 [IPsec/XAuth](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth-zh.md) 模式。\n\n如需添加，修改或者删除 VPN 用户账户，首先更新你的 `env` 文件，然后你必须按照[下一节](#更新-docker-镜像)的说明来删除并重新创建 Docker 容器。高级用户可以[绑定挂载](docs/advanced-usage-zh.md#绑定挂载-env-文件) `env` 文件。\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#使用其他的-dns-服务器)。\n\n## 更新 Docker 镜像\n\n要更新 Docker 镜像和容器，首先[下载](#下载)最新版本：\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\n如果 Docker 镜像已经是最新的，你会看到提示：\n\n```\nStatus: Image is up to date for hwdsl2/ipsec-vpn-server:latest\n```\n\n否则将会下载最新版本。要更新你的 Docker 容器，首先在纸上记下你所有的 [VPN 登录信息](#获取-vpn-登录信息)。然后删除 Docker 容器： `docker rm -f ipsec-vpn-server`。最后按照[如何使用本镜像](#如何使用本镜像)的说明来重新创建它。\n\n## 配置并使用 IKEv2 VPN\n\nIKEv2 模式是比 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 更佳的连接模式，该模式无需 IPsec PSK, 用户名或密码。更多信息请看[这里](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md)。\n\n首先，查看容器的日志以获取 IKEv2 配置信息：\n\n```bash\ndocker logs ipsec-vpn-server\n```\n\n**注：** 如果你无法找到 IKEv2 配置信息，IKEv2 可能没有在容器中启用。尝试按照[更新 Docker 镜像](#更新-docker-镜像)一节的说明更新 Docker 镜像和容器。\n\n在 IKEv2 安装过程中会创建一个 IKEv2 客户端（默认名称为 `vpnclient`），并且导出它的配置到 **容器内** 的 `/etc/ipsec.d` 目录下。你可以将配置文件复制到 Docker 主机：\n\n```bash\n# 查看容器内的 /etc/ipsec.d 目录的文件\ndocker exec -it ipsec-vpn-server ls -l /etc/ipsec.d\n# 示例：将一个客户端配置文件从容器复制到 Docker 主机当前目录\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpnclient.p12 ./\n```\n\n**下一步：** [配置你的设备](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md)以使用 IKEv2 VPN。\n\n<details>\n<summary>\n了解如何管理 IKEv2 客户端。\n</summary>\n\n你可以使用辅助脚本管理 IKEv2 客户端。示例如下。如需自定义客户端选项，可以在不添加参数的情况下运行脚本。\n\n```bash\n# 添加一个客户端（使用默认选项）\ndocker exec -it ipsec-vpn-server ikev2.sh --addclient [client name]\n# 导出一个已有的客户端的配置\ndocker exec -it ipsec-vpn-server ikev2.sh --exportclient [client name]\n# 列出已有的客户端\ndocker exec -it ipsec-vpn-server ikev2.sh --listclients\n# 显示使用信息\ndocker exec -it ipsec-vpn-server ikev2.sh -h\n```\n\n**注：** 如果你遇到错误 \"executable file not found\"，将上面的 `ikev2.sh` 换成 `/opt/src/ikev2.sh`。\n</details>\n<details>\n<summary>\n了解如何更改 IKEv2 服务器地址。\n</summary>\n\n在某些情况下，你可能需要更改 IKEv2 服务器地址。例如切换为使用域名，或者在服务器的 IP 更改之后。要更改 IKEv2 服务器地址，首先[在容器中运行 Bash shell](docs/advanced-usage-zh.md#在容器中运行-bash-shell)，然后[按照这里的说明操作](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto-zh.md#更改-ikev2-服务器地址)。请注意，容器的日志在你重启 Docker 容器之前将不显示新的 IKEv2 服务器地址。\n</details>\n<details>\n<summary>\n移除 IKEv2 并使用自定义选项重新配置。\n</summary>\n\n在某些情况下，你可能需要移除 IKEv2 并使用自定义选项重新配置它。\n\n**警告：** 这将**永久删除**所有的 IKEv2 配置（包括证书和密钥），并且**不可撤销**！\n\n**选项 1:** 使用辅助脚本移除 IKEv2 并重新配置。\n\n请注意，这将覆盖你在 `env` 文件中指定的变量，例如 `VPN_DNS_NAME` 和 `VPN_CLIENT_NAME`，并且容器的日志将不再显示 IKEv2 的最新信息。\n\n```bash\n# 移除 IKEv2 并删除所有的 IKEv2 配置\ndocker exec -it ipsec-vpn-server ikev2.sh --removeikev2\n# 使用自定义选项重新配置 IKEv2\ndocker exec -it ipsec-vpn-server ikev2.sh\n```\n\n**选项 2:** 移除 `ikev2-vpn-data` 并重新创建容器。\n\n1. 在纸上记下你所有的 [VPN 登录信息](#获取-vpn-登录信息)。\n1. 删除 Docker 容器：`docker rm -f ipsec-vpn-server`。\n1. 删除 `ikev2-vpn-data` 卷：`docker volume rm ikev2-vpn-data`。\n1. 更新你的 `env` 文件并添加自定义 IKEv2 选项，例如 `VPN_DNS_NAME` 和 `VPN_CLIENT_NAME`，然后重新创建容器。参见[如何使用本镜像](#如何使用本镜像)。\n</details>\n\n## 高级用法\n\n请参见[高级用法](docs/advanced-usage-zh.md)。\n\n- [使用其他的 DNS 服务器](docs/advanced-usage-zh.md#使用其他的-dns-服务器)\n- [不启用 privileged 模式运行](docs/advanced-usage-zh.md#不启用-privileged-模式运行)\n- [选择 VPN 模式](docs/advanced-usage-zh.md#选择-vpn-模式)\n- [访问 Docker 主机上的其它容器](docs/advanced-usage-zh.md#访问-docker-主机上的其它容器)\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- [关于 host network 模式](docs/advanced-usage-zh.md#关于-host-network-模式)\n- [启用 Libreswan 日志](docs/advanced-usage-zh.md#启用-libreswan-日志)\n- [查看服务器状态](docs/advanced-usage-zh.md#查看服务器状态)\n- [从源代码构建](docs/advanced-usage-zh.md#从源代码构建)\n- [在容器中运行 Bash shell](docs/advanced-usage-zh.md#在容器中运行-bash-shell)\n- [绑定挂载 env 文件](docs/advanced-usage-zh.md#绑定挂载-env-文件)\n- [部署 Google BBR 拥塞控制](docs/advanced-usage-zh.md#部署-google-bbr-拥塞控制)\n\n## 技术细节\n\n需要运行以下两个服务：`Libreswan (pluto)` 提供 IPsec VPN，`xl2tpd` 提供 L2TP 支持。\n\n默认的 IPsec 配置支持以下协议：\n\n* IPsec/L2TP with PSK\n* IKEv1 with PSK and XAuth (\"Cisco IPsec\")\n* IKEv2\n\n为使 VPN 服务器正常工作，将会打开以下端口：\n\n* 4500/udp and 500/udp for IPsec\n\n## 授权协议\n\n**注：** 预构建镜像中的软件组件（例如 Libreswan 和 xl2tpd）在其各自版权所有者选择的相应许可下。对于任何预构建的镜像的使用，用户有责任确保对该镜像的任何使用符合其中包含的所有软件的任何相关许可。\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基于 [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-ru.md)\n\n# IPsec VPN Server on Docker\n\n[![Build Status](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml/badge.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/actions/workflows/main-alpine.yml) [![GitHub Stars](docs/images/badges/github-stars.svg)](https://github.com/hwdsl2/docker-ipsec-vpn-server/stargazers) [![Docker Stars](docs/images/badges/docker-stars.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/) [![Docker Pulls](docs/images/badges/docker-pulls.svg)](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/)\n\nDocker image to run an IPsec VPN server, with IPsec/L2TP, Cisco IPsec and IKEv2.\n\nBased on Alpine 3.23 or Debian 12 with [Libreswan](https://libreswan.org) (IPsec VPN software) and [xl2tpd](https://github.com/xelerance/xl2tpd) (L2TP daemon).\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\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\nUse this command to set up an IPsec VPN server on Docker:\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\nYour VPN login details will be randomly generated. See [Retrieve VPN login details](#retrieve-vpn-login-details).\n\nAlternatively, you may [set up IPsec VPN without Docker](https://github.com/hwdsl2/setup-ipsec-vpn). To learn more about how to use this image, read the sections below.\n\n## Features\n\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 a helper script to manage IKEv2 users and certificates\n\n## Install Docker\n\nFirst, [install Docker](https://docs.docker.com/engine/install/) on your Linux server. You may also use [Podman](https://podman.io) to run this image, after [creating an alias](https://podman.io/whatis.html) for `docker`.\n\nAdvanced users can use this image on macOS with [Docker for Mac](https://docs.docker.com/docker-for-mac/). Before using IPsec/L2TP mode, you may need to restart the Docker container once with `docker restart ipsec-vpn-server`. This image does not support Docker for Windows.\n\n## Download\n\nGet the trusted build from the [Docker Hub registry](https://hub.docker.com/r/hwdsl2/ipsec-vpn-server/):\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\nAlternatively, you may download from [Quay.io](https://quay.io/repository/hwdsl2/ipsec-vpn-server):\n\n```\ndocker pull quay.io/hwdsl2/ipsec-vpn-server\ndocker image tag quay.io/hwdsl2/ipsec-vpn-server hwdsl2/ipsec-vpn-server\n```\n\nSupported platforms: `linux/amd64`, `linux/arm64` and `linux/arm/v7`.\n\nAdvanced users can [build from source code](docs/advanced-usage.md#build-from-source-code) on GitHub.\n\n### Image comparison\n\nTwo pre-built images are available. The default Alpine-based image is only ~19 MB.\n\n|                   | Alpine-based             | Debian-based                   |\n| ----------------- | ------------------------ | ------------------------------ |\n| Image name        | hwdsl2/ipsec-vpn-server  | hwdsl2/ipsec-vpn-server:debian |\n| Compressed size   | ~ 19 MB                  | ~ 62 MB                        |\n| Base image        | Alpine Linux 3.23        | Debian Linux 12                |\n| Platforms         | amd64, arm64, arm/v7     | amd64, arm64, arm/v7           |\n| Libreswan version | 5.3                      | 5.3                            |\n| IPsec/L2TP        | ✅                       | ✅                              |\n| Cisco IPsec       | ✅                       | ✅                              |\n| IKEv2             | ✅                       | ✅                              |\n\n**Note:** To use the Debian-based image, replace every `hwdsl2/ipsec-vpn-server` with `hwdsl2/ipsec-vpn-server:debian` in this README. These images are not currently compatible with Synology NAS systems.\n\n<details>\n<summary>\nI want to use 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 use the older Libreswan version 4, you can build the Docker image from source code:\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# Specify Libreswan version 4\nsed -i 's/SWAN_VER=5\\..*/SWAN_VER=4.15/' Dockerfile Dockerfile.debian\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server .\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n</details>\n\n## How to use this image\n\n### Environment variables\n\n**Note:** All the variables to this image are optional, which means you don't have to type in any variable, and you can have an IPsec VPN server out of the box! To do that, create an empty `env` file using `touch vpn.env`, and skip to the next section.\n\nThis Docker image uses the following variables, that can be declared in an `env` file (see [example](vpn.env.example)):\n\n```\nVPN_IPSEC_PSK=your_ipsec_pre_shared_key\nVPN_USER=your_vpn_username\nVPN_PASSWORD=your_vpn_password\n```\n\nThis will create a user account for VPN login, which can be used by your multiple devices[\\*](#important-notes). The IPsec PSK (pre-shared key) is specified by the `VPN_IPSEC_PSK` environment variable. The VPN username is defined in `VPN_USER`, and VPN password is specified by `VPN_PASSWORD`.\n\nAdditional VPN users are supported, and can be optionally declared in your `env` file like this. Usernames and passwords must be separated by spaces, and usernames cannot contain duplicates. All VPN users will share the same IPsec PSK.\n\n```\nVPN_ADDL_USERS=additional_username_1 additional_username_2\nVPN_ADDL_PASSWORDS=additional_password_1 additional_password_2\n```\n\nThe variables above are only for IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes. For IKEv2, see [Configure and use IKEv2 VPN](#configure-and-use-ikev2-vpn).\n\n**Note:** In your `env` file, DO NOT put `\"\"` or `''` around values, or add space around `=`. DO NOT use these special characters within values: `\\ \" '`. A secure IPsec PSK should consist of at least 20 random characters.\n\n**Note:** If you modify the `env` file after the Docker container is already created, you must remove and re-create the container for the changes to take effect. Refer to [Update Docker image](#update-docker-image).\n\n### Additional environment variables\n\nAdvanced users can optionally specify a DNS name, client name and/or custom DNS servers.\n\n<details>\n<summary>\nLearn how to specify a DNS name, client name and/or custom DNS servers.\n</summary>\n\nAdvanced 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```\nVPN_DNS_NAME=vpn.example.com\n```\n\nYou may specify a name for the first IKEv2 client. Use one word only, no special characters except `-` and `_`. The default is `vpnclient` if not specified.\n\n```\nVPN_CLIENT_NAME=your_client_name\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```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\nFor more details and a list of some popular public DNS providers, see [Use alternative DNS servers](docs/advanced-usage.md).\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```\nVPN_PROTECT_CONFIG=yes\n```\n\n**Note:** The variables above have no effect for IKEv2 mode, if IKEv2 is already set up in the Docker container. In this case, you may remove IKEv2 and set it up again using custom options. Refer to [Configure and use IKEv2 VPN](#configure-and-use-ikev2-vpn).\n</details>\n\n### Start the IPsec VPN server\n\nCreate a new Docker container from this image (replace `./vpn.env` with your own `env` file):\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\nIn this command, we use the `-v` option of `docker run` to create a new [Docker volume](https://docs.docker.com/storage/volumes/) named `ikev2-vpn-data`, and mount it into `/etc/ipsec.d` in the container. IKEv2 related data such as certificates and keys will persist in the volume, and later when you need to re-create the Docker container, just specify the same volume again.\n\nIt is recommended to enable IKEv2 when using this image. However, if you prefer not to enable IKEv2 and use only the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes to connect to the VPN, remove the first `-v` option from the `docker run` command above.\n\n**Note:** Advanced users can also [run without privileged mode](docs/advanced-usage.md#run-without-privileged-mode).\n\n### Retrieve VPN login details\n\nIf you did not specify an `env` file in the `docker run` command above, `VPN_USER` will default to `vpnuser` and both `VPN_IPSEC_PSK` and `VPN_PASSWORD` will be randomly generated. To retrieve them, view the container logs:\n\n```\ndocker logs ipsec-vpn-server\n```\n\nSearch for these lines in the output:\n\n```\nConnect to your new VPN with these details:\n\nServer IP: your_vpn_server_ip\nIPsec PSK: your_ipsec_pre_shared_key\nUsername: your_vpn_username\nPassword: your_vpn_password\n```\n\nThe output will also include details for IKEv2 mode, if enabled.\n\n(Optional) Backup the generated VPN login details (if any) to the current directory:\n\n```\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpn-gen.env ./\n```\n\n## Next steps\n\n*Read this in other languages: [English](README.md#next-steps), [简体中文](README-zh.md#下一步), [繁體中文](README-zh-Hant.md#下一步), [Русский](README-ru.md#следующие-шаги).*\n\nGet your computer or device to use the VPN. Please refer to:\n\n**[Configure and use IKEv2 VPN (recommended)](#configure-and-use-ikev2-vpn)**\n\n**[Configure IPsec/L2TP VPN Clients](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md)**\n\n**[Configure IPsec/XAuth (\"Cisco IPsec\") VPN Clients](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/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](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/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](#configure-and-use-ikev2-vpn) or [IPsec/XAuth](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth.md) mode.\n\nIf you wish to add, edit or remove VPN user accounts, first update your `env` file, then you must remove and re-create the Docker container using instructions from the [next section](#update-docker-image). Advanced users can [bind mount](docs/advanced-usage.md#bind-mount-the-env-file) the `env` file.\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, read [this section](docs/advanced-usage.md#use-alternative-dns-servers).\n\n## Update Docker image\n\nTo update the Docker image and container, first [download](#download) the latest version:\n\n```\ndocker pull hwdsl2/ipsec-vpn-server\n```\n\nIf the Docker image is already up to date, you should see:\n\n```\nStatus: Image is up to date for hwdsl2/ipsec-vpn-server:latest\n```\n\nOtherwise, it will download the latest version. To update your Docker container, first write down all your [VPN login details](#retrieve-vpn-login-details). Then remove the Docker container with `docker rm -f ipsec-vpn-server`. Finally, re-create it using instructions from [How to use this image](#how-to-use-this-image).\n\n## Configure and use IKEv2 VPN\n\nIKEv2 mode has improvements over IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\"), and does not require an IPsec PSK, username or password. Read more [here](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md).\n\nFirst, check container logs to view details for IKEv2:\n\n```bash\ndocker logs ipsec-vpn-server\n```\n\n**Note:** If you cannot find IKEv2 details, IKEv2 may not be enabled in the container. Try updating the Docker image and container using instructions from the [Update Docker image](#update-docker-image) section.\n\nDuring IKEv2 setup, an IKEv2 client (with default name `vpnclient`) is created, with its configuration exported to `/etc/ipsec.d` **inside the container**. To copy config file(s) to the Docker host:\n\n```bash\n# Check contents of /etc/ipsec.d in the container\ndocker exec -it ipsec-vpn-server ls -l /etc/ipsec.d\n# Example: Copy a client config file from the container\n# to the current directory on the Docker host\ndocker cp ipsec-vpn-server:/etc/ipsec.d/vpnclient.p12 ./\n```\n\n**Next steps:** [Configure your devices](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md) to use the IKEv2 VPN.\n\n<details>\n<summary>\nLearn how to manage IKEv2 clients.\n</summary>\n\nYou can manage IKEv2 clients using the helper script. See examples below. To customize client options, run the script without arguments.\n\n```bash\n# Add a new client (using default options)\ndocker exec -it ipsec-vpn-server ikev2.sh --addclient [client name]\n# Export configuration for an existing client\ndocker exec -it ipsec-vpn-server ikev2.sh --exportclient [client name]\n# List existing clients\ndocker exec -it ipsec-vpn-server ikev2.sh --listclients\n# Show usage\ndocker exec -it ipsec-vpn-server ikev2.sh -h\n```\n\n**Note:** If you encounter error \"executable file not found\", replace `ikev2.sh` above with `/opt/src/ikev2.sh`.\n</details>\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. To change the IKEv2 server address, first [open a bash shell inside the container](docs/advanced-usage.md#bash-shell-inside-container), then [follow these instructions](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/ikev2-howto.md#change-ikev2-server-address). Note that the container logs will not show the new IKEv2 server address until you restart the Docker container.\n</details>\n<details>\n<summary>\nRemove IKEv2 and set it up again using custom options.\n</summary>\n\nIn certain circumstances, you may need to remove IKEv2 and set it up again using custom options.\n\n**Warning:** All IKEv2 configuration including certificates and keys will be **permanently deleted**. This **cannot be undone**!\n\n**Option 1:** Remove IKEv2 and set it up again using the helper script.\n\nNote that this will override variables you specified in the `env` file, such as `VPN_DNS_NAME` and `VPN_CLIENT_NAME`, and the container logs will no longer show up-to-date information for IKEv2.\n\n```bash\n# Remove IKEv2 and delete all IKEv2 configuration\ndocker exec -it ipsec-vpn-server ikev2.sh --removeikev2\n# Set up IKEv2 again using custom options\ndocker exec -it ipsec-vpn-server ikev2.sh\n```\n\n**Option 2:** Remove `ikev2-vpn-data` and re-create the container.\n\n1. Write down all your [VPN login details](#retrieve-vpn-login-details).\n1. Remove the Docker container: `docker rm -f ipsec-vpn-server`.\n1. Remove the `ikev2-vpn-data` volume: `docker volume rm ikev2-vpn-data`.\n1. Update your `env` file and add custom IKEv2 options such as `VPN_DNS_NAME` and `VPN_CLIENT_NAME`, then re-create the container. Refer to [How to use this image](#how-to-use-this-image).\n</details>\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- [Run without privileged mode](docs/advanced-usage.md#run-without-privileged-mode)\n- [Select VPN modes](docs/advanced-usage.md#select-vpn-modes)\n- [Access other containers on the Docker host](docs/advanced-usage.md#access-other-containers-on-the-docker-host)\n- [Specify VPN server's public IP](docs/advanced-usage.md#specify-vpn-servers-public-ip)\n- [Assign static IPs to VPN clients](docs/advanced-usage.md#assign-static-ips-to-vpn-clients)\n- [Customize VPN subnets](docs/advanced-usage.md#customize-vpn-subnets)\n- [IPv6 support](docs/advanced-usage.md#ipv6-support)\n- [Split tunneling](docs/advanced-usage.md#split-tunneling)\n- [About host network mode](docs/advanced-usage.md#about-host-network-mode)\n- [Enable Libreswan logs](docs/advanced-usage.md#enable-libreswan-logs)\n- [Check server status](docs/advanced-usage.md#check-server-status)\n- [Build from source code](docs/advanced-usage.md#build-from-source-code)\n- [Bash shell inside container](docs/advanced-usage.md#bash-shell-inside-container)\n- [Bind mount the env file](docs/advanced-usage.md#bind-mount-the-env-file)\n- [Deploy Google BBR congestion control](docs/advanced-usage.md#deploy-google-bbr-congestion-control)\n\n## Technical details\n\nThere are two services running: `Libreswan (pluto)` for the IPsec VPN, and `xl2tpd` for L2TP support.\n\nThe default IPsec configuration supports:\n\n* IPsec/L2TP with PSK\n* IKEv1 with PSK and XAuth (\"Cisco IPsec\")\n* IKEv2\n\nThe ports that are exposed for this container to work are:\n\n* 4500/udp and 500/udp for IPsec\n\n## License\n\n**Note:** The software components inside the pre-built image (such as Libreswan and xl2tpd) are under the respective licenses chosen by their respective copyright holders. As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within.\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)   \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": "docker-compose.yml",
    "content": "version: '3'\n\nvolumes:\n  ikev2-vpn-data:\n\nservices:\n  vpn:\n    image: hwdsl2/ipsec-vpn-server\n    restart: always\n    env_file:\n      - ./vpn.env\n    ports:\n      - \"500:500/udp\"\n      - \"4500:4500/udp\"\n    privileged: true\n    hostname: ipsec-vpn-server\n    container_name: ipsec-vpn-server\n    volumes:\n      - ikev2-vpn-data:/etc/ipsec.d\n      - /lib/modules:/lib/modules:ro\n    # To enable IPv6 support for IKEv2 clients, the Docker host must have a\n    # public IPv6 address. Uncomment the network section below and configure\n    # IPv6 in your Docker daemon (set \"ipv6\": true and \"fixed-cidr-v6\" in\n    # /etc/docker/daemon.json), then re-create this container.\n    # networks:\n    #   vpnnet:\n    #     ipv6_address: <assign_a_ula_ipv6_address>\n\n# networks:\n#   vpnnet:\n#     enable_ipv6: true\n#     ipam:\n#       config:\n#         - subnet: fddd:1::/64\n"
  },
  {
    "path": "docs/advanced-usage-zh.md",
    "content": "[English](advanced-usage.md) | [中文](advanced-usage-zh.md)\n\n# 高级用法\n\n- [使用其他的 DNS 服务器](#使用其他的-dns-服务器)\n- [不启用 privileged 模式运行](#不启用-privileged-模式运行)\n- [选择 VPN 模式](#选择-vpn-模式)\n- [访问 Docker 主机上的其它容器](#访问-docker-主机上的其它容器)\n- [指定 VPN 服务器的公有 IP](#指定-vpn-服务器的公有-ip)\n- [为 VPN 客户端指定静态 IP](#为-vpn-客户端指定静态-ip)\n- [自定义 VPN 子网](#自定义-vpn-子网)\n- [IPv6 支持](#ipv6-支持)\n- [VPN 分流](#vpn-分流)\n- [关于 host network 模式](#关于-host-network-模式)\n- [启用 Libreswan 日志](#启用-libreswan-日志)\n- [查看服务器状态](#查看服务器状态)\n- [从源代码构建](#从源代码构建)\n- [在容器中运行 Bash shell](#在容器中运行-bash-shell)\n- [绑定挂载 env 文件](#绑定挂载-env-文件)\n- [部署 Google BBR 拥塞控制](#部署-google-bbr-拥塞控制)\n\n## 使用其他的 DNS 服务器\n\n在 VPN 已连接时，客户端默认配置为使用 [Google Public DNS](https://developers.google.com/speed/public-dns/)。如果偏好其它的域名解析服务，你可以在 `env` 文件中定义 `VPN_DNS_SRV1` 和 `VPN_DNS_SRV2`（可选），然后按照[说明](../README-zh.md#更新-docker-镜像)重新创建 Docker 容器。示例如下：\n\n```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\n使用 `VPN_DNS_SRV1` 指定主 DNS 服务器，使用 `VPN_DNS_SRV2` 指定辅助 DNS 服务器（可选）。\n\n请注意，如果 Docker 容器中已经配置了 IKEv2，你还需要编辑 Docker 容器内的 `/etc/ipsec.d/ikev2.conf` 并将 `8.8.8.8` 和 `8.8.4.4` 替换为你的其他的 DNS 服务器，然后重新启动 Docker 容器。\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## 不启用 privileged 模式运行\n\n高级用户可以在不启用 [privileged 模式](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)的情况下使用本镜像创建一个 Docker 容器（将以下命令中的 `./vpn.env` 替换为你自己的 `env` 文件）。\n\n**注：** 如果要启用 [IPv6 支持](#ipv6-支持)，你必须在下方的 `docker run` 命令中添加 `--sysctl net.ipv6.conf.all.forwarding=1`。\n\n**注：** 如果你的 Docker 主机运行 CentOS Stream, Oracle Linux 8+, Rocky Linux 或者 AlmaLinux，推荐使用 [privileged 模式](../README-zh.md#运行-ipsec-vpn-服务器)。如果你想要不启用 privileged 模式运行，则 **必须** 在创建 Docker 容器之前以及系统启动时运行 `modprobe ip_tables`。\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --cap-add=NET_ADMIN \\\n    --device=/dev/ppp \\\n    --sysctl net.ipv4.ip_forward=1 \\\n    --sysctl net.ipv4.conf.all.accept_redirects=0 \\\n    --sysctl net.ipv4.conf.all.send_redirects=0 \\\n    --sysctl net.ipv4.conf.all.rp_filter=0 \\\n    --sysctl net.ipv4.conf.default.accept_redirects=0 \\\n    --sysctl net.ipv4.conf.default.send_redirects=0 \\\n    --sysctl net.ipv4.conf.default.rp_filter=0 \\\n    hwdsl2/ipsec-vpn-server\n```\n\n在不启用 privileged 模式运行时，容器不能更改 `sysctl` 设置。这可能会影响本镜像的某些功能。一个已知问题是 [Android/Linux MTU/MSS fix](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-zh.md#androidlinux-mtumss-问题) 需要另外在 `docker run` 命令添加 `--sysctl net.ipv4.ip_no_pmtu_disc=1` 才有效。如果你遇到任何问题，可以尝试换用 [privileged 模式](../README-zh.md#运行-ipsec-vpn-服务器)重新创建容器。\n\n在创建 Docker 容器之后，请转到[获取 VPN 登录信息](../README-zh.md#获取-vpn-登录信息)。\n\n类似地，如果你使用 [Docker compose](https://docs.docker.com/compose/)，可以将 [docker-compose.yml](../docker-compose.yml) 中的 `privileged: true` 替换为：\n\n```\n  cap_add:\n    - NET_ADMIN\n  devices:\n    - \"/dev/ppp:/dev/ppp\"\n  sysctls:\n    - net.ipv4.ip_forward=1\n    - net.ipv4.conf.all.accept_redirects=0\n    - net.ipv4.conf.all.send_redirects=0\n    - net.ipv4.conf.all.rp_filter=0\n    - net.ipv4.conf.default.accept_redirects=0\n    - net.ipv4.conf.default.send_redirects=0\n    - net.ipv4.conf.default.rp_filter=0\n```\n\n更多信息请参见 [compose file reference](https://docs.docker.com/compose/compose-file/)。\n\n## 选择 VPN 模式\n\n在使用此 Docker 镜像时，默认启用 IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式。此外，如果在创建 Docker 容器时在 `docker run` 命令中[指定](../README-zh.md#运行-ipsec-vpn-服务器)了 `-v ikev2-vpn-data:/etc/ipsec.d` 选项，则会启用 IKEv2 模式。\n\n高级用户可以有选择性地禁用 VPN 模式，通过在 `env` 文件中设置以下变量并重新创建 Docker 容器来实现。\n\n禁用 IPsec/L2TP 模式：`VPN_DISABLE_IPSEC_L2TP=yes`   \n禁用 IPsec/XAuth (\"Cisco IPsec\") 模式：`VPN_DISABLE_IPSEC_XAUTH=yes`   \n禁用 IPsec/L2TP 和 IPsec/XAuth 模式：`VPN_IKEV2_ONLY=yes`\n\n## 访问 Docker 主机上的其它容器\n\n连接到 VPN 后，VPN 客户端通常可以访问在同一 Docker 主机上其他容器中运行的服务，而无需进行其他配置。\n\n例如，如果 IPsec VPN 服务器容器的 IP 为 `172.17.0.2`，并且一个 IP 为 `172.17.0.3` 的 Nginx 容器在同一 Docker 主机上运行，则 VPN 客户端可以使用 IP `172.17.0.3` 来访问 Nginx 容器上的服务。要找出分配给容器的 IP ，可以运行 `docker inspect <container name>`。\n\n## 指定 VPN 服务器的公有 IP\n\n在具有多个公有 IP 地址的 Docker 主机上，高级用户可以使用 `env` 文件中的变量 `VPN_PUBLIC_IP` 为 VPN 服务器指定一个公有 IP，然后重新创建 Docker 容器。例如，如果 Docker 主机的 IP 为 `192.0.2.1` 和 `192.0.2.2`，并且你想要 VPN 服务器使用 `192.0.2.2`：\n\n```\nVPN_PUBLIC_IP=192.0.2.2\n```\n\n请注意，如果在 Docker 容器中已经配置了 IKEv2，则此变量对 IKEv2 模式无效。在这种情况下，你可以移除 IKEv2 并使用自定义选项重新配置它。参见[配置并使用 IKEv2 VPN](../README-zh.md#配置并使用-ikev2-vpn)。\n\n如果你想要 VPN 客户端在 VPN 连接处于活动状态时使用指定的公有 IP 作为其 \"出站 IP\"，并且指定的 IP **不是** Docker 主机上的主 IP（或默认路由），则可能需要额外的配置。在这种情况下，你可以尝试在 Docker 主机上添加一个 IPTables `SNAT` 规则。如果要在重启后继续有效，你可以将命令添加到 `/etc/rc.local`。\n\n继续上面的例子，如果 Docker 容器具有内部 IP `172.17.0.2`（使用 `docker inspect ipsec-vpn-server` 查看），Docker 的网络接口名称为 `docker0`（使用 `iptables -nvL -t nat` 查看)，并且你希望 \"出站 IP\" 为 `192.0.2.2`：\n\n```\niptables -t nat -I POSTROUTING -s 172.17.0.2 ! -o docker0 -j SNAT --to 192.0.2.2\n```\n\n要检查一个已连接的 VPN 客户端的 \"出站 IP\"，你可以在该客户端上打开浏览器并到[这里](https://www.ipchicken.com)检测 IP 地址。\n\n## 为 VPN 客户端指定静态 IP\n\n在使用 IPsec/L2TP 模式连接时，VPN 服务器（Docker 容器）在虚拟网络 `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\") 或 IKEv2 模式连接时，VPN 服务器（Docker 容器）在虚拟网络 `192.168.43.0/24` 内 **没有** 内网 IP。为客户端分配的内网 IP 在这个范围内：`192.168.43.10` 到 `192.168.43.250`。\n\n高级用户可以将静态 IP 分配给 VPN 客户端。这是可选的。对于 **IKEv2 模式**，首先[在容器中运行 Bash shell](#在容器中运行-bash-shell)，然后按照[VPN 内网 IP 和流量](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/advanced-usage-zh.md#vpn-内网-ip-和流量)中的 \"IKEv2 模式：为 VPN 客户端分配静态 IP\" 小节中的步骤操作。请注意，你需要跳过第 2, 3 和 5 步，并且在完成后重启 Docker 容器。这是因为对 `/etc/ipsec.conf` 的修改可能会在重启容器时被覆盖。\n\n以下说明 **仅适用于** IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式。\n\n要分配静态 IP，在你的 `env` 文件中定义 `VPN_ADDL_IP_ADDRS` 变量，然后重新创建 Docker 容器。例如：\n\n```\nVPN_ADDL_USERS=user1 user2 user3 user4 user5\nVPN_ADDL_PASSWORDS=pass1 pass2 pass3 pass4 pass5\nVPN_ADDL_IP_ADDRS=* * 192.168.42.2 192.168.43.2\n```\n\n在此示例中，我们为 IPsec/L2TP 模式的 `user3` 分配静态 IP `192.168.42.2`，并为 IPsec/XAuth (\"Cisco IPsec\") 模式的 `user4` 分配静态 IP `192.168.43.2`。`user1`, `user2` 和 `user5` 的内网 IP 将被自动分配。`user3` 在 IPsec/XAuth 模式下的内网 IP 和 `user4` 在 IPsec/L2TP 模式下的内网 IP 也将被自动分配。你可以使用 `*` 来指定自动分配的 IP，或者将这些用户放在列表的末尾。\n\n你为 IPsec/L2TP 模式指定的静态 IP 必须在 `192.168.42.2` 到 `192.168.42.9` 范围内。你为 IPsec/XAuth (\"Cisco IPsec\") 模式指定的静态 IP 必须在 `192.168.43.2` 到 `192.168.43.9` 范围内。\n\n如果你需要分配更多静态 IP，则必须缩小自动分配的 IP 地址池。示例如下：\n\n```\nVPN_L2TP_POOL=192.168.42.100-192.168.42.250\nVPN_XAUTH_POOL=192.168.43.100-192.168.43.250\n```\n\n这将允许你为 IPsec/L2TP 模式在 `192.168.42.2` 到 `192.168.42.99` 范围内分配静态 IP，并且为 IPsec/XAuth (\"Cisco IPsec\") 模式在 `192.168.43.2` 到 `192.168.43.99` 范围内分配静态 IP。\n\n请注意，如果你在 `env` 文件中指定了 `VPN_XAUTH_POOL`，并且在 Docker 容器中已经配置了 IKEv2，你 **必须** 在重新创建 Docker 容器之前手动编辑容器内的 `/etc/ipsec.d/ikev2.conf` 并将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为与 `VPN_XAUTH_POOL` **相同的值**。否则 IKEv2 可能会停止工作。\n\n**注：** 在你的 `env` 文件中，**不要**为变量值添加 `\"\"` 或者 `''`，或在 `=` 两边添加空格。**不要**在值中使用这些字符： `\\ \" '`。\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`。有关更多详细信息，请阅读上一节。\n\n对于大多数用例，没有必要也 **不建议** 自定义这些子网。但是，如果你的用例需要它，你可以在 `env` 文件中指定自定义子网，然后你必须重新创建 Docker 容器。\n\n```\n# 示例：为 IPsec/L2TP 模式指定自定义 VPN 子网\n# 注：必须指定所有三个变量。\nVPN_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\n```\n\n```\n# 示例：为 IPsec/XAuth 和 IKEv2 模式指定自定义 VPN 子网\n# 注：必须指定以下两个变量。\nVPN_XAUTH_NET=10.2.0.0/16\nVPN_XAUTH_POOL=10.2.0.10-10.2.254.254\n```\n\n**注：** 在你的 `env` 文件中，**不要**为变量值添加 `\"\"` 或者 `''`，或在 `=` 两边添加空格。\n\n在上面的例子中，`VPN_L2TP_LOCAL` 是在 IPsec/L2TP 模式下的 VPN 服务器的内网 IP。`VPN_L2TP_POOL` 和 `VPN_XAUTH_POOL` 是为 VPN 客户端自动分配的 IP 地址池。\n\n请注意，如果你在 `env` 文件中指定了 `VPN_XAUTH_POOL`，并且在 Docker 容器中已经配置了 IKEv2，你 **必须** 在重新创建 Docker 容器之前手动编辑容器内的 `/etc/ipsec.d/ikev2.conf` 并将 `rightaddresspool=192.168.43.10-192.168.43.250` 替换为与 `VPN_XAUTH_POOL` **相同的值**。否则 IKEv2 可能会停止工作。\n\n## IPv6 支持\n\n如果 Docker 宿主机拥有公共（全局单播）IPv6 地址并且满足以下要求，IKEv2 客户端的 IPv6 支持将在容器启动时自动启用，无需手动配置。\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 流量通过宿主机的 IPv6 地址进行伪装（NAT），使 VPN 客户端通过隧道获得完整的 IPv6 互联网访问。\n\n**要求：**\n- Docker 宿主机必须拥有可路由的全局单播 IPv6 地址（以 `2` 或 `3` 开头）。链路本地地址 (`fe80::/10`) 不满足要求。\n- 必须为 Docker 容器启用 IPv6。参见[在 Docker 中启用 IPv6 支持](https://docs.docker.com/engine/daemon/ipv6/)。\n- Libreswan 5.0 或更新版本（Docker 镜像默认包含 5.x）。\n- IPv6 仅支持 **IKEv2 模式**。IPsec/L2TP 和 IPsec/XAuth (\"Cisco IPsec\") 模式不支持 IPv6。\n\n要为 Docker 容器启用 IPv6，首先在 Docker 宿主机上将以下内容添加到 `/etc/docker/daemon.json`，然后重启 Docker：\n\n```json\n{\n  \"ipv6\": true,\n  \"fixed-cidr-v6\": \"fddd:1::/64\"\n}\n```\n\n然后重新创建容器。`run.sh` 脚本将检测容器的公共 IPv6 地址并自动配置 IPv6 支持。\n\n要验证 IPv6 是否正常工作，请使用 IKEv2 连接到 VPN，然后检查你的 IPv6 地址，例如使用 [test-ipv6.com](https://test-ipv6.com)。\n\n**注：** 如果[不启用 privileged 模式运行](#不启用-privileged-模式运行) Docker 容器，你必须在 `docker run` 命令中添加 `--sysctl net.ipv6.conf.all.forwarding=1`。\n\n**现有容器注意事项：** 如果你的容器中已经配置了 IKEv2（即 `ikev2-vpn-data` 卷中已存在 `ikev2.conf`），在容器重启或重新创建时 IPv6 **不会**自动添加到现有的 IKEv2 配置中。要为 IKEv2 启用完整的 IPv6 支持，必须移除 IKEv2 并重新配置。参见[配置并使用 IKEv2 VPN](../README-zh.md#配置并使用-ikev2-vpn) 中的\"移除 IKEv2\"部分。\n\n你也可以在 `env` 文件中设置 `VPN_IP6_NET`，在重新创建容器之前自定义 IPv6 地址池子网：\n\n```\n# 示例：为 IKEv2 模式指定自定义 IPv6 地址池子网\n# 必须是 ULA 范围内的 /64 子网\nVPN_IP6_NET=fddd:1234:5678:9012::/64\n```\n\n## VPN 分流\n\n在启用 VPN 分流 (split tunneling) 时，VPN 客户端将仅通过 VPN 隧道发送特定目标子网的流量。其他流量 **不会** 通过 VPN 隧道。这允许你通过 VPN 安全访问指定的网络，而无需通过 VPN 发送所有客户端的流量。VPN 分流有一些局限性，而且并非所有的 VPN 客户端都支持。\n\n高级用户可以为 IKEv2 模式启用 VPN 分流。这是可选的。将变量 `VPN_SPLIT_IKEV2` 添加到你的 `env` 文件，然后重新创建 Docker 容器。例如，如果目标子网是 `10.123.123.0/24`：\n\n```\nVPN_SPLIT_IKEV2=10.123.123.0/24\n```\n\n请注意，如果在 Docker 容器中已经配置了 IKEv2，则此变量无效。在这种情况下，有两个选项：\n\n**选项 1：** 首先[在容器中运行 Bash shell](#在容器中运行-bash-shell)，然后编辑 `/etc/ipsec.d/ikev2.conf` 并将 `leftsubnet=0.0.0.0/0` 替换为你想要的子网。在完成后，退出容器并运行 `docker restart ipsec-vpn-server`。\n\n**选项 2：** 删除 Docker 容器以及 `ikev2-vpn-data` 卷，然后重新创建容器。这将**永久删除**所有的 VPN 配置。参见[配置并使用 IKEv2 VPN](../README-zh.md#配置并使用-ikev2-vpn) 中的\"移除 IKEv2\"部分。\n\n另外，Windows 用户也可以通过手动添加路由的方式启用 VPN 分流。有关详细信息，请参阅 [VPN 分流](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/advanced-usage-zh.md#vpn-分流)。\n\n## 关于 host network 模式\n\n高级用户可以使用 [host network 模式](https://docs.docker.com/network/host/)运行本镜像，通过为 `docker run` 命令添加 `--network=host` 参数来实现。\n\n在非必要的情况下，**不推荐**使用 host network 模式运行本镜像。在该模式下，容器的网络栈未与 Docker 主机隔离，从而在使用 IPsec/L2TP 模式连接之后，VPN 客户端可以使用 Docker 主机的 VPN 内网 IP `192.168.42.1` 访问主机上的端口或服务。请注意，当你不再使用本镜像时，你需要手动清理 [run.sh](../run.sh) 所更改的 IPTables 规则和 sysctl 设置，或者重启服务器。\n\n某些 Docker 主机操作系统，比如 Debian 10，不能使用 host network 模式运行本镜像，因为它们使用 nftables。\n\n## 启用 Libreswan 日志\n\n为了保持较小的 Docker 镜像，Libreswan (IPsec) 日志默认未开启。如果你需要启用它以进行故障排除，首先在正在运行的 Docker 容器中开始一个 Bash 会话：\n\n```\ndocker exec -it ipsec-vpn-server env TERM=xterm bash -l\n```\n\n然后运行以下命令：\n\n```\n# For Alpine-based image\napk add --no-cache rsyslog\nrsyslogd\nrc-service ipsec stop; rc-service -D ipsec start >/dev/null 2>&1\nsed -i '\\|pluto\\.pid|a rm -f /var/run/rsyslogd.pid; rsyslogd' /opt/src/run.sh\nexit\n# For Debian-based image\napt-get update && apt-get -y install rsyslog\nrsyslogd\nservice ipsec restart\nsed -i '\\|pluto\\.pid|a rm -f /var/run/rsyslogd.pid; rsyslogd' /opt/src/run.sh\nexit\n```\n\n**注：** 如果你在不启用 privileged 模式的情况下使用本镜像，则错误 `rsyslogd: imklog: cannot open kernel log` 是正常的。\n\n完成后你可以这样查看 Libreswan 日志：\n\n```\ndocker exec -it ipsec-vpn-server grep pluto /var/log/auth.log\n```\n\n如需查看 xl2tpd 日志，请运行 `docker logs ipsec-vpn-server`。\n\n## 查看服务器状态\n\n检查 IPsec VPN 服务器状态：\n\n```\ndocker exec -it ipsec-vpn-server ipsec status\n```\n\n查看当前已建立的 VPN 连接：\n\n```\ndocker exec -it ipsec-vpn-server ipsec trafficstatus\n```\n\n## 从源代码构建\n\n高级用户可以从 GitHub 下载并自行编译源代码：\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server .\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n\n若不需要改动源码，也可以这样：\n\n```\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server github.com/hwdsl2/docker-ipsec-vpn-server\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian \\\n  github.com/hwdsl2/docker-ipsec-vpn-server\n```\n\n## 在容器中运行 Bash shell\n\n在正在运行的 Docker 容器中开始一个 Bash 会话：\n\n```\ndocker exec -it ipsec-vpn-server env TERM=xterm bash -l\n```\n\n（可选步骤）安装 `nano` 编辑器：\n\n```\n# For Alpine-based image\napk add --no-cache nano\n# For Debian-based image\napt-get update && apt-get -y install nano\n```\n\n然后在容器中运行你的命令。完成后退出并重启 Docker 容器（如果需要）：\n\n```\nexit\ndocker restart ipsec-vpn-server\n```\n\n## 绑定挂载 env 文件\n\n作为 `--env-file` 选项的替代方案，高级用户可以绑定挂载 `env` 文件。该方法的好处是你在更新 `env` 文件之后可以重启 Docker 容器以生效，而不需要重新创建它。要使用这个方法，你必须首先编辑你的 `env` 文件并将所有的变量值用单引号 `''` 括起来。然后（重新）创建 Docker 容器（将第一个 `vpn.env` 替换为你自己的 `env` 文件）：\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v \"$(pwd)/vpn.env:/opt/src/env/vpn.env:ro\" \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\n\n## 部署 Google BBR 拥塞控制\n\nVPN 服务器搭建完成后，可以通过在 Docker 主机上部署 Google BBR 拥塞控制算法提升性能。\n\n这通常只需要在配置文件 `/etc/sysctl.conf` 中插入设定即可完成。但是部分 Linux 发行版可能需要额外更新 Linux 内核。\n\n详细的部署方法，可以参考[这篇文档](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/bbr-zh.md)。在完成后重启 Docker 容器：\n\n```\ndocker restart ipsec-vpn-server\n```\n\n## 授权协议\n\n**注：** 预构建镜像中的软件组件（例如 Libreswan 和 xl2tpd）在其各自版权所有者选择的相应许可下。对于任何预构建的镜像的使用，用户有责任确保对该镜像的任何使用符合其中包含的所有软件的任何相关许可。\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/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- [Run without privileged mode](#run-without-privileged-mode)\n- [Select VPN modes](#select-vpn-modes)\n- [Access other containers on the Docker host](#access-other-containers-on-the-docker-host)\n- [Specify VPN server's public IP](#specify-vpn-servers-public-ip)\n- [Assign static IPs to VPN clients](#assign-static-ips-to-vpn-clients)\n- [Customize VPN subnets](#customize-vpn-subnets)\n- [IPv6 support](#ipv6-support)\n- [Split tunneling](#split-tunneling)\n- [About host network mode](#about-host-network-mode)\n- [Enable Libreswan logs](#enable-libreswan-logs)\n- [Check server status](#check-server-status)\n- [Build from source code](#build-from-source-code)\n- [Bash shell inside container](#bash-shell-inside-container)\n- [Bind mount the env file](#bind-mount-the-env-file)\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, define `VPN_DNS_SRV1` and optionally `VPN_DNS_SRV2` in your `env` file, then follow [instructions](../README.md#update-docker-image) to re-create the Docker container. Example:\n\n```\nVPN_DNS_SRV1=1.1.1.1\nVPN_DNS_SRV2=1.0.0.1\n```\n\nUse `VPN_DNS_SRV1` to specify the primary DNS server, and `VPN_DNS_SRV2` to specify the secondary DNS server (optional).\n\nNote that if IKEv2 is already set up in the Docker container, you will also need to edit `/etc/ipsec.d/ikev2.conf` inside the Docker container and replace `8.8.8.8` and `8.8.4.4` with your alternative DNS server(s), then restart the Docker container.\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\n## Run without privileged mode\n\nAdvanced users can create a Docker container from this image without using [privileged mode](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities) (replace `./vpn.env` in the command below with your own `env` file).\n\n**Note:** For [IPv6 support](#ipv6-support) to work, you must add `--sysctl net.ipv6.conf.all.forwarding=1` to the `docker run` command below.\n\n**Note:** If your Docker host runs CentOS Stream, Oracle Linux 8+, Rocky Linux or AlmaLinux, it is recommended to use [privileged mode](../README.md#start-the-ipsec-vpn-server). If you want to run without privileged mode, you **must** run `modprobe ip_tables` before creating the Docker container and also on boot.\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --env-file ./vpn.env \\\n    --restart=always \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --cap-add=NET_ADMIN \\\n    --device=/dev/ppp \\\n    --sysctl net.ipv4.ip_forward=1 \\\n    --sysctl net.ipv4.conf.all.accept_redirects=0 \\\n    --sysctl net.ipv4.conf.all.send_redirects=0 \\\n    --sysctl net.ipv4.conf.all.rp_filter=0 \\\n    --sysctl net.ipv4.conf.default.accept_redirects=0 \\\n    --sysctl net.ipv4.conf.default.send_redirects=0 \\\n    --sysctl net.ipv4.conf.default.rp_filter=0 \\\n    hwdsl2/ipsec-vpn-server\n```\n\nWhen running without privileged mode, the container is unable to change `sysctl` settings. This could affect certain features of this image. A known issue is that the [Android/Linux MTU/MSS fix](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients.md#androidlinux-mtumss-issues) also requires adding `--sysctl net.ipv4.ip_no_pmtu_disc=1` to the `docker run` command. If you encounter any issues, try re-creating the container using [privileged mode](../README.md#start-the-ipsec-vpn-server).\n\nAfter creating the Docker container, see [Retrieve VPN login details](../README.md#retrieve-vpn-login-details).\n\nSimilarly, if using [Docker compose](https://docs.docker.com/compose/), you may replace `privileged: true` in [docker-compose.yml](../docker-compose.yml) with:\n\n```\n  cap_add:\n    - NET_ADMIN\n  devices:\n    - \"/dev/ppp:/dev/ppp\"\n  sysctls:\n    - net.ipv4.ip_forward=1\n    - net.ipv4.conf.all.accept_redirects=0\n    - net.ipv4.conf.all.send_redirects=0\n    - net.ipv4.conf.all.rp_filter=0\n    - net.ipv4.conf.default.accept_redirects=0\n    - net.ipv4.conf.default.send_redirects=0\n    - net.ipv4.conf.default.rp_filter=0\n```\n\nFor more information, see [compose file reference](https://docs.docker.com/compose/compose-file/).\n\n## Select VPN modes\n\nUsing this Docker image, the IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes are enabled by default. In addition, IKEv2 mode will be enabled if the `-v ikev2-vpn-data:/etc/ipsec.d` option [is specified](../README.md#start-the-ipsec-vpn-server) in the `docker run` command when creating the Docker container.\n\nAdvanced users can selectively disable VPN modes by setting the following variable(s) in the `env` file, then re-create the Docker container.\n\nDisable IPsec/L2TP mode: `VPN_DISABLE_IPSEC_L2TP=yes`   \nDisable IPsec/XAuth (\"Cisco IPsec\") mode: `VPN_DISABLE_IPSEC_XAUTH=yes`   \nDisable both IPsec/L2TP and IPsec/XAuth modes: `VPN_IKEV2_ONLY=yes`\n\n## Access other containers on the Docker host\n\nAfter connecting to the VPN, VPN clients can generally access services running in other containers on the same Docker host, without additional configuration.\n\nFor example, if the IPsec VPN server container has IP `172.17.0.2`, and an Nginx container with IP `172.17.0.3` is running on the same Docker host, VPN clients can use IP `172.17.0.3` to access services on the Nginx container. To find out which IP is assigned to a container, run `docker inspect <container name>`.\n\n## Specify VPN server's public IP\n\nOn Docker hosts with multiple public IP addresses, advanced users can specify a public IP for the VPN server using variable `VPN_PUBLIC_IP` in the `env` file, then re-create the Docker container. For example, if the Docker host 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```\nVPN_PUBLIC_IP=192.0.2.2\n```\n\nNote that this variable has no effect for IKEv2 mode, if IKEv2 is already set up in the Docker container. In this case, you may remove IKEv2 and set it up again using custom options. Refer to [Configure and use IKEv2 VPN](../README.md#configure-and-use-ikev2-vpn).\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 Docker host. In this case, you can try adding an IPTables `SNAT` rule on the Docker host. To persist after reboot, you may add the command to `/etc/rc.local`.\n\nContinuing with the example above, if the Docker container has internal IP `172.17.0.2` (check using `docker inspect ipsec-vpn-server`), Docker's network interface name is `docker0` (check using `iptables -nvL -t nat`), and you want the \"outgoing IP\" to be `192.0.2.2`:\n\n```\niptables -t nat -I POSTROUTING -s 172.17.0.2 ! -o docker0 -j SNAT --to 192.0.2.2\n```\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## Assign static IPs to VPN clients\n\nWhen connecting using IPsec/L2TP mode, the VPN server (Docker container) 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\") or IKEv2 mode, the VPN server (Docker container) 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\nAdvanced users may optionally assign static IPs to VPN clients. For **IKEv2 mode**, first open a [Bash shell inside the container](#bash-shell-inside-container), then follow the steps in section \"IKEv2 mode: Assign static IPs to VPN clients\" of [Internal VPN IPs and traffic](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/advanced-usage.md#internal-vpn-ips-and-traffic). Note that you should skip steps 2, 3 and 5, and restart the Docker container when finished. This is because changes to `/etc/ipsec.conf` may be overwritten on container restart.\n\nInstructions below **ONLY** apply to IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes.\n\nTo assign static IPs, declare the `VPN_ADDL_IP_ADDRS` variable in your `env` file, then re-create the Docker container. Example:\n\n```\nVPN_ADDL_USERS=user1 user2 user3 user4 user5\nVPN_ADDL_PASSWORDS=pass1 pass2 pass3 pass4 pass5\nVPN_ADDL_IP_ADDRS=* * 192.168.42.2 192.168.43.2\n```\n\nIn this example, we assign static IP `192.168.42.2` for `user3` for IPsec/L2TP mode, and assign static IP `192.168.43.2` for `user4` for IPsec/XAuth (\"Cisco IPsec\") mode. Internal IPs for `user1`, `user2` and `user5` will be auto-assigned. The internal IP for `user3` for IPsec/XAuth mode and the internal IP for `user4` for IPsec/L2TP mode will also be auto-assigned. You may use `*` to specify auto-assigned IPs, or put those user(s) at the end of the list.\n\nStatic IPs that you specify for IPsec/L2TP mode must be within the range from `192.168.42.2` to `192.168.42.9`. Static IPs that you specify for IPsec/XAuth (\"Cisco IPsec\") mode must be within the range from `192.168.43.2` to `192.168.43.9`.\n\nIf you need to assign more static IPs, you must shrink the pool of auto-assigned IP addresses. Example:\n\n```\nVPN_L2TP_POOL=192.168.42.100-192.168.42.250\nVPN_XAUTH_POOL=192.168.43.100-192.168.43.250\n```\n\nThis will allow you to assign static IPs within the range from `192.168.42.2` to `192.168.42.99` for IPsec/L2TP mode, and within the range from `192.168.43.2` to `192.168.43.99` for IPsec/XAuth (\"Cisco IPsec\") mode.\n\nNote that if you specify `VPN_XAUTH_POOL` in the `env` file, and IKEv2 is already set up in the Docker container, you **must** manually edit `/etc/ipsec.d/ikev2.conf` inside the container and replace `rightaddresspool=192.168.43.10-192.168.43.250` with the **same value** as `VPN_XAUTH_POOL`, before re-creating the Docker container. Otherwise, IKEv2 may stop working.\n\n**Note:** In your `env` file, DO NOT put `\"\"` or `''` around values, or add space around `=`. DO NOT use these special characters within values: `\\ \" '`.\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, read the previous section.\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) in your `env` file, then you must re-create the Docker container.\n\n```\n# Example: Specify custom VPN subnet for IPsec/L2TP mode\n# Note: All three variables must be specified.\nVPN_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\n```\n\n```\n# Example: Specify custom VPN subnet for IPsec/XAuth and IKEv2 modes\n# Note: Both variables must be specified.\nVPN_XAUTH_NET=10.2.0.0/16\nVPN_XAUTH_POOL=10.2.0.10-10.2.254.254\n```\n\n**Note:** In your `env` file, DO NOT put `\"\"` or `''` around values, or add space around `=`.\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\nNote that if you specify `VPN_XAUTH_POOL` in the `env` file, and IKEv2 is already set up in the Docker container, you **must** manually edit `/etc/ipsec.d/ikev2.conf` inside the container and replace `rightaddresspool=192.168.43.10-192.168.43.250` with the **same value** as `VPN_XAUTH_POOL`, before re-creating the Docker container. Otherwise, IKEv2 may stop working.\n\n## IPv6 support\n\nIf the Docker host has a public (global unicast) IPv6 address and the requirements below are met, IPv6 support for IKEv2 clients is automatically enabled when the container starts. No additional 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 container masquerades IPv6 traffic from VPN clients through the host's IPv6 address, giving clients full IPv6 internet access through the tunnel.\n\n**Requirements:**\n- The Docker host must have a routable global unicast IPv6 address (starting with `2` or `3`). Link-local (`fe80::/10`) addresses are not sufficient.\n- IPv6 must be enabled for the Docker container. See [Enable IPv6 support in Docker](https://docs.docker.com/engine/daemon/ipv6/).\n- Libreswan 5.0 or newer (the Docker image includes 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 enable IPv6 for the Docker container, first enable IPv6 in the Docker daemon by adding the following to `/etc/docker/daemon.json` on the Docker host, then restart Docker:\n\n```json\n{\n  \"ipv6\": true,\n  \"fixed-cidr-v6\": \"fddd:1::/64\"\n}\n```\n\nAfter that, re-create the Docker container. The `run.sh` script will detect the container's public IPv6 address and automatically configure IPv6 support.\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\n**Note:** If you run the Docker container [without privileged mode](#run-without-privileged-mode), you must add `--sysctl net.ipv6.conf.all.forwarding=1` to the `docker run` command.\n\n**Note for existing containers:** If IKEv2 is already set up in your container (i.e. `ikev2.conf` already exists in the `ikev2-vpn-data` volume), IPv6 will **not** be automatically added to the existing IKEv2 configuration when the container restarts or is recreated. To enable full IPv6 support for IKEv2, you must remove IKEv2 and set it up again. Refer to \"remove IKEv2\" in [Configure and use IKEv2 VPN](../README.md#configure-and-use-ikev2-vpn).\n\nYou may optionally customize the IPv6 pool subnet by setting `VPN_IP6_NET` in your `env` file before re-creating the container:\n\n```\n# Example: Specify custom IPv6 pool subnet for IKEv2 mode\n# Must be a /64 subnet in the ULA range\nVPN_IP6_NET=fddd:1234:5678:9012::/64\n```\n\n## Split tunneling\n\nWith split tunneling, VPN clients will only send traffic for a specific destination subnet 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 IKEv2 mode. Add the variable `VPN_SPLIT_IKEV2` to your `env` file, then re-create the Docker container. For example, if the destination subnet is `10.123.123.0/24`:\n\n```\nVPN_SPLIT_IKEV2=10.123.123.0/24\n```\n\nNote that this variable has no effect if IKEv2 is already set up in the Docker container. In this case, you have two options:\n\n**Option 1:** First start a [Bash shell inside the container](#bash-shell-inside-container), then edit `/etc/ipsec.d/ikev2.conf` and replace `leftsubnet=0.0.0.0/0` with your desired subnet. When finished, `exit` the container and run `docker restart ipsec-vpn-server`.\n\n**Option 2:** Remove both the Docker container and the `ikev2-vpn-data` volume, then re-create the Docker container. All VPN configuration will be **permanently deleted**. Refer to \"remove IKEv2\" in [Configure and use IKEv2 VPN](../README.md#configure-and-use-ikev2-vpn).\n\nAlternatively, Windows users can enable split tunneling by manually adding routes. For more details, see [Split tunneling](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/advanced-usage.md#split-tunneling).\n\n## About host network mode\n\nAdvanced users can run this image in [host network mode](https://docs.docker.com/network/host/), by adding `--network=host` to the `docker run` command.\n\nHost network mode is NOT recommended for this image, unless your use case requires it. In this mode, the container's network stack is not isolated from the Docker host, and VPN clients may be able to access ports or services on the Docker host using its internal VPN IP `192.168.42.1` after connecting using IPsec/L2TP mode. Note that you will need to manually clean up the changes to IPTables rules and sysctl settings by [run.sh](../run.sh) or reboot the server when you no longer use this image.\n\nSome Docker host OS, such as Debian 10, cannot run this image in host network mode due to the use of nftables.\n\n## Enable Libreswan logs\n\nTo keep the Docker image small, Libreswan (IPsec) logs are not enabled by default. If you need to enable it for troubleshooting purposes, first start a Bash session in the running container:\n\n```\ndocker exec -it ipsec-vpn-server env TERM=xterm bash -l\n```\n\nThen run the following commands:\n\n```\n# For Alpine-based image\napk add --no-cache rsyslog\nrsyslogd\nrc-service ipsec stop; rc-service -D ipsec start >/dev/null 2>&1\nsed -i '\\|pluto\\.pid|a rm -f /var/run/rsyslogd.pid; rsyslogd' /opt/src/run.sh\nexit\n# For Debian-based image\napt-get update && apt-get -y install rsyslog\nrsyslogd\nservice ipsec restart\nsed -i '\\|pluto\\.pid|a rm -f /var/run/rsyslogd.pid; rsyslogd' /opt/src/run.sh\nexit\n```\n\n**Note:** The error `rsyslogd: imklog: cannot open kernel log` is normal if you use this Docker image without privileged mode.\n\nWhen finished, you may check Libreswan logs with:\n\n```\ndocker exec -it ipsec-vpn-server grep pluto /var/log/auth.log\n```\n\nTo check xl2tpd logs, run `docker logs ipsec-vpn-server`.\n\n## Check server status\n\nCheck the status of the IPsec VPN server:\n\n```\ndocker exec -it ipsec-vpn-server ipsec status\n```\n\nShow currently established VPN connections:\n\n```\ndocker exec -it ipsec-vpn-server ipsec trafficstatus\n```\n\n## Build from source code\n\nAdvanced users can download and compile the source code from GitHub:\n\n```\ngit clone https://github.com/hwdsl2/docker-ipsec-vpn-server\ncd docker-ipsec-vpn-server\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server .\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian .\n```\n\nOr use this if not modifying the source code:\n\n```\n# To build Alpine-based image\ndocker build -t hwdsl2/ipsec-vpn-server github.com/hwdsl2/docker-ipsec-vpn-server\n# To build Debian-based image\ndocker build -f Dockerfile.debian -t hwdsl2/ipsec-vpn-server:debian \\\n  github.com/hwdsl2/docker-ipsec-vpn-server\n```\n\n## Bash shell inside container\n\nTo start a Bash session in the running container:\n\n```\ndocker exec -it ipsec-vpn-server env TERM=xterm bash -l\n```\n\n(Optional) Install the `nano` editor:\n\n```\n# For Alpine-based image\napk add --no-cache nano\n# For Debian-based image\napt-get update && apt-get -y install nano\n```\n\nThen run your commands inside the container. When finished, exit the container and restart if needed:\n\n```\nexit\ndocker restart ipsec-vpn-server\n```\n\n## Bind mount the env file\n\nAs an alternative to the `--env-file` option, advanced users can bind mount the `env` file. The advantage of this method is that after updating the `env` file, you can restart the Docker container to take effect instead of re-creating it. To use this method, you must first edit your `env` file and use single quotes `''` to enclose the values of all variables. Then (re-)create the Docker container (replace the first `vpn.env` with your own `env` file):\n\n```\ndocker run \\\n    --name ipsec-vpn-server \\\n    --restart=always \\\n    -v \"$(pwd)/vpn.env:/opt/src/env/vpn.env:ro\" \\\n    -v ikev2-vpn-data:/etc/ipsec.d \\\n    -v /lib/modules:/lib/modules:ro \\\n    -p 500:500/udp \\\n    -p 4500:4500/udp \\\n    -d --privileged \\\n    hwdsl2/ipsec-vpn-server\n```\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 on your Docker host.\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](https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/bbr.md). When finished, restart the Docker container:\n\n```\ndocker restart ipsec-vpn-server\n```\n\n## License\n\n**Note:** The software components inside the pre-built image (such as Libreswan and xl2tpd) are under the respective licenses chosen by their respective copyright holders. As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within.\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-zh-Hant.md",
    "content": "[&laquo; 返回首頁](../README-zh-Hant.md) | [English](vpn-book.md) | [简体中文](vpn-book-zh.md) | [繁體中文](vpn-book-zh-Hant.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)\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)\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": "run.sh",
    "content": "#!/bin/bash\n#\n# Docker script to configure and start an IPsec VPN server\n#\n# DO NOT RUN THIS SCRIPT ON YOUR PC OR MAC! THIS IS ONLY MEANT TO BE RUN\n# IN A CONTAINER!\n#\n# This file is part of IPsec VPN Docker image, available at:\n# https://github.com/hwdsl2/docker-ipsec-vpn-server\n#\n# Copyright (C) 2016-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\nexport PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\nexiterr()  { echo \"Error: $1\" >&2; exit 1; }\nnospaces() { printf '%s' \"$1\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'; }\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\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_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_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_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\nif [ ! -f \"/.dockerenv\" ] && [ ! -f \"/run/.containerenv\" ] \\\n  && [ -z \"$KUBERNETES_SERVICE_HOST\" ] \\\n  && ! head -n 1 /proc/1/sched 2>/dev/null | grep -q '^run\\.sh '; then\n  exiterr \"This script ONLY runs in a container (e.g. Docker, Podman).\"\nfi\n\nif ip link add dummy0 type dummy 2>&1 | grep -q \"not permitted\"; then\ncat 1>&2 <<'EOF'\nError: This Docker image should be run in privileged mode.\n       See: https://github.com/hwdsl2/docker-ipsec-vpn-server\n\nEOF\n  exit 1\nfi\nip link delete dummy0 >/dev/null 2>&1\n\nos_type=debian\nos_arch=$(uname -m | tr -dc 'A-Za-z0-9_-')\n[ -f /etc/os-release ] && os_type=$(. /etc/os-release && printf '%s' \"$ID\")\n\nif [ ! -e /dev/ppp ]; then\ncat <<'EOF'\n\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\nEOF\nfi\n\nNET_IFACE=$(route 2>/dev/null | grep -m 1 '^default' | grep -o '[^ ]*$')\n[ -z \"$NET_IFACE\" ] && NET_IFACE=$(ip -4 route list 0/0 2>/dev/null | grep -m 1 -Po '(?<=dev )(\\S+)')\n[ -z \"$NET_IFACE\" ] && NET_IFACE=eth0\n\nmkdir -p /opt/src\nvpn_env=\"/opt/src/vpn.env\"\nvpn_env_dir=\"/opt/src/env/vpn.env\"\nif [ -f \"$vpn_env_dir\" ]; then\n  vpn_env=\"$vpn_env_dir\"\nfi\nvpn_gen_env=\"/etc/ipsec.d/vpn-gen.env\"\nif [ -z \"$VPN_IPSEC_PSK\" ] && [ -z \"$VPN_USER\" ] && [ -z \"$VPN_PASSWORD\" ]; then\n  if [ -f \"$vpn_env\" ]; then\n    echo\n    echo 'Retrieving VPN credentials...'\n    . \"$vpn_env\"\n  elif [ -f \"$vpn_gen_env\" ]; then\n    echo\n    echo 'Retrieving previously generated VPN credentials...'\n    . \"$vpn_gen_env\"\n  else\n    echo\n    echo '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    printf '%s\\n' \"VPN_IPSEC_PSK='$VPN_IPSEC_PSK'\" > \"$vpn_gen_env\"\n    printf '%s\\n' \"VPN_USER='$VPN_USER'\" >> \"$vpn_gen_env\"\n    printf '%s\\n' \"VPN_PASSWORD='$VPN_PASSWORD'\" >> \"$vpn_gen_env\"\n    chmod 600 \"$vpn_gen_env\"\n  fi\nfi\n\n# Remove whitespace and quotes around VPN variables, if any\nVPN_IPSEC_PSK=$(nospaces \"$VPN_IPSEC_PSK\")\nVPN_IPSEC_PSK=$(noquotes \"$VPN_IPSEC_PSK\")\nVPN_USER=$(nospaces \"$VPN_USER\")\nVPN_USER=$(noquotes \"$VPN_USER\")\nVPN_PASSWORD=$(nospaces \"$VPN_PASSWORD\")\nVPN_PASSWORD=$(noquotes \"$VPN_PASSWORD\")\nif [ -n \"$VPN_ADDL_USERS\" ] && [ -n \"$VPN_ADDL_PASSWORDS\" ]; then\n  VPN_ADDL_USERS=$(nospaces \"$VPN_ADDL_USERS\")\n  VPN_ADDL_USERS=$(noquotes \"$VPN_ADDL_USERS\")\n  VPN_ADDL_USERS=$(onespace \"$VPN_ADDL_USERS\")\n  VPN_ADDL_USERS=$(noquotes2 \"$VPN_ADDL_USERS\")\n  VPN_ADDL_PASSWORDS=$(nospaces \"$VPN_ADDL_PASSWORDS\")\n  VPN_ADDL_PASSWORDS=$(noquotes \"$VPN_ADDL_PASSWORDS\")\n  VPN_ADDL_PASSWORDS=$(onespace \"$VPN_ADDL_PASSWORDS\")\n  VPN_ADDL_PASSWORDS=$(noquotes2 \"$VPN_ADDL_PASSWORDS\")\n  if [ -n \"$VPN_ADDL_IP_ADDRS\" ]; then\n    VPN_ADDL_IP_ADDRS=$(nospaces \"$VPN_ADDL_IP_ADDRS\")\n    VPN_ADDL_IP_ADDRS=$(noquotes \"$VPN_ADDL_IP_ADDRS\")\n    VPN_ADDL_IP_ADDRS=$(onespace \"$VPN_ADDL_IP_ADDRS\")\n    VPN_ADDL_IP_ADDRS=$(noquotes2 \"$VPN_ADDL_IP_ADDRS\")\n  fi\nelse\n  VPN_ADDL_USERS=\"\"\n  VPN_ADDL_PASSWORDS=\"\"\n  VPN_ADDL_IP_ADDRS=\"\"\nfi\nif [ -n \"$VPN_DNS_SRV1\" ]; then\n  VPN_DNS_SRV1=$(nospaces \"$VPN_DNS_SRV1\")\n  VPN_DNS_SRV1=$(noquotes \"$VPN_DNS_SRV1\")\nfi\nif [ -n \"$VPN_DNS_SRV2\" ]; then\n  VPN_DNS_SRV2=$(nospaces \"$VPN_DNS_SRV2\")\n  VPN_DNS_SRV2=$(noquotes \"$VPN_DNS_SRV2\")\nfi\nif [ -n \"$VPN_CLIENT_NAME\" ]; then\n  VPN_CLIENT_NAME=$(nospaces \"$VPN_CLIENT_NAME\")\n  VPN_CLIENT_NAME=$(noquotes \"$VPN_CLIENT_NAME\")\nfi\nif [ -n \"$VPN_DNS_NAME\" ]; then\n  VPN_DNS_NAME=$(nospaces \"$VPN_DNS_NAME\")\n  VPN_DNS_NAME=$(noquotes \"$VPN_DNS_NAME\")\nfi\nif [ -n \"$VPN_PUBLIC_IP\" ]; then\n  VPN_PUBLIC_IP=$(nospaces \"$VPN_PUBLIC_IP\")\n  VPN_PUBLIC_IP=$(noquotes \"$VPN_PUBLIC_IP\")\nfi\nif [ -n \"$VPN_ANDROID_MTU_FIX\" ]; then\n  VPN_ANDROID_MTU_FIX=$(nospaces \"$VPN_ANDROID_MTU_FIX\")\n  VPN_ANDROID_MTU_FIX=$(noquotes \"$VPN_ANDROID_MTU_FIX\")\nfi\nif [ -n \"$VPN_SHA2_TRUNCBUG\" ]; then\n  VPN_SHA2_TRUNCBUG=$(nospaces \"$VPN_SHA2_TRUNCBUG\")\n  VPN_SHA2_TRUNCBUG=$(noquotes \"$VPN_SHA2_TRUNCBUG\")\nfi\nif [ -n \"$VPN_PROTECT_CONFIG\" ]; then\n  VPN_PROTECT_CONFIG=$(nospaces \"$VPN_PROTECT_CONFIG\")\n  VPN_PROTECT_CONFIG=$(noquotes \"$VPN_PROTECT_CONFIG\")\nfi\nif [ -n \"$VPN_SPLIT_IKEV2\" ]; then\n  VPN_SPLIT_IKEV2=$(nospaces \"$VPN_SPLIT_IKEV2\")\n  VPN_SPLIT_IKEV2=$(noquotes \"$VPN_SPLIT_IKEV2\")\nfi\nif [ -n \"$VPN_DISABLE_IPSEC_L2TP\" ]; then\n  VPN_DISABLE_IPSEC_L2TP=$(nospaces \"$VPN_DISABLE_IPSEC_L2TP\")\n  VPN_DISABLE_IPSEC_L2TP=$(noquotes \"$VPN_DISABLE_IPSEC_L2TP\")\nfi\nif [ -n \"$VPN_DISABLE_IPSEC_XAUTH\" ]; then\n  VPN_DISABLE_IPSEC_XAUTH=$(nospaces \"$VPN_DISABLE_IPSEC_XAUTH\")\n  VPN_DISABLE_IPSEC_XAUTH=$(noquotes \"$VPN_DISABLE_IPSEC_XAUTH\")\nfi\nif [ -n \"$VPN_IKEV2_ONLY\" ]; then\n  VPN_IKEV2_ONLY=$(nospaces \"$VPN_IKEV2_ONLY\")\n  VPN_IKEV2_ONLY=$(noquotes \"$VPN_IKEV2_ONLY\")\nfi\nif [ -n \"$VPN_ENABLE_MODP1024\" ]; then\n  VPN_ENABLE_MODP1024=$(nospaces \"$VPN_ENABLE_MODP1024\")\n  VPN_ENABLE_MODP1024=$(noquotes \"$VPN_ENABLE_MODP1024\")\nfi\nif [ -n \"$VPN_ENABLE_MODP1536\" ]; then\n  VPN_ENABLE_MODP1536=$(nospaces \"$VPN_ENABLE_MODP1536\")\n  VPN_ENABLE_MODP1536=$(noquotes \"$VPN_ENABLE_MODP1536\")\nfi\nif [ -n \"$VPN_L2TP_NET\" ]; then\n  VPN_L2TP_NET=$(nospaces \"$VPN_L2TP_NET\")\n  VPN_L2TP_NET=$(noquotes \"$VPN_L2TP_NET\")\nfi\nif [ -n \"$VPN_L2TP_LOCAL\" ]; then\n  VPN_L2TP_LOCAL=$(nospaces \"$VPN_L2TP_LOCAL\")\n  VPN_L2TP_LOCAL=$(noquotes \"$VPN_L2TP_LOCAL\")\nfi\nif [ -n \"$VPN_L2TP_POOL\" ]; then\n  VPN_L2TP_POOL=$(nospaces \"$VPN_L2TP_POOL\")\n  VPN_L2TP_POOL=$(noquotes \"$VPN_L2TP_POOL\")\nfi\nif [ -n \"$VPN_XAUTH_NET\" ]; then\n  VPN_XAUTH_NET=$(nospaces \"$VPN_XAUTH_NET\")\n  VPN_XAUTH_NET=$(noquotes \"$VPN_XAUTH_NET\")\nfi\nif [ -n \"$VPN_XAUTH_POOL\" ]; then\n  VPN_XAUTH_POOL=$(nospaces \"$VPN_XAUTH_POOL\")\n  VPN_XAUTH_POOL=$(noquotes \"$VPN_XAUTH_POOL\")\nfi\nif [ -n \"$VPN_PUBLIC_IP6\" ]; then\n  VPN_PUBLIC_IP6=$(nospaces \"$VPN_PUBLIC_IP6\")\n  VPN_PUBLIC_IP6=$(noquotes \"$VPN_PUBLIC_IP6\")\nfi\nif [ -n \"$VPN_IP6_NET\" ]; then\n  VPN_IP6_NET=$(nospaces \"$VPN_IP6_NET\")\n  VPN_IP6_NET=$(noquotes \"$VPN_IP6_NET\")\nfi\n\nip6=\"\"\nif [ -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=\"\"; }\nfi\nif [ -z \"$ip6\" ]; then\n  ip6=$(ip -6 addr 2>/dev/null | awk '/inet6 [23]/ {print $2}' | cut -d'/' -f1 | head -n1)\n  check_ip6 \"$ip6\" || ip6=\"\"\n  if [ -z \"$ip6\" ] && ip -6 addr 2>/dev/null | grep 'inet6' | grep -qv 'inet6 \\(::1\\|fe80\\)'; then\n    ip6=$(wget -t 2 -T 10 -qO- https://ipv6.icanhazip.com 2>/dev/null)\n    check_ip6 \"$ip6\" || ip6=\"\"\n  fi\nfi\n\nif [ -z \"$VPN_IPSEC_PSK\" ] || [ -z \"$VPN_USER\" ] || [ -z \"$VPN_PASSWORD\" ]; then\n  exiterr \"All VPN credentials must be specified. Edit your 'env' file and re-enter them.\"\nfi\nif printf '%s' \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD $VPN_ADDL_USERS $VPN_ADDL_PASSWORDS\" | LC_ALL=C grep -q '[^ -~]\\+'; then\n  exiterr \"VPN credentials must not contain non-ASCII characters.\"\nfi\ncase \"$VPN_IPSEC_PSK $VPN_USER $VPN_PASSWORD $VPN_ADDL_USERS $VPN_ADDL_PASSWORDS\" in\n  *[\\\\\\\"\\']*)\n    exiterr \"VPN credentials must not contain these special characters: \\\\ \\\" '\"\n    ;;\nesac\nif printf '%s' \"$VPN_USER $VPN_ADDL_USERS\" | tr ' ' '\\n' | sort | uniq -c | grep -qv '^ *1 '; then\n  exiterr \"VPN usernames must not contain duplicates.\"\nfi\n\n# Check DNS servers and try to resolve hostnames to IPs\nif [ -n \"$VPN_DNS_SRV1\" ]; then\n  check_ip \"$VPN_DNS_SRV1\" || VPN_DNS_SRV1=$(dig -t A -4 +short \"$VPN_DNS_SRV1\")\n  if ! check_ip \"$VPN_DNS_SRV1\"; then\ncat <<'EOF'\n\nWarning: Invalid DNS server. Check VPN_DNS_SRV1 in your 'env' file.\nEOF\n    VPN_DNS_SRV1=\"\"\n  fi\nfi\nif [ -n \"$VPN_DNS_SRV2\" ]; then\n  check_ip \"$VPN_DNS_SRV2\" || VPN_DNS_SRV2=$(dig -t A -4 +short \"$VPN_DNS_SRV2\")\n  if ! check_ip \"$VPN_DNS_SRV2\"; then\ncat <<'EOF'\n\nWarning: Invalid DNS server. Check VPN_DNS_SRV2 in your 'env' file.\nEOF\n    VPN_DNS_SRV2=\"\"\n  fi\nfi\nif [ -n \"$VPN_CLIENT_NAME\" ]; then\n  if ! check_client_name \"$VPN_CLIENT_NAME\"; then\ncat <<'EOF'\n\nWarning: Invalid client name. Use one word only, no special characters except '-' and '_'.\n         Falling back to default client name 'vpnclient'.\nEOF\n    VPN_CLIENT_NAME=\"\"\n  fi\nfi\nif [ -n \"$VPN_DNS_NAME\" ]; then\n  if ! check_dns_name \"$VPN_DNS_NAME\"; then\ncat <<'EOF'\n\nWarning: Invalid DNS name. 'VPN_DNS_NAME' must be a fully qualified domain name (FQDN).\n         Falling back to using this server's IP address.\nEOF\n    VPN_DNS_NAME=\"\"\n  fi\nfi\nif [ -n \"$VPN_SPLIT_IKEV2\" ]; then\n  if ! check_cidr \"$VPN_SPLIT_IKEV2\"; then\ncat <<'EOF'\n\nWarning: Invalid split VPN subnet. Check VPN_SPLIT_IKEV2 in your 'env' file.\nEOF\n    VPN_SPLIT_IKEV2=\"\"\n  fi\nfi\n\necho\necho 'Trying to auto discover IP of this server...'\n# In case auto IP discovery fails, manually define the public IP\n# of this server in your 'env' file, as variable 'VPN_PUBLIC_IP'.\npublic_ip=${VPN_PUBLIC_IP:-''}\ncheck_ip \"$public_ip\" || public_ip=$(dig @resolver1.opendns.com -t A -4 myip.opendns.com +short)\ncheck_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ipv4.icanhazip.com)\ncheck_ip \"$public_ip\" || public_ip=$(wget -t 2 -T 10 -qO- http://ip1.dynupdate.no-ip.com)\ncheck_ip \"$public_ip\" || exiterr \"Cannot detect this server's public IP. Define it in your 'env' file as 'VPN_PUBLIC_IP'.\"\n\nif [ -n \"$VPN_DNS_NAME\" ]; then\n  server_addr=\"$VPN_DNS_NAME\"\nelse\n  server_addr=\"$public_ip\"\nfi\n\nL2TP_NET=${VPN_L2TP_NET:-'192.168.42.0/24'}\nL2TP_LOCAL=${VPN_L2TP_LOCAL:-'192.168.42.1'}\nL2TP_POOL=${VPN_L2TP_POOL:-'192.168.42.10-192.168.42.250'}\nXAUTH_NET=${VPN_XAUTH_NET:-'192.168.43.0/24'}\nXAUTH_POOL=${VPN_XAUTH_POOL:-'192.168.43.10-192.168.43.250'}\nIP6_NET=${VPN_IP6_NET:-'fddd:500:500:500::/64'}\nDNS_SRV1=${VPN_DNS_SRV1:-'8.8.8.8'}\nDNS_SRV2=${VPN_DNS_SRV2:-'8.8.4.4'}\nDNS_SRVS=\"\\\"$DNS_SRV1 $DNS_SRV2\\\"\"\n[ -n \"$VPN_DNS_SRV1\" ] && [ -z \"$VPN_DNS_SRV2\" ] && DNS_SRVS=\"$DNS_SRV1\"\nvp_ip6=\"\"\n[ -n \"$ip6\" ] && vp_ip6=\",%v6:fc00::/7,%v6:!$IP6_NET\"\n\nif [ -n \"$VPN_DNS_SRV1\" ] && [ -n \"$VPN_DNS_SRV2\" ]; then\n  echo\n  echo \"Setting DNS servers to $VPN_DNS_SRV1 and $VPN_DNS_SRV2...\"\nelif [ -n \"$VPN_DNS_SRV1\" ]; then\n  echo\n  echo \"Setting DNS server to $VPN_DNS_SRV1...\"\nfi\n\nsha2_truncbug=no\ncase $VPN_SHA2_TRUNCBUG in\n  [yY][eE][sS])\n    echo\n    echo \"Setting sha2-truncbug to yes in ipsec.conf...\"\n    sha2_truncbug=yes\n    ;;\nesac\ndisable_ipsec_l2tp=no\ncase $VPN_DISABLE_IPSEC_L2TP in\n  [yY][eE][sS])\n    disable_ipsec_l2tp=yes\n    ;;\nesac\ndisable_ipsec_xauth=no\ncase $VPN_DISABLE_IPSEC_XAUTH in\n  [yY][eE][sS])\n    disable_ipsec_xauth=yes\n    ;;\nesac\ncase $VPN_IKEV2_ONLY in\n  [yY][eE][sS])\n    disable_ipsec_l2tp=yes\n    disable_ipsec_xauth=yes\n    ;;\nesac\nike_algs=\"aes256-sha2;modp2048,aes128-sha2;modp2048,aes256-sha1;modp2048,aes128-sha1;modp2048\"\nike_algs_addl_1=\",aes256-sha2;modp1024,aes128-sha1;modp1024\"\nike_algs_addl_2=\",aes256-sha2;modp1536,aes128-sha1;modp1536\"\ncase $VPN_ENABLE_MODP1024 in\n  [yY][eE][sS])\n    echo\n    echo \"Enabling modp1024 in ipsec.conf...\"\n    ike_algs=\"$ike_algs$ike_algs_addl_1\"\n    ;;\nesac\ncase $VPN_ENABLE_MODP1536 in\n  [yY][eE][sS])\n    echo\n    echo \"Enabling modp1536 in ipsec.conf...\"\n    ike_algs=\"$ike_algs$ike_algs_addl_2\"\n    ;;\nesac\n\nif [ \"$disable_ipsec_l2tp\" = yes ] && [ \"$disable_ipsec_xauth\" = yes ]; then\ncat <<'EOF'\n\nNote: Running in IKEv2-only mode via env file option.\n      IPsec/L2TP and IPsec/XAuth (\"Cisco IPsec\") modes are disabled.\nEOF\n  if ! grep -q \" /etc/ipsec.d \" /proc/mounts; then\ncat <<'EOF'\n\nWarning: /etc/ipsec.d not mounted. IKEv2 setup requires a Docker volume\n         mounted at /etc/ipsec.d.\nEOF\n  fi\nelif [ \"$disable_ipsec_l2tp\" = yes ]; then\ncat <<'EOF'\n\nNote: IPsec/L2TP mode is disabled via env file option.\nEOF\nelif [ \"$disable_ipsec_xauth\" = yes ]; then\ncat <<'EOF'\n\nNote: IPsec/XAuth (\"Cisco IPsec\") mode is disabled via env file option.\nEOF\nfi\n\n# Create IPsec config\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=$ike_algs\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=$sha2_truncbug\n\nEOF\n\nif [ \"$disable_ipsec_l2tp\" != yes ]; then\ncat >> /etc/ipsec.conf <<'EOF'\nconn l2tp-psk\n  auto=add\n  leftprotoport=17/1701\n  rightprotoport=17/%any\n  type=transport\n  also=shared\n\nEOF\nfi\nif [ \"$disable_ipsec_xauth\" != yes ]; then\ncat >> /etc/ipsec.conf <<EOF\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\nEOF\nfi\n\ncat >> /etc/ipsec.conf <<'EOF'\ninclude /etc/ipsec.d/*.conf\nEOF\n\nif uname -r | grep -qi 'coreos'; then\n  sed -i '/phase2alg/s/,aes256-sha2_512//' /etc/ipsec.conf\nfi\nif grep -qs ike-frag /etc/ipsec.d/ikev2.conf; then\n  sed -i 's/^[[:space:]]\\+ike-frag=/  fragmentation=/' /etc/ipsec.d/ikev2.conf\nfi\n\n# Specify IPsec PSK\ncat > /etc/ipsec.secrets <<EOF\n%any  %any  : PSK \"$VPN_IPSEC_PSK\"\nEOF\n\n# Create xl2tpd config\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\n# Set xl2tpd options\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\nif [ -z \"$VPN_DNS_SRV1\" ] || [ -n \"$VPN_DNS_SRV2\" ]; then\ncat >> /etc/ppp/options.xl2tpd <<EOF\nms-dns $DNS_SRV2\nEOF\nfi\n\n# Create VPN credentials\ncat > /etc/ppp/chap-secrets <<EOF\n\"$VPN_USER\" l2tpd \"$VPN_PASSWORD\" *\nEOF\n\nVPN_PASSWORD_ENC=$(openssl passwd -1 \"$VPN_PASSWORD\")\ncat > /etc/ipsec.d/passwd <<EOF\n$VPN_USER:$VPN_PASSWORD_ENC:xauth-psk\nEOF\n\nif [ -n \"$VPN_ADDL_USERS\" ] && [ -n \"$VPN_ADDL_PASSWORDS\" ]; then\n  count=1\n  addl_user=$(printf '%s' \"$VPN_ADDL_USERS\" | cut -d ' ' -f 1)\n  addl_password=$(printf '%s' \"$VPN_ADDL_PASSWORDS\" | cut -d ' ' -f 1)\n  addl_ip=$(printf '%s' \"$VPN_ADDL_IP_ADDRS\" | cut -d ' ' -f 1)\n  while [ -n \"$addl_user\" ] && [ -n \"$addl_password\" ]; do\n    addl_ip_l2tp=\"$addl_ip\"\n    addl_ip_xauth=\"$addl_ip\"\n    if [ \"$addl_ip\" = \"*\" ] || ! check_ip \"$addl_ip\"; then\n      addl_ip_l2tp=\"\"\n      addl_ip_xauth=\"\"\n    elif [ \"$L2TP_NET\" = \"192.168.42.0/24\" ] && [ \"$XAUTH_NET\" = \"192.168.43.0/24\" ]; then\n      addl_ip_part=$(printf '%s' \"$addl_ip\" | cut -f 1-3 -d '.')\n      if [ \"$addl_ip_part\" = \"192.168.42\" ]; then\n        addl_ip_xauth=\"\"\n      elif [ \"$addl_ip_part\" = \"192.168.43\" ]; then\n        addl_ip_l2tp=\"\"\n      else\n        addl_ip_l2tp=\"\"\n        addl_ip_xauth=\"\"\n      fi\n    fi\ncat >> /etc/ppp/chap-secrets <<EOF\n\"$addl_user\" l2tpd \"$addl_password\" ${addl_ip_l2tp:-*}\nEOF\n    [ -n \"$addl_ip_xauth\" ] && addl_ip_xauth=$(printf '%s' \":$addl_ip_xauth\")\n    addl_password_enc=$(openssl passwd -1 \"$addl_password\")\ncat >> /etc/ipsec.d/passwd <<EOF\n$addl_user:$addl_password_enc:xauth-psk${addl_ip_xauth}\nEOF\n    count=$((count+1))\n    addl_user=$(printf '%s' \"$VPN_ADDL_USERS\" | cut -s -d ' ' -f \"$count\")\n    addl_password=$(printf '%s' \"$VPN_ADDL_PASSWORDS\" | cut -s -d ' ' -f \"$count\")\n    addl_ip=$(printf '%s' \"$VPN_ADDL_IP_ADDRS\" | cut -s -d ' ' -f \"$count\")\n  done\nfi\n\n# Update sysctl settings\nsyt='/sbin/sysctl -e -q -w'\n$syt kernel.msgmnb=65536 2>/dev/null\n$syt kernel.msgmax=65536 2>/dev/null\n$syt net.ipv4.ip_forward=1 2>/dev/null\n$syt net.ipv4.conf.all.accept_redirects=0 2>/dev/null\n$syt net.ipv4.conf.all.send_redirects=0 2>/dev/null\n$syt net.ipv4.conf.all.rp_filter=0 2>/dev/null\n$syt net.ipv4.conf.default.accept_redirects=0 2>/dev/null\n$syt net.ipv4.conf.default.send_redirects=0 2>/dev/null\n$syt net.ipv4.conf.default.rp_filter=0 2>/dev/null\n$syt \"net.ipv4.conf.$NET_IFACE.send_redirects=0\" 2>/dev/null\n$syt \"net.ipv4.conf.$NET_IFACE.rp_filter=0\" 2>/dev/null\n$syt net.ipv4.tcp_rmem=\"4096 87380 16777216\" 2>/dev/null\n$syt net.ipv4.tcp_wmem=\"4096 87380 16777216\" 2>/dev/null\nif [ -n \"$ip6\" ]; then\n  $syt net.ipv6.conf.all.forwarding=1 2>/dev/null\nfi\nif modprobe -q tcp_bbr 2>/dev/null \\\n  && printf '%s\\n%s' \"4.20\" \"$(uname -r)\" | sort -C -V; then\n  $syt net.ipv4.tcp_congestion_control=bbr 2>/dev/null\nfi\n\n# Create IPTables rules\nipi='iptables -I INPUT'\nipf='iptables -I FORWARD'\nipp='iptables -t nat -I POSTROUTING'\nres='RELATED,ESTABLISHED'\nmodprobe -q ip_tables 2>/dev/null\nif ! iptables -t nat -C POSTROUTING -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE 2>/dev/null; then\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  # Client-to-client traffic is allowed by default. To *disallow* such traffic,\n  # uncomment below and restart the Docker container.\n  # $ipf 2 -i ppp+ -o ppp+ -s \"$L2TP_NET\" -d \"$L2TP_NET\" -j DROP\n  # $ipf 3 -s \"$XAUTH_NET\" -d \"$XAUTH_NET\" -j DROP\n  # $ipf 4 -i ppp+ -d \"$XAUTH_NET\" -j DROP\n  # $ipf 5 -s \"$XAUTH_NET\" -o ppp+ -j DROP\n  iptables -A FORWARD -j DROP\n  if ! $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" -m policy --dir out --pol none -j MASQUERADE; then\n    $ipp -s \"$XAUTH_NET\" -o \"$NET_IFACE\" ! -d \"$XAUTH_NET\" -j MASQUERADE\n  fi\n  $ipp -s \"$L2TP_NET\" -o \"$NET_IFACE\" -j MASQUERADE\nfi\n\nif [ -n \"$ip6\" ]; then\n  modprobe -q ip6_tables 2>/dev/null\n  if ip6tables -t nat -L >/dev/null 2>&1; then\n    ipi6='ip6tables -I INPUT'\n    ipf6='ip6tables -I FORWARD'\n    ipp6='ip6tables -t nat -I POSTROUTING'\n    if ! ip6tables -t nat -C POSTROUTING -s \"$IP6_NET\" -o \"$NET_IFACE\" \\\n        -j MASQUERADE 2>/dev/null; then\n      $ipi6 1 -m conntrack --ctstate INVALID -j DROP\n      $ipi6 2 -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ipi6 3 -p udp -m multiport --dports 500,4500 -j ACCEPT\n      $ipf6 1 -m conntrack --ctstate INVALID -j DROP\n      $ipf6 2 -i \"$NET_IFACE\" -d \"$IP6_NET\" -m conntrack --ctstate \"$res\" -j ACCEPT\n      $ipf6 3 -s \"$IP6_NET\" -o \"$NET_IFACE\" -j ACCEPT\n      if ! $ipp6 -s \"$IP6_NET\" -o \"$NET_IFACE\" \\\n          -m policy --dir out --pol none -j MASQUERADE; then\n        $ipp6 -s \"$IP6_NET\" -o \"$NET_IFACE\" ! -d \"$IP6_NET\" -j MASQUERADE\n      fi\n    fi\n  fi\nfi\n\ncase $VPN_ANDROID_MTU_FIX in\n  [yY][eE][sS])\n    echo\n    echo \"Applying fix for Android MTU/MSS issues...\"\n    iptables -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\n    iptables -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    echo 1 > /proc/sys/net/ipv4/ip_no_pmtu_disc\n    ;;\nesac\n\n# Update file attributes\nchmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /etc/ipsec.d/passwd\n\necho\necho \"Starting IPsec service...\"\nmkdir -p /run/pluto /var/run/pluto\nrm -f /run/pluto/pluto.pid /var/run/pluto/pluto.pid\nif [ \"$os_type\" = \"alpine\" ]; then\n  sed -i '1c\\#!/sbin/openrc-run' /etc/init.d/ipsec\n  rc-status >/dev/null 2>&1\n  rc-service ipsec zap >/dev/null\n  rc-service -D ipsec start >/dev/null 2>&1\n  mkdir -p /etc/crontabs\n  cron_cmd=\"rc-service -c -D ipsec zap start\"\nif ! 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\nfi\n  /usr/sbin/crond -L /dev/null\nelse\n  service ipsec start >/dev/null 2>&1\nfi\n\nif [ -n \"$VPN_DNS_NAME\" ]; then\n  server_text=\"Server\"\nelse\n  server_text=\"Server IP\"\nfi\n\nif [ \"$disable_ipsec_l2tp\" != yes ] || [ \"$disable_ipsec_xauth\" != yes ]; then\ncat <<EOF\n\n================================================\n\nIPsec VPN server is now ready for use!\n\nConnect to your new VPN with these details:\n\n$server_text: $server_addr\nIPsec PSK: $VPN_IPSEC_PSK\nUsername: $VPN_USER\nPassword: $VPN_PASSWORD\nEOF\n  if [ -n \"$VPN_ADDL_USERS\" ] && [ -n \"$VPN_ADDL_PASSWORDS\" ]; then\n    count=1\n    addl_user=$(printf '%s' \"$VPN_ADDL_USERS\" | cut -d ' ' -f 1)\n    addl_password=$(printf '%s' \"$VPN_ADDL_PASSWORDS\" | cut -d ' ' -f 1)\ncat <<'EOF'\n\nAdditional VPN users (username | password):\nEOF\n    while [ -n \"$addl_user\" ] && [ -n \"$addl_password\" ]; do\ncat <<EOF\n$addl_user | $addl_password\nEOF\n      count=$((count+1))\n      addl_user=$(printf '%s' \"$VPN_ADDL_USERS\" | cut -s -d ' ' -f \"$count\")\n      addl_password=$(printf '%s' \"$VPN_ADDL_PASSWORDS\" | cut -s -d ' ' -f \"$count\")\n    done\n  fi\ncat <<'EOF'\n\nWrite these down. You'll need them to connect!\n\nVPN client setup: https://vpnsetup.net/clients2\n\n================================================\nEOF\nfi\n\n# Set up IKEv2\nstatus=0\nikev2_sh=\"/opt/src/ikev2.sh\"\nikev2_conf=\"/etc/ipsec.d/ikev2.conf\"\nikev2_log=\"/etc/ipsec.d/ikev2setup.log\"\nif grep -q \" /etc/ipsec.d \" /proc/mounts && [ -s \"$ikev2_sh\" ] && [ ! -f \"$ikev2_conf\" ]; then\n  echo\n  echo \"Setting up IKEv2. This may take a few moments...\"\n  if [ -n \"$VPN_SPLIT_IKEV2\" ]; then\n    sed -i \"s|^  leftsubnet=0\\.0\\.0\\.0/0$|  leftsubnet=$VPN_SPLIT_IKEV2|g\" \"$ikev2_sh\"\n  fi\n  if 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_PUBLIC_IP6=\"$ip6\" \\\n    /bin/bash \"$ikev2_sh\" --auto >\"$ikev2_log\" 2>&1; then\n    status=1\n    status_text=\"IKEv2 setup successful.\"\n  else\n    status=4\n    rm -f \"$ikev2_conf\"\n    echo \"IKEv2 setup failed.\"\n  fi\n  chmod 600 \"$ikev2_log\"\nfi\nif [ \"$status\" = 0 ] && [ -f \"$ikev2_conf\" ] && [ -s \"$ikev2_log\" ]; then\n  status=2\n  status_text=\"IKEv2 is already set up.\"\nfi\nif [ \"$status\" = 1 ] || [ \"$status\" = 2 ]; then\ncat <<EOF\n\n================================================\n\n$status_text Details for IKEv2 mode:\n\nEOF\n  sed -n '/VPN server address:/,/Next steps:/p' \"$ikev2_log\"\ncat <<'EOF'\nhttps://vpnsetup.net/clients2\n\n================================================\n\nEOF\nelse\n  echo\nfi\n\nif [ \"$status\" = 2 ] && [ -n \"$VPN_DNS_NAME\" ]; then\n  server_addr_cur=$(grep -s \"leftcert=\" /etc/ipsec.d/ikev2.conf | cut -f2 -d= | head -n 1)\n  if [ \"$VPN_DNS_NAME\" != \"$server_addr_cur\" ]; then\ncat <<'EOF'\nWarning: The VPN_DNS_NAME variable you specified has no effect\n         for IKEv2 mode, because IKEv2 is already set up in this\n         container. To change the IKEv2 server address, see:\n         https://vpnsetup.net/ikev2docker\n\nEOF\n  fi\nfi\n\n# Check for new Libreswan version\nts_file=\"/opt/src/swanver\"\nif [ ! -f \"$ts_file\" ] || [ \"$(find \"$ts_file\" -mmin +10080)\" ]; then\n  touch \"$ts_file\"\n  ipsec_ver=$(ipsec --version 2>/dev/null)\n  swan_ver=$(printf '%s' \"$ipsec_ver\" | sed -e 's/.*Libreswan U\\?//' -e 's/\\( (\\|\\/K\\).*//')\n  base_url=\"https://github.com/hwdsl2/vpn-extras/releases/download/v1.0.0\"\n  swan_ver_url=\"$base_url/upg-docker-$os_type-$os_arch-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.\nTo update this Docker image, see: https://vpnsetup.net/dockerupdate\n\nEOF\n  fi\nfi\n\n# Start xl2tpd\nmkdir -p /var/run/xl2tpd\nrm -f /var/run/xl2tpd.pid\nexec /usr/sbin/xl2tpd -D -c /etc/xl2tpd/xl2tpd.conf\n"
  },
  {
    "path": "vpn.env.example",
    "content": "# Note: All the variables to this image are optional.\n# See README for more information.\n# To use, uncomment and replace with your own values.\n\n# Define IPsec PSK, VPN username and password\n# - DO NOT put \"\" or '' around values, or add space around =\n# - DO NOT use these special characters within values: \\ \" '\n# VPN_IPSEC_PSK=your_ipsec_pre_shared_key\n# VPN_USER=your_vpn_username\n# VPN_PASSWORD=your_vpn_password\n\n# Define additional VPN users\n# - DO NOT put \"\" or '' around values, or add space around =\n# - DO NOT use these special characters within values: \\ \" '\n# - Usernames and passwords must be separated by spaces\n# VPN_ADDL_USERS=additional_username_1 additional_username_2\n# VPN_ADDL_PASSWORDS=additional_password_1 additional_password_2\n\n# Use a DNS name for the VPN server\n# - The DNS name must be a fully qualified domain name (FQDN)\n# VPN_DNS_NAME=vpn.example.com\n\n# Specify a name for the first IKEv2 client\n# - Use one word only, no special characters except '-' and '_'\n# - The default is 'vpnclient' if not specified\n# VPN_CLIENT_NAME=your_client_name\n\n# Use alternative DNS servers\n# - By default, clients are set to use Google Public DNS\n# - Example below shows Cloudflare's DNS service\n# VPN_DNS_SRV1=1.1.1.1\n# VPN_DNS_SRV2=1.0.0.1\n\n# Protect IKEv2 client config files using a password\n# - By default, no password is required when importing IKEv2 client configuration\n# - Uncomment if you want to protect these files using a random password\n# VPN_PROTECT_CONFIG=yes\n\n# Specify the public IPv6 address of the Docker host (optional)\n# - Only used when the Docker host has a public IPv6 address\n# - If not specified, the IPv6 address is auto-detected\n# VPN_PUBLIC_IP6=your_ipv6_address\n\n# Customize the IPv6 pool subnet for IKEv2 clients (optional)\n# - Only used when the Docker host has a public IPv6 address\n# - Must be a /64 subnet in the ULA range (e.g. fddd::/16)\n# - Default is fddd:500:500:500::/64 if not specified\n# VPN_IP6_NET=fddd:1234:5678:9012::/64\n"
  }
]