├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── docker-image-pr.yml │ ├── docker-image-tag-pdns-admin.yml │ ├── docker-image-tag-pdns-mysql-alpine.yml │ ├── docker-image-tag-pdns-mysql-fedora.yml │ ├── docker-image-tag-pdns-pgsql-alpine.yml │ ├── docker-image-tag-pdns-pgsql-fedora.yml │ ├── docker-image-tag-recursor-alpine.yml │ ├── docker-image-tag-recursor-fedora.yml │ └── docker-image.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── ansible-playbook-mysql.yml ├── ansible-playbook-pgsql.yml ├── deprecated ├── README.md ├── pdns-admin-base-ngoduykhanh │ ├── Dockerfile │ ├── config.py.tpl │ └── run.py ├── pdns-admin-static-ngoduykhanh │ ├── Dockerfile │ ├── docker-entrypoint.sh │ └── pdns-nginx.conf.tpl └── pdns-admin-uwsgi-ngoduykhanh │ ├── Dockerfile │ ├── docker-entrypoint.sh │ └── pdns-admin.ini ├── docker-compose-mysql-ipv6.yml ├── docker-compose-mysql.yml ├── docker-compose-pgsql.yml ├── examples └── kubernetes │ ├── README.MD │ ├── admin-dashboard.yaml │ ├── kustomization.yaml │ ├── mariadb.yaml │ ├── master-daemonset.yaml │ └── slave-daemonset.yaml ├── pdns-admin ├── Caddyfile.tpl ├── Dockerfile ├── config.py.tpl ├── docker-entrypoint.sh ├── pdns-admin.ini ├── run.py └── supervisor.ini ├── pdns-mysql ├── Dockerfile ├── Dockerfile.alpine ├── docker-entrypoint.sh └── pdns.conf.tpl ├── pdns-pgsql ├── Dockerfile ├── Dockerfile.alpine ├── docker-entrypoint.sh └── pdns.conf.tpl └── pdns-recursor ├── Dockerfile ├── Dockerfile.alpine ├── docker-entrypoint.sh └── recursor.conf.tpl /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: pschiffe 2 | custom: "https://www.paypal.com/paypalme/pschiffe" 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "docker" 4 | directory: "/pdns-mysql" 5 | schedule: 6 | interval: "monthly" 7 | - package-ecosystem: "docker" 8 | directory: "/pdns-pgsql" 9 | schedule: 10 | interval: "monthly" 11 | - package-ecosystem: "docker" 12 | directory: "/pdns-recursor" 13 | schedule: 14 | interval: "monthly" 15 | - package-ecosystem: "docker" 16 | directory: "/pdns-admin" 17 | schedule: 18 | interval: "monthly" 19 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-pr.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI for PRs 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | test-recursor-latest: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check Out Repo 13 | uses: actions/checkout@v4 14 | - name: Set up Docker Buildx 15 | id: buildx 16 | uses: docker/setup-buildx-action@v3 17 | - name: Build PDNS Recursor latest 18 | id: docker_build_recursor_latest 19 | uses: docker/build-push-action@v5 20 | with: 21 | context: ./pdns-recursor 22 | file: ./pdns-recursor/Dockerfile 23 | builder: ${{ steps.buildx.outputs.name }} 24 | push: false 25 | tags: pdns-recursor:latest 26 | - name: Image digest 27 | run: echo ${{ steps.docker_build_recursor_latest.outputs.digest }} 28 | 29 | test-recursor-alpine: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Check Out Repo 33 | uses: actions/checkout@v4 34 | - name: Set up Docker Buildx 35 | id: buildx 36 | uses: docker/setup-buildx-action@v3 37 | - name: Build PDNS Recursor alpine 38 | id: docker_build_recursor_alpine 39 | uses: docker/build-push-action@v5 40 | with: 41 | context: ./pdns-recursor 42 | file: ./pdns-recursor/Dockerfile.alpine 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: false 45 | tags: pdns-recursor:alpine 46 | - name: Image digest 47 | run: echo ${{ steps.docker_build_recursor_alpine.outputs.digest }} 48 | 49 | test-pdns-mysql-latest: 50 | runs-on: ubuntu-latest 51 | steps: 52 | - name: Check Out Repo 53 | uses: actions/checkout@v4 54 | - name: Set up Docker Buildx 55 | id: buildx 56 | uses: docker/setup-buildx-action@v3 57 | - name: Build PDNS mysql latest 58 | id: docker_build_pdns_mysql_latest 59 | uses: docker/build-push-action@v5 60 | with: 61 | context: ./pdns-mysql 62 | file: ./pdns-mysql/Dockerfile 63 | builder: ${{ steps.buildx.outputs.name }} 64 | push: false 65 | tags: pdns-mysql:latest 66 | - name: Image digest 67 | run: echo ${{ steps.docker_build_pdns_mysql_latest.outputs.digest }} 68 | 69 | test-pdns-mysql-alpine: 70 | runs-on: ubuntu-latest 71 | steps: 72 | - name: Check Out Repo 73 | uses: actions/checkout@v4 74 | - name: Set up Docker Buildx 75 | id: buildx 76 | uses: docker/setup-buildx-action@v3 77 | - name: Build PDNS mysql alpine 78 | id: docker_build_pdns_mysql_alpine 79 | uses: docker/build-push-action@v5 80 | with: 81 | context: ./pdns-mysql 82 | file: ./pdns-mysql/Dockerfile.alpine 83 | builder: ${{ steps.buildx.outputs.name }} 84 | push: false 85 | tags: pdns-mysql:alpine 86 | - name: Image digest 87 | run: echo ${{ steps.docker_build_pdns_mysql_alpine.outputs.digest }} 88 | 89 | test-pdns-pgsql-latest: 90 | runs-on: ubuntu-latest 91 | steps: 92 | - name: Check Out Repo 93 | uses: actions/checkout@v4 94 | - name: Set up Docker Buildx 95 | id: buildx 96 | uses: docker/setup-buildx-action@v3 97 | - name: Build PDNS pgsql latest 98 | id: docker_build_pdns_pgsql_latest 99 | uses: docker/build-push-action@v5 100 | with: 101 | context: ./pdns-pgsql 102 | file: ./pdns-pgsql/Dockerfile 103 | builder: ${{ steps.buildx.outputs.name }} 104 | push: false 105 | tags: pdns-pgsql:latest 106 | - name: Image digest 107 | run: echo ${{ steps.docker_build_pdns_pgsql_latest.outputs.digest }} 108 | 109 | test-pdns-pgsql-alpine: 110 | runs-on: ubuntu-latest 111 | steps: 112 | - name: Check Out Repo 113 | uses: actions/checkout@v4 114 | - name: Set up Docker Buildx 115 | id: buildx 116 | uses: docker/setup-buildx-action@v3 117 | - name: Build PDNS pgsql alpine 118 | id: docker_build_pdns_pgsql_alpine 119 | uses: docker/build-push-action@v5 120 | with: 121 | context: ./pdns-pgsql 122 | file: ./pdns-pgsql/Dockerfile.alpine 123 | builder: ${{ steps.buildx.outputs.name }} 124 | push: false 125 | tags: pdns-pgsql:alpine 126 | - name: Image digest 127 | run: echo ${{ steps.docker_build_pdns_pgsql_alpine.outputs.digest }} 128 | 129 | test-pdns-admin: 130 | runs-on: ubuntu-latest 131 | steps: 132 | - name: Check Out Repo 133 | uses: actions/checkout@v4 134 | - name: Set up Docker Buildx 135 | id: buildx 136 | uses: docker/setup-buildx-action@v3 137 | - name: Build pdns admin 138 | id: docker_build_pdns_admin 139 | uses: docker/build-push-action@v5 140 | with: 141 | context: ./pdns-admin 142 | file: ./pdns-admin/Dockerfile 143 | builder: ${{ steps.buildx.outputs.name }} 144 | push: false 145 | tags: | 146 | pdns-admin:latest 147 | - name: Image digest 148 | run: echo ${{ steps.docker_build_pdns_admin.outputs.digest }} 149 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-pdns-admin.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-admin 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-admin-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS Admin 37 | id: docker_build_pdns_admin 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-admin 41 | file: ./pdns-admin/Dockerfile 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-admin:${{ steps.vars.outputs.version }} 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_pdns_admin.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-pdns-mysql-alpine.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-mysql alpine 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-alpine-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS mysql 37 | id: docker_build_pdns 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-mysql 41 | file: ./pdns-mysql/Dockerfile.alpine 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-mysql:${{ steps.vars.outputs.version }}-alpine 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_pdns.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-pdns-mysql-fedora.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-mysql fedora 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-fedora-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS mysql 37 | id: docker_build_pdns 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-mysql 41 | file: ./pdns-mysql/Dockerfile 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-mysql:${{ steps.vars.outputs.version }} 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_pdns.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-pdns-pgsql-alpine.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-pgsql alpine 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-alpine-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS pgsql 37 | id: docker_build_pdns 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-pgsql 41 | file: ./pdns-pgsql/Dockerfile.alpine 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:${{ steps.vars.outputs.version }}-alpine 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_pdns.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-pdns-pgsql-fedora.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-pgsql fedora 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-fedora-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS pgsql 37 | id: docker_build_pdns 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-pgsql 41 | file: ./pdns-pgsql/Dockerfile 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:${{ steps.vars.outputs.version }} 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_pdns.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-recursor-alpine.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-recursor alpine 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-recursor-alpine-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS Recursor 37 | id: docker_build_recursor 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-recursor 41 | file: ./pdns-recursor/Dockerfile.alpine 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-recursor:${{ steps.vars.outputs.version }}-alpine 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_recursor.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image-tag-recursor-fedora.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI pdns-recursor fedora 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'pdns-recursor-fedora-*' 7 | 8 | jobs: 9 | 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | 16 | - name: Check Out Repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | id: buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Login to Docker Hub 27 | uses: docker/login-action@v3 28 | with: 29 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 30 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 31 | 32 | - name: Set output 33 | id: vars 34 | run: echo ::set-output name=version::${GITHUB_REF##*-} 35 | 36 | - name: Build and push PDNS Recursor 37 | id: docker_build_recursor 38 | uses: docker/build-push-action@v5 39 | with: 40 | context: ./pdns-recursor 41 | file: ./pdns-recursor/Dockerfile 42 | platforms: linux/amd64,linux/arm64 43 | builder: ${{ steps.buildx.outputs.name }} 44 | push: true 45 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-recursor:${{ steps.vars.outputs.version }} 46 | 47 | - name: Image digest 48 | run: echo ${{ steps.docker_build_recursor.outputs.digest }} 49 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ master ] 7 | 8 | jobs: 9 | 10 | build-recursor-latest: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Check Out Repo 14 | uses: actions/checkout@v4 15 | - name: Set up QEMU 16 | uses: docker/setup-qemu-action@v3 17 | - name: Set up Docker Buildx 18 | id: buildx 19 | uses: docker/setup-buildx-action@v3 20 | - name: Login to Docker Hub 21 | uses: docker/login-action@v3 22 | with: 23 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 24 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 25 | - name: Build and push PDNS Recursor latest 26 | id: docker_build_recursor_latest 27 | uses: docker/build-push-action@v5 28 | with: 29 | context: ./pdns-recursor 30 | file: ./pdns-recursor/Dockerfile 31 | platforms: linux/amd64,linux/arm64 32 | builder: ${{ steps.buildx.outputs.name }} 33 | push: true 34 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-recursor:latest 35 | - name: Image digest 36 | run: echo ${{ steps.docker_build_recursor_latest.outputs.digest }} 37 | 38 | build-recursor-alpine: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Check Out Repo 42 | uses: actions/checkout@v4 43 | - name: Set up QEMU 44 | uses: docker/setup-qemu-action@v3 45 | - name: Set up Docker Buildx 46 | id: buildx 47 | uses: docker/setup-buildx-action@v3 48 | - name: Login to Docker Hub 49 | uses: docker/login-action@v3 50 | with: 51 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 52 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 53 | - name: Build and push PDNS Recursor alpine 54 | id: docker_build_recursor_alpine 55 | uses: docker/build-push-action@v5 56 | with: 57 | context: ./pdns-recursor 58 | file: ./pdns-recursor/Dockerfile.alpine 59 | platforms: linux/amd64,linux/arm64 60 | builder: ${{ steps.buildx.outputs.name }} 61 | push: true 62 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-recursor:alpine 63 | - name: Image digest 64 | run: echo ${{ steps.docker_build_recursor_alpine.outputs.digest }} 65 | 66 | build-pdns-mysql-latest: 67 | runs-on: ubuntu-latest 68 | steps: 69 | - name: Check Out Repo 70 | uses: actions/checkout@v4 71 | - name: Set up QEMU 72 | uses: docker/setup-qemu-action@v3 73 | - name: Set up Docker Buildx 74 | id: buildx 75 | uses: docker/setup-buildx-action@v3 76 | - name: Login to Docker Hub 77 | uses: docker/login-action@v3 78 | with: 79 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 80 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 81 | - name: Build and push PDNS mysql latest 82 | id: docker_build_pdns_mysql_latest 83 | uses: docker/build-push-action@v5 84 | with: 85 | context: ./pdns-mysql 86 | file: ./pdns-mysql/Dockerfile 87 | platforms: linux/amd64,linux/arm64 88 | builder: ${{ steps.buildx.outputs.name }} 89 | push: true 90 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-mysql:latest 91 | - name: Image digest 92 | run: echo ${{ steps.docker_build_pdns_mysql_latest.outputs.digest }} 93 | 94 | build-pdns-mysql-alpine: 95 | runs-on: ubuntu-latest 96 | steps: 97 | - name: Check Out Repo 98 | uses: actions/checkout@v4 99 | - name: Set up QEMU 100 | uses: docker/setup-qemu-action@v3 101 | - name: Set up Docker Buildx 102 | id: buildx 103 | uses: docker/setup-buildx-action@v3 104 | - name: Login to Docker Hub 105 | uses: docker/login-action@v3 106 | with: 107 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 108 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 109 | - name: Build and push PDNS mysql alpine 110 | id: docker_build_pdns_mysql_alpine 111 | uses: docker/build-push-action@v5 112 | with: 113 | context: ./pdns-mysql 114 | file: ./pdns-mysql/Dockerfile.alpine 115 | platforms: linux/amd64,linux/arm64 116 | builder: ${{ steps.buildx.outputs.name }} 117 | push: true 118 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-mysql:alpine 119 | - name: Image digest 120 | run: echo ${{ steps.docker_build_pdns_mysql_alpine.outputs.digest }} 121 | 122 | build-pdns-pgsql-latest: 123 | runs-on: ubuntu-latest 124 | steps: 125 | - name: Check Out Repo 126 | uses: actions/checkout@v4 127 | - name: Set up QEMU 128 | uses: docker/setup-qemu-action@v3 129 | - name: Set up Docker Buildx 130 | id: buildx 131 | uses: docker/setup-buildx-action@v3 132 | - name: Login to Docker Hub 133 | uses: docker/login-action@v3 134 | with: 135 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 136 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 137 | - name: Build and push PDNS pgsql latest 138 | id: docker_build_pdns_pgsql_latest 139 | uses: docker/build-push-action@v5 140 | with: 141 | context: ./pdns-pgsql 142 | file: ./pdns-pgsql/Dockerfile 143 | platforms: linux/amd64,linux/arm64 144 | builder: ${{ steps.buildx.outputs.name }} 145 | push: true 146 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:latest 147 | - name: Image digest 148 | run: echo ${{ steps.docker_build_pdns_pgsql_latest.outputs.digest }} 149 | 150 | build-pdns-pgsql-alpine: 151 | runs-on: ubuntu-latest 152 | steps: 153 | - name: Check Out Repo 154 | uses: actions/checkout@v4 155 | - name: Set up QEMU 156 | uses: docker/setup-qemu-action@v3 157 | - name: Set up Docker Buildx 158 | id: buildx 159 | uses: docker/setup-buildx-action@v3 160 | - name: Login to Docker Hub 161 | uses: docker/login-action@v3 162 | with: 163 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 164 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 165 | - name: Build and push PDNS pgsql alpine 166 | id: docker_build_pdns_pgsql_alpine 167 | uses: docker/build-push-action@v5 168 | with: 169 | context: ./pdns-pgsql 170 | file: ./pdns-pgsql/Dockerfile.alpine 171 | platforms: linux/amd64,linux/arm64 172 | builder: ${{ steps.buildx.outputs.name }} 173 | push: true 174 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-pgsql:alpine 175 | - name: Image digest 176 | run: echo ${{ steps.docker_build_pdns_pgsql_alpine.outputs.digest }} 177 | 178 | build-pdns-admin: 179 | runs-on: ubuntu-latest 180 | steps: 181 | - name: Check Out Repo 182 | uses: actions/checkout@v4 183 | - name: Set up QEMU 184 | uses: docker/setup-qemu-action@v3 185 | - name: Set up Docker Buildx 186 | id: buildx 187 | uses: docker/setup-buildx-action@v3 188 | - name: Login to Docker Hub 189 | uses: docker/login-action@v3 190 | with: 191 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 192 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 193 | - name: Build and push pdns admin 194 | id: docker_build_pdns_admin 195 | uses: docker/build-push-action@v5 196 | with: 197 | context: ./pdns-admin 198 | file: ./pdns-admin/Dockerfile 199 | platforms: linux/amd64,linux/arm64 200 | builder: ${{ steps.buildx.outputs.name }} 201 | push: true 202 | tags: | 203 | ${{ secrets.DOCKER_HUB_USERNAME }}/pdns-admin:latest 204 | - name: Image digest 205 | run: echo ${{ steps.docker_build_pdns_admin.outputs.digest }} 206 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | snm5jkn8h@mozmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Peter Schiffer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerDNS Docker Images 2 | 3 | This repository contains the following Docker images - pdns-mysql, pdns-pgsql, pdns-recursor and pdns-admin. Image **pdns-mysql** contains completely configurable [PowerDNS 4.x server](https://doc.powerdns.com/authoritative/) with mysql backend (without mysql server). Image **pdns-pgsql** contains completely configurable [PowerDNS 4.x server](https://doc.powerdns.com/authoritative/) with postgres backend (without postgres server). Image **pdns-recursor** contains completely configurable [PowerDNS 5.x recursor](https://doc.powerdns.com/recursor/). Image **pdns-admin** contains fronted (Caddy) and backend (uWSGI) for the [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, which is written in Flask and used for managing PowerDNS servers. 4 | 5 | The pdns-mysql, pdns-pgsql and pdns-recursor images have also the `alpine` tag, thanks to @PoppyPop. 6 | 7 | All images are available on Docker Hub: 8 | 9 | https://hub.docker.com/r/pschiffe/pdns-mysql/ 10 | 11 | https://hub.docker.com/r/pschiffe/pdns-pgsql/ 12 | 13 | https://hub.docker.com/r/pschiffe/pdns-recursor/ 14 | 15 | https://hub.docker.com/r/pschiffe/pdns-admin/ 16 | 17 | Source GitHub repository: https://github.com/pschiffe/docker-pdns 18 | 19 | --- 20 | [![Static Badge](https://img.shields.io/badge/GitHub_Sponsors-grey?logo=github)](https://github.com/sponsors/pschiffe) [![Static Badge](https://img.shields.io/badge/paypal.me-grey?logo=paypal)](https://www.paypal.com/paypalme/pschiffe) 21 | 22 | If this project is useful to you, please consider sponsoring me to support maintenance and further development. Thank you! 23 | 24 | ## pdns-mysql 25 | 26 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-mysql/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-mysql/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-mysql) 27 | 28 | https://hub.docker.com/r/pschiffe/pdns-mysql/ 29 | 30 | Docker image with [PowerDNS 4.x server](https://doc.powerdns.com/authoritative/) and mysql backend. Requires external mysql server. Env vars for mysql configuration: 31 | ``` 32 | (name=default value) 33 | 34 | PDNS_gmysql_host=mysql 35 | PDNS_gmysql_port=3306 36 | PDNS_gmysql_user=root 37 | PDNS_gmysql_password=powerdns 38 | PDNS_gmysql_dbname=powerdns 39 | ``` 40 | 41 | If linked with the official [mariadb](https://hub.docker.com/_/mariadb/) image using the alias `mysql`, the connection can be automatically configured, eliminating the need to specify any of the above. The DB is automatically initialized if tables are missing. 42 | 43 | The PowerDNS server is configurable via env vars. Every variable starting with `PDNS_` will be inserted into `/etc/pdns/pdns.conf` conf file in the following way: prefix `PDNS_` will be stripped away and every `_` will be replaced with `-`. For example, from the above mysql config, `PDNS_gmysql_host=mysql` will became `gmysql-host=mysql` in `/etc/pdns/pdns.conf` file. This way, you can configure PowerDNS server in any way you need within a `docker run` command. 44 | 45 | The `SUPERMASTER_IPS` env var is also supported, which can be used to configure supermasters for a slave DNS server. [Docs](https://doc.powerdns.com/authoritative/modes-of-operation.html#autoprimary-automatic-provisioning-of-secondaries). Multiple IP addresses separated by spaces should work. 46 | 47 | You can find all the available settings [here](https://doc.powerdns.com/authoritative/settings.html). 48 | 49 | ### Examples 50 | 51 | Example of a master server with the API enabled and one slave server configured: 52 | ``` 53 | docker run -d -p 53:53 -p 53:53/udp --name pdns-master \ 54 | --hostname ns1.example.com --link mariadb:mysql \ 55 | -e PDNS_primary=yes \ 56 | -e PDNS_api=yes \ 57 | -e PDNS_api_key=secret \ 58 | -e PDNS_webserver=yes \ 59 | -e PDNS_webserver_address=0.0.0.0 \ 60 | -e PDNS_webserver_password=secret2 \ 61 | -e PDNS_version_string=anonymous \ 62 | -e PDNS_default_ttl=1500 \ 63 | -e PDNS_allow_axfr_ips=172.5.0.21 \ 64 | -e PDNS_only_notify=172.5.0.21 \ 65 | pschiffe/pdns-mysql 66 | ``` 67 | 68 | Example of a slave server with a supermaster: 69 | ``` 70 | docker run -d -p 53:53 -p 53:53/udp --name pdns-slave \ 71 | --hostname ns2.example.com --link mariadb:mysql \ 72 | -e PDNS_gmysql_dbname=powerdnsslave \ 73 | -e PDNS_secondary=yes \ 74 | -e PDNS_autosecondary=yes \ 75 | -e PDNS_version_string=anonymous \ 76 | -e PDNS_disable_axfr=yes \ 77 | -e PDNS_allow_notify_from=172.5.0.20 \ 78 | -e SUPERMASTER_IPS=172.5.0.20 \ 79 | pschiffe/pdns-mysql 80 | ``` 81 | 82 | ## pdns-pgsql 83 | 84 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-pgsql/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-pgsql/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-pgsql) 85 | 86 | https://hub.docker.com/r/pschiffe/pdns-pgsql/ 87 | 88 | Docker image with [PowerDNS 4.x server](https://doc.powerdns.com/authoritative/) and postgres backend. Requires external postgres server. Env vars for pgsql configuration: 89 | ``` 90 | (name=default value) 91 | 92 | PDNS_gpgsql_host=pgsql 93 | PDNS_gpgsql_port=5432 94 | PDNS_gpgsql_user=postgres 95 | PDNS_gpgsql_password=powerdns 96 | PDNS_gpgsql_dbname=powerdns 97 | ``` 98 | 99 | If linked with the official [postgres](https://hub.docker.com/_/postgres) image using the alias `pgsql`, the connection can be automatically configured, eliminating the need to specify any of the above. The DB is automatically initialized if tables are missing. 100 | 101 | The PowerDNS server is configurable via env vars. Every variable starting with `PDNS_` will be inserted into `/etc/pdns/pdns.conf` conf file in the following way: prefix `PDNS_` will be stripped away and every `_` will be replaced with `-`. For example, from the above pgsql config, `PDNS_gpgsql_host=pgsql` will became `gpgsql-host=pgsql` in `/etc/pdns/pdns.conf` file. This way, you can configure PowerDNS server in any way you need within a `docker run` command. 102 | 103 | The `SUPERMASTER_IPS` env var is also supported, which can be used to configure supermasters for a slave DNS server. [Docs](https://doc.powerdns.com/authoritative/modes-of-operation.html#autoprimary-automatic-provisioning-of-secondaries). Multiple IP addresses separated by spaces should work. 104 | 105 | You can find all the available settings [here](https://doc.powerdns.com/authoritative/settings.html). 106 | 107 | ### Examples 108 | 109 | Example of a master server with the API enabled and one slave server configured: 110 | ``` 111 | docker run -d -p 53:53 -p 53:53/udp --name pdns-master \ 112 | --hostname ns1.example.com --link postgres:pgsql \ 113 | -e PDNS_primary=yes \ 114 | -e PDNS_api=yes \ 115 | -e PDNS_api_key=secret \ 116 | -e PDNS_webserver=yes \ 117 | -e PDNS_webserver_address=0.0.0.0 \ 118 | -e PDNS_webserver_password=secret2 \ 119 | -e PDNS_version_string=anonymous \ 120 | -e PDNS_default_ttl=1500 \ 121 | -e PDNS_allow_axfr_ips=172.5.0.21 \ 122 | -e PDNS_only_notify=172.5.0.21 \ 123 | pschiffe/pdns-pgsql 124 | ``` 125 | 126 | Example of a slave server with a supermaster: 127 | ``` 128 | docker run -d -p 53:53 -p 53:53/udp --name pdns-slave \ 129 | --hostname ns2.example.com --link postgres:pgsql \ 130 | -e PDNS_gpgsql_dbname=powerdnsslave \ 131 | -e PDNS_secondary=yes \ 132 | -e PDNS_autosecondary=yes \ 133 | -e PDNS_version_string=anonymous \ 134 | -e PDNS_disable_axfr=yes \ 135 | -e PDNS_allow_notify_from=172.5.0.20 \ 136 | -e SUPERMASTER_IPS=172.5.0.20 \ 137 | pschiffe/pdns-pgsql 138 | ``` 139 | 140 | ## pdns-recursor 141 | 142 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-recursor/latest?label=latest) ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-recursor/alpine?label=alpine) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-recursor) 143 | 144 | https://hub.docker.com/r/pschiffe/pdns-recursor/ 145 | 146 | Docker image with [PowerDNS 5.x recursor](https://doc.powerdns.com/recursor/). 147 | 148 | PowerDNS recursor is configurable via env vars. Every variable starting with `PDNS_` will be inserted into `/etc/pdns/recursor.conf` conf file in the following way: prefix `PDNS_` will be stripped away and every `_` will be replaced with `-`. For example, from the above mysql config, `PDNS_gmysql_host=mysql` will became `gmysql-host=mysql` in `/etc/pdns/recursor.conf` file. This way, you can configure PowerDNS recursor any way you need within a `docker run` command. 149 | 150 | You can find all available settings [here](https://doc.powerdns.com/recursor/settings.html). 151 | 152 | ### Example 153 | 154 | Recursor server with API enabled: 155 | ``` 156 | docker run -d -p 53:53 -p 53:53/udp --name pdns-recursor \ 157 | -e PDNS_api_key=secret \ 158 | -e PDNS_webserver=yes \ 159 | -e PDNS_webserver_address=0.0.0.0 \ 160 | -e PDNS_webserver_password=secret2 \ 161 | pschiffe/pdns-recursor 162 | ``` 163 | 164 | ## pdns-admin 165 | 166 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-admin/latest?label=latest) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-admin) 167 | 168 | https://hub.docker.com/r/pschiffe/pdns-admin/ 169 | 170 | Docker image with [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, written in Flask, for managing PowerDNS servers. It needs external mysql or postgres server. 171 | 172 | There is also an official image for the pdns-admin on [Docker Hub](https://hub.docker.com/r/powerdnsadmin/pda-legacy). That image contains only gunicorn process that handles both - static files and the python app. Image in this repo contains uWSGI server handling requests for python app and Caddy web server handling static files and optionally HTTPS with Let's Encrypt. 173 | 174 | Env vars for mysql configuration: 175 | ``` 176 | (name=default value) 177 | 178 | PDNS_ADMIN_SQLA_DB_HOST=mysql 179 | PDNS_ADMIN_SQLA_DB_PORT=3306 180 | PDNS_ADMIN_SQLA_DB_USER=root 181 | PDNS_ADMIN_SQLA_DB_PASSWORD=powerdnsadmin 182 | PDNS_ADMIN_SQLA_DB_NAME=powerdnsadmin 183 | ``` 184 | If linked with official [mariadb](https://hub.docker.com/_/mariadb/) image with alias `mysql`, the connection can be automatically configured, so you don't need to specify any of the above. 185 | 186 | Env vars for pgsql configuration: 187 | ``` 188 | PDNS_ADMIN_SQLA_DB_TYPE=postgres 189 | PDNS_ADMIN_SQLA_DB_HOST=pgsql 190 | PDNS_ADMIN_SQLA_DB_PORT=5432 191 | PDNS_ADMIN_SQLA_DB_USER=postgres 192 | PDNS_ADMIN_SQLA_DB_PASSWORD=powerdnsadmin 193 | PDNS_ADMIN_SQLA_DB_NAME=powerdnsadmin 194 | ``` 195 | 196 | The DB is automatically initialized if tables are missing. 197 | 198 | Similar to the pdns-mysql, pdns-admin is also completely configurable via env vars. Prefix in this case is `PDNS_ADMIN_`, configuration will be written to the `/opt/powerdns-admin/powerdnsadmin/default_config.py` file. 199 | 200 | ### Connecting to the PowerDNS server 201 | 202 | For the pdns-admin to make sense, it needs a PowerDNS server to manage. The PowerDNS server needs to have exposed API (example configuration for PowerDNS 4.x): 203 | ``` 204 | api=yes 205 | api-key=secret 206 | webserver=yes 207 | webserver-address=0.0.0.0 208 | webserver-allow-from=172.5.0.0/16 209 | ``` 210 | 211 | And again, PowerDNS connection is configured via env vars (it needs url of the PowerDNS server, api key and a version of PowerDNS server, for example 4.0): 212 | ``` 213 | (name=default value) 214 | 215 | PDNS_API_URL="http://pdns:8081/" 216 | PDNS_API_KEY="" 217 | PDNS_VERSION="" 218 | ``` 219 | 220 | If this container is linked with pdns-mysql from this repo with alias `pdns`, it will be configured automatically and none of the env vars from above are needed to be specified. 221 | 222 | ### PowerDNS Admin API keys and SALT 223 | 224 | In order to be able to generate an API Key, you will need to specify the SALT via `PDNS_ADMIN_SALT` env var. This is a secret value, which can be generated via command: 225 | ``` 226 | python3 -c 'import bcrypt; print(bcrypt.gensalt().decode("utf-8"));' 227 | ``` 228 | Example value looks like `$2b$12$xxxxxxxxxxxxxxxxxxxxxx` - remember that when using docker-compose, literal `$` must be specified as `$$`. 229 | 230 | ### SSL with Let's Encrypt 231 | 232 | Included Caddy server can optionally handle HTTPS with certificates from Let's Encrypt. To make this work, add `SSL_MAIN_DOMAIN` env var with your primary domain for HTTPS. The `SSL_EXTRA_DOMAINS` env var can contain list of comma-separated domains that will be redirected to the `SSL_MAIN_DOMAIN`. Public DNS must be properly configured and pdns-admin ports `8080`, `8443` and `8443/udp` must be exposed as `80`, `443` and `443/udp` (`443/udp` is for HTTP/3 traffic). 233 | 234 | Finally, make the `/var/lib/caddy` dir inside of the pdns-admin container persistent - that's where the generated certificates will be stored. 235 | 236 | ### Persistent data 237 | 238 | There is also a directory with user uploads which should be persistent: `/opt/powerdns-admin/upload` 239 | 240 | ### Examples 241 | 242 | When linked with pdns-mysql from this repo: 243 | ``` 244 | docker run -d -p 8080:8080 --name pdns-admin \ 245 | --link mariadb:mysql --link pdns-master:pdns \ 246 | -v pdns-admin-upload:/opt/powerdns-admin/upload \ 247 | pschiffe/pdns-admin 248 | ``` 249 | 250 | The same with HTTPS: 251 | ``` 252 | docker run -d -p 80:8080 -p 443:8443 -p 443:8443/udp --name pdns-admin \ 253 | --link mariadb:mysql --link pdns-master:pdns \ 254 | -v pdns-admin-caddy:/var/lib/caddy \ 255 | -v pdns-admin-upload:/opt/powerdns-admin/upload \ 256 | -e SSL_MAIN_DOMAIN=www.pdns-admin.com \ 257 | -e SSL_EXTRA_DOMAINS=pdns-admin.com,pdns-admin.eu \ 258 | pschiffe/pdns-admin 259 | ``` 260 | 261 | ## Docker Compose 262 | 263 | Included docker compose files contain example configuration of how to use these containers: 264 | ``` 265 | docker-compose -f docker-compose-mysql.yml up -d 266 | ``` 267 | 268 | ## Ansible playbook 269 | 270 | Included ansible playbooks can be used to build and run the containers from this repo. Run it with: 271 | ``` 272 | ansible-playbook ansible-playbook-mysql.yml 273 | ``` 274 | -------------------------------------------------------------------------------- /ansible-playbook-mysql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PDNS mysql 3 | hosts: localhost 4 | vars: 5 | pdns_master_ip: 172.5.0.20 6 | pdns_slave_ip: 172.5.0.21 7 | wipe: false 8 | c_state: '{{ "absent" if wipe | bool else "started" }}' 9 | i_state: present 10 | alpine: false 11 | tasks: 12 | - name: Create docker network 13 | community.docker.docker_network: 14 | name: pdns-net-mysql 15 | state: present 16 | ipam_config: 17 | - subnet: '172.5.0.0/16' 18 | gateway: '172.5.0.1' 19 | tags: 20 | - pdns 21 | - pdns-admin 22 | - pdns-recursor 23 | 24 | - name: Build pdns recursor 25 | community.docker.docker_image: 26 | name: pschiffe/pdns-recursor 27 | state: '{{ i_state }}' 28 | source: build 29 | force_source: true 30 | build: 31 | pull: true 32 | path: ./pdns-recursor 33 | tags: 34 | - pdns-recursor 35 | 36 | - name: Build pdns recursor alpine version 37 | community.docker.docker_image: 38 | name: pschiffe/pdns-recursor 39 | tag: alpine 40 | state: '{{ i_state }}' 41 | source: build 42 | force_source: true 43 | build: 44 | pull: true 45 | path: ./pdns-recursor 46 | dockerfile: Dockerfile.alpine 47 | tags: 48 | - pdns-recursor 49 | 50 | - name: PDNS recursor 51 | community.docker.docker_container: 52 | name: pdns-recursor-mysql 53 | image: pschiffe/pdns-recursor:{{ "alpine" if alpine | bool else "latest" }} 54 | state: '{{ c_state }}' 55 | networks: 56 | - name: pdns-net-mysql 57 | volumes: 58 | - /etc/localtime:/etc/localtime:ro 59 | ulimits: 60 | - 'nofile:10000:10000' 61 | tags: 62 | - pdns-recursor 63 | 64 | - name: DB 65 | community.docker.docker_container: 66 | name: pdns-mariadb 67 | image: mariadb:11-ubi 68 | pull: true 69 | state: '{{ c_state }}' 70 | networks: 71 | - name: pdns-net-mysql 72 | aliases: 73 | - db 74 | - mysql 75 | volumes: 76 | - /etc/localtime:/etc/localtime:ro 77 | - pdns-mariadb-volume:/var/lib/mysql:Z 78 | env: 79 | MYSQL_ROOT_PASSWORD: 'my-secret-pw' 80 | healthcheck: 81 | test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'] 82 | timeout: 10s 83 | retries: 5 84 | tags: 85 | - db 86 | 87 | - name: Phpmyadmin 88 | community.docker.docker_container: 89 | name: pdns-phpmyadmin 90 | image: phpmyadmin:5 91 | pull: true 92 | state: '{{ c_state }}' 93 | networks: 94 | - name: pdns-net-mysql 95 | published_ports: 96 | - '8888:80' 97 | volumes: 98 | - /etc/localtime:/etc/localtime:ro 99 | healthcheck: 100 | test: ['CMD', 'curl', '-fsSL', 'http://127.0.0.1:80'] 101 | timeout: 10s 102 | retries: 5 103 | tags: 104 | - db 105 | 106 | - name: Build pdns mysql 107 | community.docker.docker_image: 108 | name: pschiffe/pdns-mysql 109 | state: '{{ i_state }}' 110 | source: build 111 | force_source: true 112 | build: 113 | pull: true 114 | path: ./pdns-mysql 115 | tags: 116 | - pdns 117 | 118 | - name: Build pdns mysql alpine version 119 | community.docker.docker_image: 120 | name: pschiffe/pdns-mysql 121 | tag: alpine 122 | state: '{{ i_state }}' 123 | source: build 124 | force_source: true 125 | build: 126 | pull: true 127 | path: ./pdns-mysql 128 | dockerfile: Dockerfile.alpine 129 | tags: 130 | - pdns 131 | 132 | - name: PDNS mysql master 133 | community.docker.docker_container: 134 | name: pdns-mysql 135 | image: pschiffe/pdns-mysql:{{ "alpine" if alpine | bool else "latest" }} 136 | state: '{{ c_state }}' 137 | hostname: ns1.example.com 138 | networks: 139 | - name: pdns-net-mysql 140 | ipv4_address: '{{ pdns_master_ip }}' 141 | aliases: 142 | - pdns 143 | etc_hosts: 144 | ns1.example.com: '{{ pdns_master_ip }}' 145 | ns2.example.com: '{{ pdns_slave_ip }}' 146 | volumes: 147 | - /etc/localtime:/etc/localtime:ro 148 | env: 149 | PDNS_gmysql_password: 'my-secret-pw' 150 | PDNS_primary: 'yes' 151 | PDNS_api: 'yes' 152 | PDNS_api_key: 'secret' 153 | PDNS_webserver: 'yes' 154 | PDNS_webserver_address: '0.0.0.0' 155 | PDNS_webserver_allow_from: '172.5.0.0/16' 156 | PDNS_version_string: 'anonymous' 157 | PDNS_default_ttl: '1500' 158 | PDNS_allow_axfr_ips: '{{ pdns_slave_ip }}' 159 | PDNS_only_notify: '{{ pdns_slave_ip }}' 160 | tags: 161 | - pdns 162 | 163 | - name: PDNS mysql slave 164 | community.docker.docker_container: 165 | name: pdns-mysql-slave 166 | image: pschiffe/pdns-mysql:{{ "alpine" if alpine | bool else "latest" }} 167 | state: '{{ c_state }}' 168 | hostname: ns2.example.com 169 | networks: 170 | - name: pdns-net-mysql 171 | ipv4_address: '{{ pdns_slave_ip }}' 172 | etc_hosts: 173 | ns1.example.com: '{{ pdns_master_ip }}' 174 | ns2.example.com: '{{ pdns_slave_ip }}' 175 | volumes: 176 | - /etc/localtime:/etc/localtime:ro 177 | env: 178 | PDNS_gmysql_dbname: 'powerdnsslave' 179 | PDNS_gmysql_password: 'my-secret-pw' 180 | PDNS_secondary: 'yes' 181 | PDNS_autosecondary: 'yes' 182 | PDNS_webserver: 'yes' 183 | PDNS_webserver_address: '0.0.0.0' 184 | PDNS_webserver_allow_from: '172.5.0.0/16' 185 | PDNS_version_string: 'anonymous' 186 | PDNS_disable_axfr: 'yes' 187 | PDNS_allow_notify_from: '{{ pdns_master_ip }}' 188 | SUPERMASTER_IPS: '{{ pdns_master_ip }}' 189 | tags: 190 | - pdns 191 | 192 | - name: Build pdns-admin 193 | community.docker.docker_image: 194 | name: pschiffe/pdns-admin 195 | tag: latest 196 | state: '{{ i_state }}' 197 | source: build 198 | force_source: true 199 | build: 200 | pull: true 201 | path: ./pdns-admin 202 | tags: 203 | - pdns-admin 204 | 205 | - name: PDNS-admin 206 | community.docker.docker_container: 207 | name: pdns-admin-mysql 208 | image: pschiffe/pdns-admin 209 | state: '{{ c_state }}' 210 | networks: 211 | - name: pdns-net-mysql 212 | aliases: 213 | - pdns-admin 214 | published_ports: 215 | - '8889:8080' 216 | volumes: 217 | - /etc/localtime:/etc/localtime:ro 218 | env: 219 | PDNS_ADMIN_SQLA_DB_PASSWORD: 'my-secret-pw' 220 | PDNS_VERSION: '4.9' 221 | PDNS_API_KEY: 'secret' 222 | tags: 223 | - pdns-admin 224 | 225 | - name: Remove docker volume 226 | community.docker.docker_volume: 227 | name: pdns-mariadb-volume 228 | state: absent 229 | when: wipe | bool 230 | 231 | - name: Remove network 232 | community.docker.docker_network: 233 | name: pdns-net-mysql 234 | state: absent 235 | when: wipe | bool 236 | -------------------------------------------------------------------------------- /ansible-playbook-pgsql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PDNS pgsql 3 | hosts: localhost 4 | vars: 5 | pdns_master_ip: 172.7.0.20 6 | pdns_slave_ip: 172.7.0.21 7 | wipe: false 8 | c_state: '{{ "absent" if wipe | bool else "started" }}' 9 | i_state: present 10 | alpine: false 11 | tasks: 12 | - name: Create docker network 13 | community.docker.docker_network: 14 | name: pdns-net-pgsql 15 | state: present 16 | ipam_config: 17 | - subnet: '172.7.0.0/16' 18 | gateway: '172.7.0.1' 19 | tags: 20 | - pdns 21 | - pdns-admin 22 | - pdns-recursor 23 | 24 | - name: Build pdns recursor 25 | community.docker.docker_image: 26 | name: pschiffe/pdns-recursor 27 | state: '{{ i_state }}' 28 | source: build 29 | force_source: true 30 | build: 31 | pull: true 32 | path: ./pdns-recursor 33 | tags: 34 | - pdns-recursor 35 | 36 | - name: Build pdns recursor alpine version 37 | community.docker.docker_image: 38 | name: pschiffe/pdns-recursor 39 | tag: alpine 40 | state: '{{ i_state }}' 41 | source: build 42 | force_source: true 43 | build: 44 | pull: true 45 | path: ./pdns-recursor 46 | dockerfile: Dockerfile.alpine 47 | tags: 48 | - pdns-recursor 49 | 50 | - name: PDNS recursor 51 | community.docker.docker_container: 52 | name: pdns-recursor-pgsql 53 | image: pschiffe/pdns-recursor:{{ "alpine" if alpine | bool else "latest" }} 54 | state: '{{ c_state }}' 55 | networks: 56 | - name: pdns-net-pgsql 57 | volumes: 58 | - /etc/localtime:/etc/localtime:ro 59 | ulimits: 60 | - 'nofile:10000:10000' 61 | tags: 62 | - pdns-recursor 63 | 64 | - name: DB 65 | community.docker.docker_container: 66 | name: pdns-postgres 67 | image: postgres:16-alpine 68 | pull: true 69 | state: '{{ c_state }}' 70 | networks: 71 | - name: pdns-net-pgsql 72 | aliases: 73 | - db 74 | - pgsql 75 | volumes: 76 | - /etc/localtime:/etc/localtime:ro 77 | - pdns-postgres-volume:/var/lib/postgresql/data:Z 78 | env: 79 | POSTGRES_PASSWORD: 'my-secret-pw' 80 | healthcheck: 81 | test: ['CMD', 'pg_isready', '-U', 'postgres'] 82 | timeout: 10s 83 | retries: 5 84 | tags: 85 | - db 86 | 87 | - name: Adminer 88 | community.docker.docker_container: 89 | name: pdns-adminer 90 | image: adminer 91 | pull: true 92 | state: '{{ c_state }}' 93 | networks: 94 | - name: pdns-net-pgsql 95 | published_ports: 96 | - '7888:8080' 97 | volumes: 98 | - /etc/localtime:/etc/localtime:ro 99 | tags: 100 | - db 101 | 102 | - name: Build pdns pgsql 103 | community.docker.docker_image: 104 | name: pschiffe/pdns-pgsql 105 | state: '{{ i_state }}' 106 | source: build 107 | force_source: true 108 | build: 109 | pull: true 110 | path: ./pdns-pgsql 111 | tags: 112 | - pdns 113 | 114 | - name: Build pdns pgsql alpine version 115 | community.docker.docker_image: 116 | name: pschiffe/pdns-pgsql 117 | tag: alpine 118 | state: '{{ i_state }}' 119 | source: build 120 | force_source: true 121 | build: 122 | pull: true 123 | path: ./pdns-pgsql 124 | dockerfile: Dockerfile.alpine 125 | tags: 126 | - pdns 127 | 128 | - name: PDNS pgsql master 129 | community.docker.docker_container: 130 | name: pdns-pgsql 131 | image: pschiffe/pdns-pgsql:{{ "alpine" if alpine | bool else "latest" }} 132 | state: '{{ c_state }}' 133 | hostname: ns1.example.com 134 | networks: 135 | - name: pdns-net-pgsql 136 | ipv4_address: '{{ pdns_master_ip }}' 137 | aliases: 138 | - pdns 139 | etc_hosts: 140 | ns1.example.com: '{{ pdns_master_ip }}' 141 | ns2.example.com: '{{ pdns_slave_ip }}' 142 | volumes: 143 | - /etc/localtime:/etc/localtime:ro 144 | env: 145 | PDNS_gpgsql_password: 'my-secret-pw' 146 | PDNS_primary: 'yes' 147 | PDNS_api: 'yes' 148 | PDNS_api_key: 'secret' 149 | PDNS_webserver: 'yes' 150 | PDNS_webserver_address: '0.0.0.0' 151 | PDNS_webserver_allow_from: '172.7.0.0/16' 152 | PDNS_version_string: 'anonymous' 153 | PDNS_default_ttl: '1500' 154 | PDNS_allow_axfr_ips: '{{ pdns_slave_ip }}' 155 | PDNS_only_notify: '{{ pdns_slave_ip }}' 156 | tags: 157 | - pdns 158 | 159 | - name: PDNS pgsql slave 160 | community.docker.docker_container: 161 | name: pdns-pgsql-slave 162 | image: pschiffe/pdns-pgsql:{{ "alpine" if alpine | bool else "latest" }} 163 | state: '{{ c_state }}' 164 | hostname: ns2.example.com 165 | networks: 166 | - name: pdns-net-pgsql 167 | ipv4_address: '{{ pdns_slave_ip }}' 168 | etc_hosts: 169 | ns1.example.com: '{{ pdns_master_ip }}' 170 | ns2.example.com: '{{ pdns_slave_ip }}' 171 | volumes: 172 | - /etc/localtime:/etc/localtime:ro 173 | env: 174 | PDNS_gpgsql_dbname: 'powerdnsslave' 175 | PDNS_gpgsql_password: 'my-secret-pw' 176 | PDNS_secondary: 'yes' 177 | PDNS_autosecondary: 'yes' 178 | PDNS_webserver: 'yes' 179 | PDNS_webserver_address: '0.0.0.0' 180 | PDNS_webserver_allow_from: '172.7.0.0/16' 181 | PDNS_version_string: 'anonymous' 182 | PDNS_disable_axfr: 'yes' 183 | PDNS_allow_notify_from: '{{ pdns_master_ip }}' 184 | SUPERMASTER_IPS: '{{ pdns_master_ip }}' 185 | tags: 186 | - pdns 187 | 188 | - name: Build pdns-admin 189 | community.docker.docker_image: 190 | name: pschiffe/pdns-admin 191 | tag: latest 192 | state: '{{ i_state }}' 193 | source: build 194 | force_source: true 195 | build: 196 | pull: true 197 | path: ./pdns-admin 198 | tags: 199 | - pdns-admin 200 | 201 | - name: PDNS-admin pgsql 202 | community.docker.docker_container: 203 | name: pdns-admin-pgsql 204 | image: pschiffe/pdns-admin 205 | state: '{{ c_state }}' 206 | networks: 207 | - name: pdns-net-pgsql 208 | aliases: 209 | - pdns-admin 210 | published_ports: 211 | - '7889:8080' 212 | volumes: 213 | - /etc/localtime:/etc/localtime:ro 214 | env: 215 | PDNS_ADMIN_SQLA_DB_TYPE: 'postgres' 216 | PDNS_ADMIN_SQLA_DB_HOST: 'pgsql' 217 | PDNS_ADMIN_SQLA_DB_PORT: '5432' 218 | PDNS_ADMIN_SQLA_DB_USER: 'postgres' 219 | PDNS_ADMIN_SQLA_DB_PASSWORD: 'my-secret-pw' 220 | PDNS_VERSION: '4.9' 221 | PDNS_API_KEY: 'secret' 222 | tags: 223 | - pdns-admin 224 | 225 | - name: Remove docker volume 226 | community.docker.docker_volume: 227 | name: pdns-postgres-volume 228 | state: absent 229 | when: wipe | bool 230 | 231 | - name: Remove network 232 | community.docker.docker_network: 233 | name: pdns-net-pgsql 234 | state: absent 235 | when: wipe | bool 236 | -------------------------------------------------------------------------------- /deprecated/README.md: -------------------------------------------------------------------------------- 1 | # Deprecated PowerDNS-Admin Docker Images 2 | 3 | The **pdns-admin** docker image for the [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app was previously created as two images: **pdns-admin-static** and **pdns-admin-uwsgi** for fronted (nginx) and backend (uWSGI). These two images won't by updated anymore. 4 | 5 | https://hub.docker.com/r/pschiffe/pdns-admin-uwsgi/ 6 | 7 | https://hub.docker.com/r/pschiffe/pdns-admin-static/ 8 | 9 | ## pdns-admin-uwsgi 10 | 11 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-admin-uwsgi/latest?label=latest) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-admin-uwsgi) 12 | 13 | https://hub.docker.com/r/pschiffe/pdns-admin-uwsgi/ 14 | 15 | Docker image with backend of [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin) web app, written in Flask, for managing PowerDNS servers. This image contains the python part of the app running under uWSGI. It needs external mysql server. Env vars for mysql configuration: 16 | ``` 17 | (name=default value) 18 | 19 | PDNS_ADMIN_SQLA_DB_HOST="mysql" 20 | PDNS_ADMIN_SQLA_DB_PORT="3306" 21 | PDNS_ADMIN_SQLA_DB_USER="root" 22 | PDNS_ADMIN_SQLA_DB_PASSWORD="powerdnsadmin" 23 | PDNS_ADMIN_SQLA_DB_NAME="powerdnsadmin" 24 | ``` 25 | If linked with official [mariadb](https://hub.docker.com/_/mariadb/) image with alias `mysql`, the connection can be automatically configured, so you don't need to specify any of the above. Also, DB is automatically initialized if tables are missing. 26 | 27 | Similar to the pdns-mysql, pdns-admin is also completely configurable via env vars. Prefix in this case is `PDNS_ADMIN_`, configuration will be written to the `/opt/powerdns-admin/config.py` file. 28 | 29 | ### Connecting to the PowerDNS server 30 | 31 | For the pdns-admin to make sense, it needs a PowerDNS server to manage. The PowerDNS server needs to have exposed API (example configuration for PowerDNS 4.x): 32 | ``` 33 | api=yes 34 | api-key=secret 35 | webserver=yes 36 | webserver-address=0.0.0.0 37 | webserver-allow-from=172.5.0.0/16 38 | ``` 39 | 40 | And again, PowerDNS connection is configured via env vars (it needs url of the PowerDNS server, api key and a version of PowerDNS server, for example 4.0): 41 | ``` 42 | (name=default value) 43 | 44 | PDNS_API_URL="http://pdns:8081/" 45 | PDNS_API_KEY="" 46 | PDNS_VERSION="" 47 | ``` 48 | 49 | If this container is linked with pdns-mysql from this repo with alias `pdns`, it will be configured automatically and none of the env vars from above are needed to be specified. 50 | 51 | ### PowerDNS Admin API keys and SALT 52 | 53 | In order to be able to generate an API Key, you will need to specify the SALT via `PDNS_ADMIN_SALT` env var. This is a secret value, which can be generated via command: 54 | ``` 55 | python3 -c 'import bcrypt; print(bcrypt.gensalt().decode("utf-8"));' 56 | ``` 57 | Example value looks like `$2b$12$xxxxxxxxxxxxxxxxxxxxxx` - remember that when using docker-compose, literal `$` must be specified as `$$`. 58 | 59 | ### Persistent data 60 | 61 | There is a directory with user uploads which should be persistent: `/opt/powerdns-admin/upload` 62 | 63 | ### Example 64 | 65 | When linked with pdns-mysql from this repo and with LDAP auth: 66 | ``` 67 | docker run -d --name pdns-admin-uwsgi \ 68 | --link mariadb:mysql --link pdns-master:pdns \ 69 | -v pdns-admin-upload:/opt/powerdns-admin/upload \ 70 | pschiffe/pdns-admin-uwsgi 71 | ``` 72 | 73 | ## pdns-admin-static 74 | 75 | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/pschiffe/pdns-admin-static/latest?label=latest) ![Docker Pulls](https://img.shields.io/docker/pulls/pschiffe/pdns-admin-static) 76 | 77 | https://hub.docker.com/r/pschiffe/pdns-admin-static/ 78 | 79 | Fronted image with nginx and static files for [PowerDNS Admin](https://github.com/PowerDNS-Admin/PowerDNS-Admin). Exposes port 80 for connections, expects uWSGI backend image under `pdns-admin-uwsgi` alias. 80 | 81 | ### Example 82 | 83 | ``` 84 | docker run -d -p 8080:80 --name pdns-admin-static \ 85 | --link pdns-admin-uwsgi:pdns-admin-uwsgi \ 86 | pschiffe/pdns-admin-static 87 | ``` 88 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-base-ngoduykhanh/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rockylinux/rockylinux:9-ubi 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ 5 | && echo 'tsflags=nodocs' >> /etc/dnf/dnf.conf \ 6 | && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ 7 | && curl -fsSL -o /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \ 8 | && dnf module enable nodejs:20 \ 9 | && dnf install epel-release \ 10 | && dnf --refresh upgrade \ 11 | && dnf install \ 12 | npm \ 13 | python3-cffi \ 14 | python3-ldap \ 15 | python3-lxml \ 16 | python3-mysqlclient \ 17 | python3-pip \ 18 | python3-pyyaml \ 19 | python3-saml \ 20 | python3-xmlsec \ 21 | uwsgi \ 22 | yarn \ 23 | https://github.com/kha7iq/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ 24 | && dnf clean all 25 | 26 | RUN mkdir -p /opt/powerdns-admin \ 27 | && curl -fsSL https://github.com/PowerDNS-Admin/PowerDNS-Admin/archive/refs/tags/v0.4.1.tar.gz \ 28 | | tar -xzf - -C /opt/powerdns-admin --strip 1 \ 29 | && sed -i \ 30 | -e '/cffi/d' \ 31 | -e '/lxml/d' \ 32 | -e '/mysqlclient/d' \ 33 | -e '/psycopg2/d' \ 34 | -e '/python-ldap/d' \ 35 | -e '/python3-saml/d' \ 36 | -e '/PyYAML/d' \ 37 | /opt/powerdns-admin/requirements.txt \ 38 | && chown -R root: /opt/powerdns-admin 39 | 40 | WORKDIR /opt/powerdns-admin 41 | 42 | RUN pip3 install -r requirements.txt --no-cache-dir 43 | 44 | ENV FLASK_APP=/opt/powerdns-admin/powerdnsadmin/__init__.py 45 | 46 | COPY config.py.tpl / 47 | COPY run.py . 48 | 49 | RUN subvars --prefix 'PDNS_ADMIN_' < /config.py.tpl > /opt/powerdns-admin/config.py \ 50 | && sed -i '/SQLALCHEMY_DATABASE_URI/d' /opt/powerdns-admin/config.py 51 | 52 | RUN yarn install --pure-lockfile --production \ 53 | && yarn cache clean \ 54 | && flask assets build \ 55 | && chown -R uwsgi: /opt/powerdns-admin/powerdnsadmin/static/.webassets-cache 56 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-base-ngoduykhanh/config.py.tpl: -------------------------------------------------------------------------------- 1 | import os 2 | basedir = os.path.abspath(os.path.dirname(__file__)) 3 | 4 | ### BASIC APP CONFIG 5 | BIND_ADDRESS = '0.0.0.0' 6 | PORT = 9191 7 | HSTS_ENABLED = False 8 | 9 | # CAPTCHA Config 10 | CAPTCHA_ENABLE = True 11 | CAPTCHA_LENGTH = 6 12 | CAPTCHA_WIDTH = 160 13 | CAPTCHA_HEIGHT = 60 14 | CAPTCHA_SESSION_KEY = 'captcha_image' 15 | 16 | SESSION_TYPE = 'sqlalchemy' 17 | 18 | # SAML Authnetication 19 | SAML_ENABLED = False 20 | 21 | # Configuration from env vars 22 | {{ range $key, $value := match "PDNS_ADMIN_" -}} 23 | {{ $v := $value | trimAll "\"'\\" -}} 24 | {{ if or (eq $v "True" "False" "None" "0") (ne ($v | int) 0) -}} 25 | {{- $key | trimPrefix "PDNS_ADMIN_" }} = {{ $v }} 26 | {{ else -}} 27 | {{- $key | trimPrefix "PDNS_ADMIN_" }} = '{{ $v }}' 28 | {{ end -}} 29 | {{ end }} 30 | ### DATABASE CONFIG 31 | SQLALCHEMY_DATABASE_URI = 'mysql://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + ':' + str(SQLA_DB_PORT) + '/' + SQLA_DB_NAME 32 | SQLALCHEMY_TRACK_MODIFICATIONS = True 33 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-base-ngoduykhanh/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from powerdnsadmin import create_app 4 | 5 | app = create_app() 6 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-static-ngoduykhanh/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pschiffe/pdns-admin-base 2 | 3 | RUN dnf install nginx \ 4 | && dnf clean all 5 | 6 | COPY pdns-nginx.conf.tpl docker-entrypoint.sh / 7 | 8 | EXPOSE 80 9 | 10 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 11 | 12 | CMD [ "/usr/sbin/nginx", "-g", "daemon off;" ] 13 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-static-ngoduykhanh/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | subvars --prefix 'PDNS_ADMIN_STATIC_' < '/pdns-nginx.conf.tpl' > '/etc/nginx/nginx.conf' 6 | 7 | exec "$@" 8 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-static-ngoduykhanh/pdns-nginx.conf.tpl: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | error_log stderr; 4 | pid /run/nginx.pid; 5 | 6 | # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. 7 | include /usr/share/nginx/modules/*.conf; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /dev/stdout main; 19 | 20 | sendfile on; 21 | tcp_nopush on; 22 | tcp_nodelay on; 23 | keepalive_timeout 65; 24 | types_hash_max_size 4096; 25 | 26 | include /etc/nginx/mime.types; 27 | default_type application/octet-stream; 28 | 29 | # Load modular configuration files from the /etc/nginx/conf.d directory. 30 | # See http://nginx.org/en/docs/ngx_core_module.html#include 31 | # for more information. 32 | include /etc/nginx/conf.d/*.conf; 33 | 34 | server { 35 | listen 80 default_server; 36 | server_name _; 37 | 38 | location /static/ { 39 | alias /opt/powerdns-admin/powerdnsadmin/static/; 40 | } 41 | 42 | location / { 43 | try_files $uri @pdns_admin; 44 | } 45 | 46 | location @pdns_admin { 47 | include uwsgi_params; 48 | uwsgi_pass {{ .PDNS_ADMIN_STATIC_UWSGI_HOST | default "pdns-admin-uwsgi" }}:{{ .PDNS_ADMIN_STATIC_UWSGI_PORT | default 9494 }}; 49 | } 50 | 51 | error_page 404 /404.html; 52 | location = /40x.html { 53 | } 54 | 55 | error_page 500 502 503 504 /50x.html; 56 | location = /50x.html { 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-uwsgi-ngoduykhanh/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM pschiffe/pdns-admin-base 2 | 3 | RUN dnf install \ 4 | mariadb \ 5 | uwsgi-plugin-python3 \ 6 | && dnf clean all 7 | 8 | COPY docker-entrypoint.sh / 9 | COPY --chown=uwsgi:uwsgi pdns-admin.ini /etc/uwsgi.ini 10 | 11 | EXPOSE 9494 12 | 13 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 14 | 15 | CMD [ "/usr/sbin/uwsgi", "--ini", "/etc/uwsgi.ini" ] 16 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-uwsgi-ngoduykhanh/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | # Configure mysql env vars 6 | : "${PDNS_ADMIN_SQLA_DB_HOST:=${MYSQL_ENV_MYSQL_HOST:-mysql}}" 7 | : "${PDNS_ADMIN_SQLA_DB_PORT:=${MYSQL_ENV_MYSQL_PORT:-3306}}" 8 | : "${PDNS_ADMIN_SQLA_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" 9 | if [ "${PDNS_ADMIN_SQLA_DB_USER}" = "root" ]; then 10 | : "${PDNS_ADMIN_SQLA_DB_PASSWORD:=$MYSQL_ENV_MYSQL_ROOT_PASSWORD}" 11 | fi 12 | : "${PDNS_ADMIN_SQLA_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-powerdnsadmin}}" 13 | : "${PDNS_ADMIN_SQLA_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-powerdnsadmin}}" 14 | 15 | # Cleanup quotes from mysql env vars 16 | PDNS_ADMIN_SQLA_DB_HOST="${PDNS_ADMIN_SQLA_DB_HOST//[\'\"]}" 17 | PDNS_ADMIN_SQLA_DB_PORT="${PDNS_ADMIN_SQLA_DB_PORT//[\'\"]}" 18 | PDNS_ADMIN_SQLA_DB_USER="${PDNS_ADMIN_SQLA_DB_USER//[\'\"]}" 19 | PDNS_ADMIN_SQLA_DB_PASSWORD="${PDNS_ADMIN_SQLA_DB_PASSWORD//[\'\"]}" 20 | PDNS_ADMIN_SQLA_DB_NAME="${PDNS_ADMIN_SQLA_DB_NAME//[\'\"]}" 21 | 22 | export PDNS_ADMIN_SQLA_DB_HOST PDNS_ADMIN_SQLA_DB_PORT PDNS_ADMIN_SQLA_DB_USER PDNS_ADMIN_SQLA_DB_PASSWORD PDNS_ADMIN_SQLA_DB_NAME 23 | 24 | # Configure pdns server env vars 25 | : "${PDNS_API_URL:=http://${PDNS_ENV_PDNS_webserver_host:-pdns}:${PDNS_ENV_PDNS_webserver_port:-8081}/}" 26 | : "${PDNS_API_KEY:=${PDNS_ENV_PDNS_api_key:-}}" 27 | : "${PDNS_VERSION:=${PDNS_ENV_VERSION:-}}" 28 | 29 | # Generate secret key 30 | [ -f /root/secret-key ] || tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 32 > /root/secret-key || true 31 | PDNS_ADMIN_SECRET_KEY="$(cat /root/secret-key)" 32 | 33 | export PDNS_ADMIN_SECRET_KEY 34 | 35 | subvars --prefix 'PDNS_ADMIN_' < '/config.py.tpl' > '/opt/powerdns-admin/powerdnsadmin/default_config.py' 36 | 37 | # Initialize DB if needed 38 | MYSQL_COMMAND="mysql -h ${PDNS_ADMIN_SQLA_DB_HOST} -P ${PDNS_ADMIN_SQLA_DB_PORT} -u ${PDNS_ADMIN_SQLA_DB_USER} -p${PDNS_ADMIN_SQLA_DB_PASSWORD}" 39 | 40 | until $MYSQL_COMMAND -e ';' ; do 41 | >&2 echo 'MySQL is unavailable - sleeping' 42 | sleep 1 43 | done 44 | 45 | $MYSQL_COMMAND -e "CREATE DATABASE IF NOT EXISTS ${PDNS_ADMIN_SQLA_DB_NAME}" 46 | 47 | flask db upgrade 48 | 49 | # initial settings if not available in the DB 50 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_url', '${PDNS_API_URL//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_url') LIMIT 1;" 51 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_key', '${PDNS_API_KEY//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_key') LIMIT 1;" 52 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_version', '${PDNS_VERSION//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_version') LIMIT 1;" 53 | 54 | # update pdns api settings if env changed 55 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_API_URL//[\'\"]}' WHERE name='pdns_api_url';" 56 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_API_KEY//[\'\"]}' WHERE name='pdns_api_key';" 57 | $MYSQL_COMMAND "${PDNS_ADMIN_SQLA_DB_NAME}" -e "UPDATE setting SET value='${PDNS_VERSION//[\'\"]}' WHERE name='pdns_version';" 58 | 59 | mkdir -p /run/uwsgi 60 | chown uwsgi: /run/uwsgi 61 | 62 | exec "$@" 63 | -------------------------------------------------------------------------------- /deprecated/pdns-admin-uwsgi-ngoduykhanh/pdns-admin.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | strict = true 3 | master = true 4 | die-on-term = true 5 | need-app = true 6 | 7 | plugins = python3 8 | 9 | uid = uwsgi 10 | gid = uwsgi 11 | 12 | chdir = /opt/powerdns-admin 13 | pythonpath = /opt/powerdns-admin 14 | 15 | mount = /=run.py 16 | manage-script-name = true 17 | callable = app 18 | 19 | vacuum = true 20 | harakiri = 20 21 | buffer-size = 32768 22 | post-buffering = 8192 23 | socket = 0.0.0.0:9494 24 | pidfile = /run/uwsgi/%n.pid 25 | 26 | enable-threads = true 27 | -------------------------------------------------------------------------------- /docker-compose-mysql-ipv6.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | pdns-recursor-mysql: 4 | image: pschiffe/pdns-recursor:${RECURSOR_TAG:-latest} 5 | networks: 6 | pdns-mysql: 7 | ipv6_address: ${NETWORK_IPV6_PREFIX}::7 8 | volumes: 9 | - /etc/localtime:/etc/localtime:ro 10 | ulimits: 11 | nofile: 12 | soft: 10000 13 | hard: 10000 14 | 15 | mariadb: 16 | image: mariadb:11-ubi 17 | networks: 18 | pdns-mysql: 19 | aliases: 20 | - db 21 | - mysql 22 | ipv6_address: ${NETWORK_IPV6_PREFIX}::2 23 | volumes: 24 | - /etc/localtime:/etc/localtime:ro 25 | - mariadb:/var/lib/mysql:Z 26 | environment: 27 | - MYSQL_ROOT_PASSWORD=my-secret-pw 28 | healthcheck: 29 | test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'] 30 | timeout: 10s 31 | retries: 5 32 | 33 | phpmyadmin: 34 | image: phpmyadmin:5 35 | networks: 36 | pdns-mysql: 37 | ipv6_address: ${NETWORK_IPV6_PREFIX}::3 38 | ports: 39 | - '8988:80' 40 | volumes: 41 | - /etc/localtime:/etc/localtime:ro 42 | healthcheck: 43 | test: ['CMD', 'curl', '-fsSL', 'http://127.0.0.1:80'] 44 | timeout: 10s 45 | retries: 5 46 | 47 | pdns-mysql-master: 48 | image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} 49 | hostname: ns1.example.com 50 | networks: 51 | pdns-mysql: 52 | ipv6_address: ${NETWORK_IPV6_PREFIX}::4 53 | aliases: 54 | - pdns 55 | extra_hosts: 56 | - 'ns1.example.com:172.6.0.20' 57 | - 'ns2.example.com:172.6.0.21' 58 | volumes: 59 | - /etc/localtime:/etc/localtime:ro 60 | environment: 61 | - PDNS_gmysql_password=my-secret-pw 62 | - PDNS_primary=yes 63 | - PDNS_api=yes 64 | - PDNS_api_key=secret 65 | - PDNS_webserver=yes 66 | - PDNS_webserver_address=0.0.0.0 67 | - PDNS_webserver_allow_from=${NETWORK_IPV6_PREFIX}::/${NETWORK_IPV6_PREFIX_LENGTH} 68 | - PDNS_version_string=anonymous 69 | - PDNS_default_ttl=1500 70 | - PDNS_allow_axfr_ips=${NETWORK_IPV6_PREFIX}::5 71 | - PDNS_only_notify=${NETWORK_IPV6_PREFIX}::5 72 | depends_on: 73 | - mariadb 74 | 75 | pdns-mysql-slave: 76 | image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} 77 | hostname: ns2.example.com 78 | networks: 79 | pdns-mysql: 80 | ipv6_address: ${NETWORK_IPV6_PREFIX}::5 81 | extra_hosts: 82 | - 'ns1.example.com:${NETWORK_IPV6_PREFIX}::4' 83 | - 'ns2.example.com:${NETWORK_IPV6_PREFIX}::5' 84 | volumes: 85 | - /etc/localtime:/etc/localtime:ro 86 | environment: 87 | - PDNS_gmysql_dbname=powerdnsslave 88 | - PDNS_gmysql_password=my-secret-pw 89 | - PDNS_secondary=yes 90 | - PDNS_autosecondary=yes 91 | - PDNS_webserver=yes 92 | - PDNS_webserver_address=0.0.0.0 93 | - PDNS_webserver_allow_from=${NETWORK_IPV6_PREFIX}::/${NETWORK_IPV6_PREFIX_LENGTH} 94 | - PDNS_version_string=anonymous 95 | - PDNS_disable_axfr=yes 96 | - PDNS_allow_notify_from=${NETWORK_IPV6_PREFIX}::4 97 | - SUPERMASTER_IPS=${NETWORK_IPV6_PREFIX}::4 98 | depends_on: 99 | - mariadb 100 | - pdns-mysql-master 101 | 102 | pdns-admin-mysql: 103 | image: pschiffe/pdns-admin 104 | networks: 105 | pdns-mysql: 106 | aliases: 107 | - pdns-admin 108 | ipv6_address: ${NETWORK_IPV6_PREFIX}::6 109 | ports: 110 | - '8989:8080' 111 | volumes: 112 | - /etc/localtime:/etc/localtime:ro 113 | environment: 114 | - PDNS_ADMIN_SQLA_DB_PASSWORD=my-secret-pw 115 | - PDNS_VERSION=4.9 116 | - PDNS_API_KEY=secret 117 | depends_on: 118 | - mariadb 119 | - pdns-mysql-master 120 | 121 | networks: 122 | pdns-mysql: 123 | enable_ipv6: true 124 | name: ${NETWORK_NAME:-dns} 125 | driver: bridge 126 | ipam: 127 | driver: default 128 | config: 129 | - subnet: ${NETWORK_IPV6_PREFIX:?network_prefix_missing}::/${NETWORK_IPV6_PREFIX_LENGTH?:network_prefix_length_missing} 130 | volumes: 131 | mariadb: 132 | -------------------------------------------------------------------------------- /docker-compose-mysql.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | pdns-recursor-mysql: 4 | image: pschiffe/pdns-recursor:${RECURSOR_TAG:-latest} 5 | networks: 6 | - pdns-mysql 7 | volumes: 8 | - /etc/localtime:/etc/localtime:ro 9 | ulimits: 10 | nofile: 11 | soft: 10000 12 | hard: 10000 13 | 14 | mariadb: 15 | image: mariadb:11-ubi 16 | networks: 17 | pdns-mysql: 18 | aliases: 19 | - db 20 | - mysql 21 | volumes: 22 | - /etc/localtime:/etc/localtime:ro 23 | - mariadb:/var/lib/mysql:Z 24 | environment: 25 | - MYSQL_ROOT_PASSWORD=my-secret-pw 26 | healthcheck: 27 | test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'] 28 | timeout: 10s 29 | retries: 5 30 | 31 | phpmyadmin: 32 | image: phpmyadmin:5 33 | networks: 34 | - pdns-mysql 35 | ports: 36 | - '8988:80' 37 | volumes: 38 | - /etc/localtime:/etc/localtime:ro 39 | healthcheck: 40 | test: ['CMD', 'curl', '-fsSL', 'http://127.0.0.1:80'] 41 | timeout: 10s 42 | retries: 5 43 | 44 | pdns-mysql-master: 45 | image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} 46 | hostname: ns1.example.com 47 | networks: 48 | pdns-mysql: 49 | ipv4_address: 172.6.0.20 50 | aliases: 51 | - pdns 52 | extra_hosts: 53 | - 'ns1.example.com:172.6.0.20' 54 | - 'ns2.example.com:172.6.0.21' 55 | volumes: 56 | - /etc/localtime:/etc/localtime:ro 57 | environment: 58 | - PDNS_gmysql_password=my-secret-pw 59 | - PDNS_primary=yes 60 | - PDNS_api=yes 61 | - PDNS_api_key=secret 62 | - PDNS_webserver=yes 63 | - PDNS_webserver_address=0.0.0.0 64 | - PDNS_webserver_allow_from=172.6.0.0/16 65 | - PDNS_version_string=anonymous 66 | - PDNS_default_ttl=1500 67 | - PDNS_allow_axfr_ips=172.6.0.21 68 | - PDNS_only_notify=172.6.0.21 69 | depends_on: 70 | - mariadb 71 | 72 | pdns-mysql-slave: 73 | image: pschiffe/pdns-mysql:${PDNS_MYSQL_TAG:-latest} 74 | hostname: ns2.example.com 75 | networks: 76 | pdns-mysql: 77 | ipv4_address: 172.6.0.21 78 | extra_hosts: 79 | - 'ns1.example.com:172.6.0.20' 80 | - 'ns2.example.com:172.6.0.21' 81 | volumes: 82 | - /etc/localtime:/etc/localtime:ro 83 | environment: 84 | - PDNS_gmysql_dbname=powerdnsslave 85 | - PDNS_gmysql_password=my-secret-pw 86 | - PDNS_secondary=yes 87 | - PDNS_autosecondary=yes 88 | - PDNS_webserver=yes 89 | - PDNS_webserver_address=0.0.0.0 90 | - PDNS_webserver_allow_from=172.6.0.0/16 91 | - PDNS_version_string=anonymous 92 | - PDNS_disable_axfr=yes 93 | - PDNS_allow_notify_from=172.6.0.20 94 | - SUPERMASTER_IPS=172.6.0.20 95 | depends_on: 96 | - mariadb 97 | - pdns-mysql-master 98 | 99 | pdns-admin-mysql: 100 | image: pschiffe/pdns-admin 101 | networks: 102 | pdns-mysql: 103 | aliases: 104 | - pdns-admin 105 | ports: 106 | - '8989:8080' 107 | volumes: 108 | - /etc/localtime:/etc/localtime:ro 109 | environment: 110 | - PDNS_ADMIN_SQLA_DB_PASSWORD=my-secret-pw 111 | - PDNS_VERSION=4.9 112 | - PDNS_API_KEY=secret 113 | depends_on: 114 | - mariadb 115 | - pdns-mysql-master 116 | 117 | networks: 118 | pdns-mysql: 119 | ipam: 120 | config: 121 | - subnet: 172.6.0.0/16 122 | gateway: 172.6.0.1 123 | 124 | volumes: 125 | mariadb: 126 | -------------------------------------------------------------------------------- /docker-compose-pgsql.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | pdns-recursor-pgsql: 4 | image: pschiffe/pdns-recursor:${RECURSOR_TAG:-latest} 5 | networks: 6 | - pdns-pgsql 7 | volumes: 8 | - /etc/localtime:/etc/localtime:ro 9 | ulimits: 10 | nofile: 11 | soft: 10000 12 | hard: 10000 13 | 14 | postgres: 15 | image: postgres:16-alpine 16 | networks: 17 | pdns-pgsql: 18 | aliases: 19 | - db 20 | - pgsql 21 | volumes: 22 | - /etc/localtime:/etc/localtime:ro 23 | - pgsql:/var/lib/postgresql/data:Z 24 | environment: 25 | - POSTGRES_PASSWORD=my-secret-pw 26 | healthcheck: 27 | test: ['CMD', 'pg_isready', '-U', 'postgres'] 28 | timeout: 10s 29 | retries: 5 30 | 31 | adminer: 32 | image: adminer 33 | networks: 34 | - pdns-pgsql 35 | ports: 36 | - '7988:8080' 37 | volumes: 38 | - /etc/localtime:/etc/localtime:ro 39 | 40 | pdns-pgsql-master: 41 | image: pschiffe/pdns-pgsql:${PDNS_PGSQL_TAG:-latest} 42 | hostname: ns1.example.com 43 | networks: 44 | pdns-pgsql: 45 | ipv4_address: 172.8.0.20 46 | aliases: 47 | - pdns 48 | extra_hosts: 49 | - 'ns1.example.com:172.8.0.20' 50 | - 'ns2.example.com:172.8.0.21' 51 | volumes: 52 | - /etc/localtime:/etc/localtime:ro 53 | environment: 54 | - PDNS_gpgsql_password=my-secret-pw 55 | - PDNS_primary=yes 56 | - PDNS_api=yes 57 | - PDNS_api_key=secret 58 | - PDNS_webserver=yes 59 | - PDNS_webserver_address=0.0.0.0 60 | - PDNS_webserver_allow_from=172.8.0.0/16 61 | - PDNS_version_string=anonymous 62 | - PDNS_default_ttl=1500 63 | - PDNS_allow_axfr_ips=172.8.0.21 64 | - PDNS_only_notify=172.8.0.21 65 | depends_on: 66 | - postgres 67 | 68 | pdns-pgsql-slave: 69 | image: pschiffe/pdns-pgsql:${PDNS_PGSQL_TAG:-latest} 70 | hostname: ns2.example.com 71 | networks: 72 | pdns-pgsql: 73 | ipv4_address: 172.8.0.21 74 | extra_hosts: 75 | - 'ns1.example.com:172.8.0.20' 76 | - 'ns2.example.com:172.8.0.21' 77 | volumes: 78 | - /etc/localtime:/etc/localtime:ro 79 | environment: 80 | - PDNS_gpgsql_dbname=powerdnsslave 81 | - PDNS_gpgsql_password=my-secret-pw 82 | - PDNS_secondary=yes 83 | - PDNS_autosecondary=yes 84 | - PDNS_webserver=yes 85 | - PDNS_webserver_address=0.0.0.0 86 | - PDNS_webserver_allow_from=172.8.0.0/16 87 | - PDNS_version_string=anonymous 88 | - PDNS_disable_axfr=yes 89 | - PDNS_allow_notify_from=172.8.0.20 90 | - SUPERMASTER_IPS=172.8.0.20 91 | depends_on: 92 | - postgres 93 | - pdns-pgsql-master 94 | 95 | pdns-admin-pgsql: 96 | image: pschiffe/pdns-admin 97 | networks: 98 | pdns-pgsql: 99 | aliases: 100 | - pdns-admin 101 | ports: 102 | - '7989:8080' 103 | volumes: 104 | - /etc/localtime:/etc/localtime:ro 105 | environment: 106 | - PDNS_ADMIN_SQLA_DB_TYPE=postgres 107 | - PDNS_ADMIN_SQLA_DB_HOST=pgsql 108 | - PDNS_ADMIN_SQLA_DB_PORT=5432 109 | - PDNS_ADMIN_SQLA_DB_USER=postgres 110 | - PDNS_ADMIN_SQLA_DB_PASSWORD=my-secret-pw 111 | - PDNS_VERSION=4.9 112 | - PDNS_API_KEY=secret 113 | depends_on: 114 | - postgres 115 | - pdns-pgsql-master 116 | 117 | networks: 118 | pdns-pgsql: 119 | ipam: 120 | config: 121 | - subnet: 172.8.0.0/16 122 | gateway: 172.8.0.1 123 | 124 | volumes: 125 | pgsql: 126 | -------------------------------------------------------------------------------- /examples/kubernetes/README.MD: -------------------------------------------------------------------------------- 1 | # PDNS example for Kubernetes 2 | 3 | ## Files 4 | - master-daemonset.yaml : Daemonset for PDNS supermaster 5 | - slave-daemonset.yaml : Daemonset for PDNS slaves 6 | - admin-dashboard.yaml : Deployment for PDNS-Admin Web Dashboard 7 | - mariadb.yaml : Example Mysql Deployment 8 | 9 | ## Example setup 10 | 11 | This example deploys a supermaster and two slaves on the host network, so pdns can be reached from external networks. Access to the admin-dashboard has to be configured separately with ingress. The admin-dashboard uses a kubernetes clusterip service to use the supermaster-api. Supermaster, slaves and dashboard use the same MariaDB example deployment with different databases (not recommended for production environments). 12 | For signed AXFR you have to manually deploy TSIG Keys to you supermaster and slaves (https://doc.powerdns.com/authoritative/tsig.html). 13 | 14 | ## Requirements 15 | 16 | ### Node Labels 17 | The Daemonsets use node-role labels as nodeSelector: 18 | 19 | kubectl label node node1 node-role.kubernetes.io/pdns-master=true 20 | kubectl label node node2 node-role.kubernetes.io/pdns-slave=true 21 | kubectl label node node3 node-role.kubernetes.io/pdns-slave=true 22 | 23 | Any other node labels will also work. 24 | 25 | ### Service Names 26 | Service names in the pdns namespace **must not** start with 'pdns' or they will break the pdns.conf environment templating. 27 | 28 | ### Pod-CIDR 29 | Replace "10.244.0.0/16" in the manifests with your cluster's pod-cidr. 30 | 31 | ### Node IPs 32 | Replace IPs and hostnames in the daemonset environments with your own node IPs and domains. 33 | 34 | Used in this example: 35 | | component | host | ip | 36 | |--|--|--| 37 | | supermaster | ns1.example.com | 10.0.0.1 | 38 | | slave1 | ns2.example.com | 10.0.0.2 | 39 | | slave2 | ns3.example.com | 10.0.0.3 | 40 | -------------------------------------------------------------------------------- /examples/kubernetes/admin-dashboard.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: pdns-admin 6 | app.kubernetes.io/part-of: pdns 7 | app.kubernetes.io/component: admin 8 | name: pdns-admin 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app.kubernetes.io/name: pdns-admin 14 | app.kubernetes.io/part-of: pdns 15 | app.kubernetes.io/component: admin 16 | template: 17 | metadata: 18 | labels: 19 | app.kubernetes.io/name: pdns-admin 20 | app.kubernetes.io/part-of: pdns 21 | app.kubernetes.io/component: admin 22 | spec: 23 | hostAliases: 24 | - ip: "127.0.0.1" 25 | hostnames: 26 | - "pdns-admin" 27 | containers: 28 | - name: pdns-admin 29 | image: pschiffe/pdns-admin 30 | imagePullPolicy: IfNotPresent 31 | ports: 32 | - containerPort: 8080 33 | protocol: TCP 34 | env: 35 | - name: PDNS_ADMIN_SQLA_DB_HOST 36 | value: "mariadb-pdns" 37 | - name: PDNS_ADMIN_SQLA_DB_PORT 38 | value: "3306" 39 | - name: PDNS_ADMIN_SQLA_DB_USER 40 | value: "root" 41 | - name: PDNS_ADMIN_SQLA_DB_PASSWORD 42 | valueFrom: 43 | secretKeyRef: 44 | name: pdns-admin-secret 45 | key: quoted_mysql_password 46 | - name: PDNS_ADMIN_SQLA_DB_NAME 47 | value: "pdnsadmin" 48 | - name: PDNS_API_URL 49 | value: "http://master-api-pdns:8081/" 50 | - name: PDNS_VERSION 51 | value: "4.9" 52 | - name: PDNS_API_KEY 53 | valueFrom: 54 | secretKeyRef: 55 | name: master-pdns-secret 56 | key: apikey 57 | volumeMounts: 58 | - name: uploads 59 | mountPath: /opt/powerdns-admin/upload/ 60 | resources: 61 | limits: 62 | cpu: 300m 63 | memory: 128Mi 64 | requests: 65 | cpu: 50m 66 | memory: 64Mi 67 | volumes: 68 | - name: uploads 69 | persistentVolumeClaim: 70 | claimName: pdns-admin-pvc 71 | --- 72 | apiVersion: v1 73 | kind: PersistentVolumeClaim 74 | metadata: 75 | labels: 76 | app.kubernetes.io/name: pdns-admin-pvc 77 | app.kubernetes.io/part-of: pdns 78 | app.kubernetes.io/component: admin 79 | name: pdns-admin-pvc 80 | spec: 81 | accessModes: 82 | - ReadWriteMany 83 | resources: 84 | requests: 85 | storage: 1Gi 86 | --- 87 | apiVersion: v1 88 | kind: Service 89 | metadata: 90 | labels: 91 | app.kubernetes.io/name: pdns-admin-svc 92 | app.kubernetes.io/part-of: pdns 93 | app.kubernetes.io/component: admin 94 | name: admin-dashboard-pdns 95 | spec: 96 | type: ClusterIP 97 | ports: 98 | - port: 80 99 | targetPort: 8080 100 | selector: 101 | app.kubernetes.io/name: pdns-admin 102 | --- 103 | apiVersion: v1 104 | kind: Secret 105 | metadata: 106 | labels: 107 | app.kubernetes.io/name: pdns-admin-secret 108 | app.kubernetes.io/part-of: pdns 109 | app.kubernetes.io/component: admin 110 | name: pdns-admin-secret 111 | data: 112 | quoted_mysql_password: J3Jvb3Qn 113 | -------------------------------------------------------------------------------- /examples/kubernetes/kustomization.yaml: -------------------------------------------------------------------------------- 1 | namespace: default 2 | resources: 3 | - mariadb.yaml 4 | - master-daemonset.yaml 5 | - slave-daemonset.yaml 6 | - admin-dashboard.yaml 7 | -------------------------------------------------------------------------------- /examples/kubernetes/mariadb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: StatefulSet 4 | metadata: 5 | creationTimestamp: null 6 | labels: 7 | app.kubernetes.io/name: mariadb-pdns 8 | app.kubernetes.io/part-of: pdns 9 | app.kubernetes.io/component: mariadb 10 | name: mariadb-pdns 11 | spec: 12 | podManagementPolicy: OrderedReady 13 | replicas: 1 14 | revisionHistoryLimit: 10 15 | selector: 16 | matchLabels: 17 | app.kubernetes.io/name: mariadb-pdns 18 | app.kubernetes.io/part-of: pdns 19 | app.kubernetes.io/component: mariadb 20 | serviceName: mariadb-pdns 21 | template: 22 | metadata: 23 | labels: 24 | app.kubernetes.io/name: mariadb-pdns 25 | app.kubernetes.io/part-of: pdns 26 | app.kubernetes.io/component: mariadb 27 | spec: 28 | containers: 29 | - name: mariadb-pdns 30 | image: mariadb:11-ubi 31 | imagePullPolicy: Always 32 | env: 33 | - name: MYSQL_ROOT_PASSWORD 34 | valueFrom: 35 | secretKeyRef: 36 | name: mariadb-pdns-secret 37 | key: password 38 | volumeMounts: 39 | - name: mariadb-pdns-storage 40 | mountPath: /var/lib/mysql 41 | - name: mariadb-pdns-config 42 | mountPath: /etc/mysql/conf.d 43 | ports: 44 | - containerPort: 3306 45 | resources: 46 | limits: 47 | cpu: 300m 48 | memory: 256Mi 49 | requests: 50 | cpu: 50m 51 | memory: 128Mi 52 | volumes: 53 | - name: mariadb-pdns-storage 54 | persistentVolumeClaim: 55 | claimName: mariadb-pdns-pvc 56 | - name: mariadb-pdns-config 57 | configMap: 58 | name: mariadb-pdns-config 59 | items: 60 | - key: mariadb-override.cnf 61 | path: mariadb-override.cnf 62 | --- 63 | apiVersion: v1 64 | kind: Service 65 | metadata: 66 | labels: 67 | app.kubernetes.io/name: mariadb-pdns-svc 68 | app.kubernetes.io/part-of: pdns 69 | app.kubernetes.io/component: mariadb 70 | name: mariadb-pdns 71 | spec: 72 | ports: 73 | - name: tcp-mysql 74 | port: 3306 75 | protocol: TCP 76 | targetPort: 3306 77 | selector: 78 | app.kubernetes.io/name: mariadb-pdns 79 | sessionAffinity: None 80 | type: ClusterIP 81 | --- 82 | apiVersion: v1 83 | kind: ConfigMap 84 | metadata: 85 | labels: 86 | app.kubernetes.io/name: mariadb-pdns-config 87 | app.kubernetes.io/part-of: pdns 88 | app.kubernetes.io/component: mariadb 89 | name: mariadb-pdns-config 90 | data: 91 | mariadb-override.cnf: | 92 | [mysqld] 93 | collation-server = utf8mb4_unicode_ci 94 | init-connect='SET NAMES utf8mb4' 95 | character-set-server = utf8mb4 96 | innodb_buffer_pool_size = 134217728 97 | innodb_log_file_size = 134217728 98 | innodb-log-files-in-group = 3 99 | binlog_format = ROW 100 | --- 101 | apiVersion: v1 102 | kind: PersistentVolumeClaim 103 | metadata: 104 | labels: 105 | app.kubernetes.io/name: mariadb-pdns-pvc 106 | app.kubernetes.io/part-of: pdns 107 | app.kubernetes.io/component: mariadb 108 | name: mariadb-pdns-pvc 109 | spec: 110 | accessModes: 111 | - ReadWriteOnce 112 | resources: 113 | requests: 114 | storage: 1Gi 115 | --- 116 | apiVersion: v1 117 | kind: Secret 118 | metadata: 119 | labels: 120 | app.kubernetes.io/name: mariadb-pdns-secret 121 | app.kubernetes.io/part-of: pdns 122 | app.kubernetes.io/component: mariadb 123 | name: mariadb-pdns-secret 124 | data: 125 | username: cm9vdA== 126 | password: cm9vdA== 127 | -------------------------------------------------------------------------------- /examples/kubernetes/master-daemonset.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: pdns-master 7 | app.kubernetes.io/part-of: pdns 8 | app.kubernetes.io/component: master 9 | name: pdns-master 10 | spec: 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: pdns-master 15 | app.kubernetes.io/part-of: pdns 16 | app.kubernetes.io/component: master 17 | template: 18 | metadata: 19 | creationTimestamp: null 20 | labels: 21 | app.kubernetes.io/name: pdns-master 22 | app.kubernetes.io/part-of: pdns 23 | app.kubernetes.io/component: master 24 | spec: 25 | nodeSelector: 26 | node-role.kubernetes.io/pdns-master: "true" 27 | containers: 28 | - image: pschiffe/pdns-mysql:alpine 29 | imagePullPolicy: IfNotPresent 30 | name: pdns-master 31 | env: 32 | - name: NODE_NAME 33 | valueFrom: 34 | fieldRef: 35 | fieldPath: spec.nodeName 36 | - name: PDNS_gmysql_host 37 | value: "mariadb-pdns" 38 | - name: PDNS_gmysql_port 39 | value: "3306" 40 | - name: PDNS_gmysql_user 41 | valueFrom: 42 | secretKeyRef: 43 | name: mariadb-pdns-secret 44 | key: username 45 | - name: PDNS_gmysql_password 46 | valueFrom: 47 | secretKeyRef: 48 | name: mariadb-pdns-secret 49 | key: password 50 | - name: PDNS_gmysql_dbname 51 | value: "master_" 52 | - name: PDNS_version_string 53 | value: "anonymous" 54 | - name: PDNS_primary 55 | value: "yes" 56 | - name: PDNS_api 57 | value: "yes" 58 | - name: PDNS_api_key 59 | valueFrom: 60 | secretKeyRef: 61 | name: master-pdns-secret 62 | key: apikey 63 | - name: PDNS_webserver 64 | value: "yes" 65 | - name: PDNS_webserver_address 66 | value: "0.0.0.0" 67 | - name: PDNS_webserver_allow_from 68 | value: "127.0.0.1/32 10.244.0.0/16" 69 | - name: PDNS_webserver_password 70 | valueFrom: 71 | secretKeyRef: 72 | name: master-pdns-secret 73 | key: webserver 74 | - name: PDNS_default_ttl 75 | value: "1500" 76 | - name: PDNS_soa_minimum_ttl 77 | value: "1200" 78 | - name: PDNS_default_soa_name 79 | value: "ns1.example.com" 80 | - name: PDNS_default_soa_mail 81 | value: "dnsmaster.example.com" 82 | - name: PDNS_allow_axfr_ips 83 | value: "10.0.0.2 10.0.0.3" 84 | - name: PDNS_only_notify 85 | value: "10.0.0.2 10.0.0.3" 86 | - name: PDNS_dnsupdate 87 | value: "yes" 88 | - name: PDNS_allow_dnsupdate_from 89 | value: "10.0.0.1/32 127.0.0.1/32 10.244.0.0/16" 90 | resources: 91 | limits: 92 | cpu: 300m 93 | memory: 256Mi 94 | requests: 95 | cpu: 50m 96 | memory: 128Mi 97 | ports: 98 | - name: dns-udp 99 | containerPort: 53 100 | protocol: UDP 101 | hostPort: 53 102 | - name: dns-tcp 103 | containerPort: 53 104 | protocol: TCP 105 | hostPort: 53 106 | - containerPort: 8081 107 | protocol: TCP 108 | dnsPolicy: ClusterFirstWithHostNet 109 | restartPolicy: Always 110 | schedulerName: default-scheduler 111 | securityContext: {} 112 | terminationGracePeriodSeconds: 30 113 | updateStrategy: 114 | rollingUpdate: 115 | maxUnavailable: 1 116 | type: RollingUpdate 117 | --- 118 | apiVersion: v1 119 | kind: Secret 120 | metadata: 121 | labels: 122 | app.kubernetes.io/name: master-pdns-secret 123 | app.kubernetes.io/part-of: pdns 124 | app.kubernetes.io/component: master 125 | name: master-pdns-secret 126 | data: 127 | apikey: MTIzNDU2Nzg5MA== 128 | webserver: MDk4NzY1NDMyMQ== 129 | --- 130 | apiVersion: v1 131 | kind: Service 132 | metadata: 133 | labels: 134 | app.kubernetes.io/name: master-api-pdns 135 | app.kubernetes.io/part-of: pdns 136 | app.kubernetes.io/component: master 137 | name: master-api-pdns 138 | spec: 139 | type: ClusterIP 140 | ports: 141 | - port: 8081 142 | targetPort: 8081 143 | selector: 144 | app.kubernetes.io/name: pdns-master 145 | -------------------------------------------------------------------------------- /examples/kubernetes/slave-daemonset.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: pdns-slave 7 | app.kubernetes.io/part-of: pdns 8 | app.kubernetes.io/component: slave 9 | name: pdns-slave 10 | spec: 11 | revisionHistoryLimit: 10 12 | selector: 13 | matchLabels: 14 | app.kubernetes.io/name: pdns-slave 15 | app.kubernetes.io/part-of: pdns 16 | app.kubernetes.io/component: slave 17 | template: 18 | metadata: 19 | creationTimestamp: null 20 | labels: 21 | app.kubernetes.io/name: pdns-slave 22 | app.kubernetes.io/part-of: pdns 23 | app.kubernetes.io/component: slave 24 | spec: 25 | nodeSelector: 26 | node-role.kubernetes.io/pdns-slave: "true" 27 | containers: 28 | - image: pschiffe/pdns-mysql:alpine 29 | imagePullPolicy: IfNotPresent 30 | name: pdns-slave 31 | env: 32 | - name: NODE_NAME 33 | valueFrom: 34 | fieldRef: 35 | fieldPath: spec.nodeName 36 | - name: PDNS_gmysql_host 37 | value: "mariadb-pdns" 38 | - name: PDNS_gmysql_port 39 | value: "3306" 40 | - name: PDNS_gmysql_user 41 | valueFrom: 42 | secretKeyRef: 43 | name: mariadb-pdns-secret 44 | key: username 45 | - name: PDNS_gmysql_password 46 | valueFrom: 47 | secretKeyRef: 48 | name: mariadb-pdns-secret 49 | key: password 50 | - name: PDNS_gmysql_dbname 51 | value: "slave_" 52 | - name: PDNS_version_string 53 | value: "anonymous" 54 | - name: PDNS_disable_axfr 55 | value: "yes" 56 | - name: PDNS_secondary 57 | value: "yes" 58 | - name: PDNS_autosecondary 59 | value: "yes" 60 | - name: PDNS_allow_unsigned_supermaster 61 | value: "no" 62 | - name: PDNS_allow_notify_from 63 | value: "10.0.0.1" 64 | - name: SUPERMASTER_HOSTS 65 | value: "ns1.example.com" 66 | - name: SUPERMASTER_IPS 67 | value: "10.0.0.1" 68 | ports: 69 | - name: dns-udp 70 | containerPort: 53 71 | protocol: UDP 72 | hostPort: 53 73 | - name: dns-tcp 74 | containerPort: 53 75 | protocol: TCP 76 | hostPort: 53 77 | resources: 78 | limits: 79 | cpu: 300m 80 | memory: 256Mi 81 | requests: 82 | cpu: 50m 83 | memory: 128Mi 84 | securityContext: 85 | privileged: false 86 | terminationMessagePath: /dev/termination-log 87 | terminationMessagePolicy: File 88 | dnsPolicy: ClusterFirstWithHostNet 89 | restartPolicy: Always 90 | schedulerName: default-scheduler 91 | securityContext: {} 92 | terminationGracePeriodSeconds: 30 93 | updateStrategy: 94 | rollingUpdate: 95 | maxUnavailable: 1 96 | type: RollingUpdate 97 | -------------------------------------------------------------------------------- /pdns-admin/Caddyfile.tpl: -------------------------------------------------------------------------------- 1 | { 2 | http_port 8080 3 | https_port 8443 4 | } 5 | 6 | {{ if all .SSL_MAIN_DOMAIN .SSL_EXTRA_DOMAINS -}} 7 | {{ .SSL_EXTRA_DOMAINS }} { 8 | redir https://{{ .SSL_MAIN_DOMAIN }} 9 | } 10 | {{ end -}} 11 | 12 | {{ .SSL_MAIN_DOMAIN | default ":8080" }} { 13 | @staticfiles { 14 | path *.jpeg *.jpg *.png *.gif *.bmp *.ico *.svg *.tif *.tiff *.css *.js *.htm *.html *.ttf *.otf *.webp *.woff *.woff2 *.txt *.csv *.rtf *.doc *.docx *.xls *.xlsx *.ppt *.pptx *.odf *.odp *.ods *.odt *.pdf *.psd *.ai *.eot *.eps *.ps *.zip *.tar *.tgz *.gz *.rar *.bz2 *.7z *.aac *.m4a *.mp3 *.mp4 *.ogg *.wav *.wma *.3gp *.avi *.flv *.m4v *.mkv *.mov *.mp4 *.mpeg *.mpg *.wmv *.exe *.iso *.dmg *.swf 15 | } 16 | 17 | log { 18 | output stdout 19 | format json 20 | } 21 | 22 | @blocked { 23 | path */.* 24 | } 25 | respond @blocked 404 26 | 27 | encode zstd gzip 28 | 29 | header X-Content-Type-Options "nosniff" 30 | header X-Frame-Options "SAMEORIGIN" 31 | header @staticfiles Cache-Control "public, max-age=604800, must-revalidate" 32 | header -Server 33 | header -X-Powered-By 34 | 35 | root * /opt/powerdns-admin/powerdnsadmin 36 | 37 | route { 38 | file_server @staticfiles { 39 | pass_thru 40 | } 41 | reverse_proxy 127.0.0.1:9494 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pdns-admin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rockylinux/rockylinux:9-ubi 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ 5 | && echo 'tsflags=nodocs' >> /etc/dnf/dnf.conf \ 6 | && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ 7 | && curl -fsSL -o /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \ 8 | && dnf module enable nodejs:20 postgresql:15 \ 9 | && dnf install dnf-plugins-core epel-release \ 10 | && dnf config-manager --set-disabled epel-cisco-openh264 \ 11 | && dnf config-manager --set-enabled crb \ 12 | && dnf --refresh upgrade \ 13 | && dnf install \ 14 | caddy \ 15 | mariadb \ 16 | npm \ 17 | postgresql \ 18 | python3-cffi \ 19 | python3-ldap \ 20 | python3-lxml \ 21 | python3-mysqlclient \ 22 | python3-pip \ 23 | python3-psycopg2 \ 24 | python3-pyyaml \ 25 | python3-saml \ 26 | python3-xmlsec \ 27 | supervisor \ 28 | uwsgi \ 29 | uwsgi-plugin-python3 \ 30 | yarn \ 31 | https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ 32 | && dnf clean all 33 | 34 | RUN mkdir -p /opt/powerdns-admin \ 35 | && curl -fsSL https://github.com/PowerDNS-Admin/PowerDNS-Admin/archive/refs/tags/v0.4.1.tar.gz \ 36 | | tar -xzf - -C /opt/powerdns-admin --strip 1 \ 37 | && sed -i \ 38 | -e '/cffi/d' \ 39 | -e '/lxml/d' \ 40 | -e '/mysqlclient/d' \ 41 | -e '/psycopg2/d' \ 42 | -e '/python-ldap/d' \ 43 | -e '/python3-saml/d' \ 44 | -e '/PyYAML/d' \ 45 | /opt/powerdns-admin/requirements.txt \ 46 | && chown -R root: /opt/powerdns-admin 47 | 48 | WORKDIR /opt/powerdns-admin 49 | 50 | RUN pip3 install -r requirements.txt --no-cache-dir 51 | 52 | ENV FLASK_APP=/opt/powerdns-admin/powerdnsadmin/__init__.py 53 | ENV SSL_MAIN_DOMAIN="" 54 | ENV SSL_EXTRA_DOMAINS="" 55 | 56 | COPY config.py.tpl Caddyfile.tpl docker-entrypoint.sh / 57 | COPY run.py . 58 | COPY --chown=uwsgi:uwsgi pdns-admin.ini /etc/uwsgi.ini 59 | COPY supervisor.ini /etc/supervisord.d/supervisor.ini 60 | 61 | RUN subvars --prefix 'PDNS_ADMIN_' < /config.py.tpl > /opt/powerdns-admin/config.py \ 62 | && sed -i '/SQLALCHEMY_DATABASE_URI/d' /opt/powerdns-admin/config.py 63 | 64 | RUN yarn install --pure-lockfile --production \ 65 | && yarn cache clean \ 66 | && flask assets build \ 67 | && chown -R uwsgi: /opt/powerdns-admin/powerdnsadmin/static/.webassets-cache 68 | 69 | EXPOSE 8080 70 | 71 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=6s \ 72 | CMD ["curl", "-fsSLo", "/dev/null", "http://127.0.0.1:9494"] 73 | 74 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 75 | 76 | CMD [ "/usr/bin/supervisord", "-c", "/etc/supervisord.conf" ] 77 | -------------------------------------------------------------------------------- /pdns-admin/config.py.tpl: -------------------------------------------------------------------------------- 1 | import os 2 | basedir = os.path.abspath(os.path.dirname(__file__)) 3 | 4 | ### BASIC APP CONFIG 5 | BIND_ADDRESS = '0.0.0.0' 6 | PORT = 9191 7 | HSTS_ENABLED = False 8 | 9 | # CAPTCHA Config 10 | CAPTCHA_ENABLE = True 11 | CAPTCHA_LENGTH = 6 12 | CAPTCHA_WIDTH = 160 13 | CAPTCHA_HEIGHT = 60 14 | CAPTCHA_SESSION_KEY = 'captcha_image' 15 | 16 | SESSION_TYPE = 'sqlalchemy' 17 | 18 | # SAML Authentication 19 | SAML_ENABLED = False 20 | 21 | # Configuration from env vars 22 | {{ range $key, $value := match "PDNS_ADMIN_" -}} 23 | {{ $v := $value | trimAll "\"'\\" -}} 24 | {{ if or (eq $v "True" "False" "None" "0") (ne ($v | int) 0) -}} 25 | {{- $key | trimPrefix "PDNS_ADMIN_" }} = {{ $v }} 26 | {{ else -}} 27 | {{- $key | trimPrefix "PDNS_ADMIN_" }} = '{{ $v }}' 28 | {{ end -}} 29 | {{ end }} 30 | ### DATABASE CONFIG 31 | SQLALCHEMY_DATABASE_URI = SQLA_DB_TYPE + '://' + SQLA_DB_USER + ':' + SQLA_DB_PASSWORD + '@' + SQLA_DB_HOST + ':' + str(SQLA_DB_PORT) + '/' + SQLA_DB_NAME 32 | SQLALCHEMY_TRACK_MODIFICATIONS = True 33 | -------------------------------------------------------------------------------- /pdns-admin/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | : "${DEBUG:=0}" 6 | 7 | if [ "${DEBUG}" -eq 1 ]; then 8 | set -x 9 | fi 10 | 11 | # Configure db env vars 12 | : "${PDNS_ADMIN_SQLA_DB_TYPE:=mysql}" # or postgres 13 | : "${PDNS_ADMIN_SQLA_DB_HOST:=${MYSQL_ENV_MYSQL_HOST:-mysql}}" 14 | : "${PDNS_ADMIN_SQLA_DB_PORT:=${MYSQL_ENV_MYSQL_PORT:-3306}}" 15 | : "${PDNS_ADMIN_SQLA_DB_USER:=${MYSQL_ENV_MYSQL_USER:-${PGSQL_ENV_POSTGRES_USER:-root}}}" 16 | if [ "${PDNS_ADMIN_SQLA_DB_USER}" = "root" ]; then 17 | : "${PDNS_ADMIN_SQLA_DB_PASSWORD:=$MYSQL_ENV_MYSQL_ROOT_PASSWORD}" 18 | fi 19 | : "${PDNS_ADMIN_SQLA_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-${PGSQL_ENV_POSTGRES_PASSWORD:-powerdnsadmin}}}" 20 | : "${PDNS_ADMIN_SQLA_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-${PGSQL_ENV_POSTGRES_DB:-powerdnsadmin}}}" 21 | 22 | # Cleanup quotes from db env vars 23 | PDNS_ADMIN_SQLA_DB_TYPE="${PDNS_ADMIN_SQLA_DB_TYPE//[\'\"]}" 24 | PDNS_ADMIN_SQLA_DB_HOST="${PDNS_ADMIN_SQLA_DB_HOST//[\'\"]}" 25 | PDNS_ADMIN_SQLA_DB_PORT="${PDNS_ADMIN_SQLA_DB_PORT//[\'\"]}" 26 | PDNS_ADMIN_SQLA_DB_USER="${PDNS_ADMIN_SQLA_DB_USER//[\'\"]}" 27 | PDNS_ADMIN_SQLA_DB_PASSWORD="${PDNS_ADMIN_SQLA_DB_PASSWORD//[\'\"]}" 28 | PDNS_ADMIN_SQLA_DB_NAME="${PDNS_ADMIN_SQLA_DB_NAME//[\'\"]}" 29 | 30 | export PDNS_ADMIN_SQLA_DB_TYPE PDNS_ADMIN_SQLA_DB_HOST PDNS_ADMIN_SQLA_DB_PORT PDNS_ADMIN_SQLA_DB_USER PDNS_ADMIN_SQLA_DB_PASSWORD PDNS_ADMIN_SQLA_DB_NAME 31 | 32 | # Configure pdns server env vars 33 | : "${PDNS_API_URL:=http://${PDNS_ENV_PDNS_webserver_host:-pdns}:${PDNS_ENV_PDNS_webserver_port:-8081}/}" 34 | : "${PDNS_API_KEY:=${PDNS_ENV_PDNS_api_key:-}}" 35 | : "${PDNS_VERSION:=${PDNS_ENV_VERSION:-}}" 36 | 37 | # Generate secret key 38 | [ -f /root/secret-key ] || tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 32 > /root/secret-key || true 39 | PDNS_ADMIN_SECRET_KEY="$(cat /root/secret-key)" 40 | 41 | export PDNS_ADMIN_SECRET_KEY 42 | 43 | subvars --prefix 'SSL_' < '/Caddyfile.tpl' > '/etc/caddy/Caddyfile' 44 | subvars --prefix 'PDNS_ADMIN_' < '/config.py.tpl' > '/opt/powerdns-admin/powerdnsadmin/default_config.py' 45 | 46 | # Initialize DB if needed 47 | if [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'mysql' ]]; then 48 | SQL_COMMAND="mariadb -h ${PDNS_ADMIN_SQLA_DB_HOST} -P ${PDNS_ADMIN_SQLA_DB_PORT} -u ${PDNS_ADMIN_SQLA_DB_USER} -p${PDNS_ADMIN_SQLA_DB_PASSWORD} -e" 49 | elif [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'postgres' ]]; then 50 | PGPASSWORD="${PDNS_ADMIN_SQLA_DB_PASSWORD}" 51 | export PGPASSWORD 52 | SQL_COMMAND="psql -h ${PDNS_ADMIN_SQLA_DB_HOST} -p ${PDNS_ADMIN_SQLA_DB_PORT} -U ${PDNS_ADMIN_SQLA_DB_USER} -c" 53 | else 54 | >&2 echo "Invalid DB type: ${PDNS_ADMIN_SQLA_DB_TYPE}" 55 | exit 1 56 | fi 57 | 58 | until $SQL_COMMAND ';' ; do 59 | >&2 echo 'DB is unavailable - sleeping' 60 | sleep 1 61 | done 62 | 63 | if [[ "${SKIP_DB_CREATE:-false}" != 'true' ]]; then 64 | if [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'mysql' ]]; then 65 | $SQL_COMMAND "CREATE DATABASE IF NOT EXISTS ${PDNS_ADMIN_SQLA_DB_NAME}" 66 | elif [[ "${PDNS_ADMIN_SQLA_DB_TYPE}" == 'postgres' ]]; then 67 | echo "SELECT 'CREATE DATABASE ${PDNS_ADMIN_SQLA_DB_NAME}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${PDNS_ADMIN_SQLA_DB_NAME}')\gexec" | ${SQL_COMMAND::-3} 68 | fi 69 | fi 70 | 71 | flask db upgrade 72 | 73 | # initial settings if not available in the DB 74 | $SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_url', '${PDNS_API_URL//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_url') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" 75 | $SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_api_key', '${PDNS_API_KEY//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_api_key') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" 76 | $SQL_COMMAND "INSERT INTO setting (name, value) SELECT * FROM (SELECT 'pdns_version', '${PDNS_VERSION//[\'\"]}') AS tmp WHERE NOT EXISTS (SELECT name FROM setting WHERE name = 'pdns_version') LIMIT 1;" "${PDNS_ADMIN_SQLA_DB_NAME}" 77 | 78 | # update pdns api settings if env changed 79 | $SQL_COMMAND "UPDATE setting SET value='${PDNS_API_URL//[\'\"]}' WHERE name='pdns_api_url';" "${PDNS_ADMIN_SQLA_DB_NAME}" 80 | $SQL_COMMAND "UPDATE setting SET value='${PDNS_API_KEY//[\'\"]}' WHERE name='pdns_api_key';" "${PDNS_ADMIN_SQLA_DB_NAME}" 81 | $SQL_COMMAND "UPDATE setting SET value='${PDNS_VERSION//[\'\"]}' WHERE name='pdns_version';" "${PDNS_ADMIN_SQLA_DB_NAME}" 82 | 83 | mkdir -p /run/uwsgi 84 | chown uwsgi: /run/uwsgi 85 | 86 | exec "$@" 87 | -------------------------------------------------------------------------------- /pdns-admin/pdns-admin.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | strict = true 3 | master = true 4 | die-on-term = true 5 | need-app = true 6 | 7 | plugins = python3 8 | 9 | uid = uwsgi 10 | gid = uwsgi 11 | 12 | chdir = /opt/powerdns-admin 13 | pythonpath = /opt/powerdns-admin 14 | 15 | mount = /=run.py 16 | manage-script-name = true 17 | callable = app 18 | 19 | vacuum = true 20 | harakiri = 20 21 | buffer-size = 32768 22 | post-buffering = 8192 23 | http-socket = 127.0.0.1:9494 24 | pidfile = /run/uwsgi/%n.pid 25 | 26 | enable-threads = true 27 | -------------------------------------------------------------------------------- /pdns-admin/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from powerdnsadmin import create_app 4 | 5 | app = create_app() 6 | -------------------------------------------------------------------------------- /pdns-admin/supervisor.ini: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon = true 3 | user = root 4 | logfile = /dev/stderr 5 | logfile_maxbytes = 0 6 | loglevel = info 7 | 8 | [program:uwsgi] 9 | command = /usr/sbin/uwsgi --ini /etc/uwsgi.ini 10 | autorestart = true 11 | stdout_logfile = /dev/stdout 12 | stdout_logfile_maxbytes = 0 13 | stderr_logfile = /dev/stderr 14 | stderr_logfile_maxbytes = 0 15 | 16 | [program:caddy] 17 | command = /usr/bin/caddy run --config /etc/caddy/Caddyfile 18 | user = caddy 19 | environment = HOME="/var/lib/caddy" 20 | autorestart = true 21 | stdout_logfile = /dev/stdout 22 | stdout_logfile_maxbytes = 0 23 | stderr_logfile = /dev/stderr 24 | stderr_logfile_maxbytes = 0 25 | -------------------------------------------------------------------------------- /pdns-mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ 5 | && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ 6 | && sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/fedora-cisco-openh264.repo \ 7 | && dnf --refresh upgrade \ 8 | && dnf install \ 9 | hostname \ 10 | mariadb \ 11 | pdns \ 12 | https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ 13 | && dnf --setopt 'tsflags=' install pdns-backend-mysql \ 14 | && dnf clean all 15 | 16 | RUN mkdir -p /run/pdns \ 17 | && chown -R pdns: /etc/pdns /run/pdns 18 | 19 | COPY pdns.conf.tpl docker-entrypoint.sh / 20 | 21 | ENV VERSION=4.9 \ 22 | PDNS_guardian=yes \ 23 | PDNS_setuid=pdns \ 24 | PDNS_setgid=pdns \ 25 | PDNS_launch=gmysql 26 | 27 | EXPOSE 53 53/udp 28 | 29 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["pdns_control", "ping"] 30 | 31 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 32 | 33 | CMD [ "/usr/sbin/pdns_server" ] 34 | -------------------------------------------------------------------------------- /pdns-mysql/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && apk update \ 5 | && apk upgrade \ 6 | && apk add \ 7 | mariadb-client \ 8 | pdns \ 9 | pdns-backend-mysql \ 10 | pdns-doc \ 11 | && wget -O subvars.apk https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.apk \ 12 | && apk add --allow-untrusted subvars.apk \ 13 | && rm -rf subvars.apk /var/cache/apk/* 14 | 15 | RUN mkdir -p /run/pdns \ 16 | && chown -R pdns: /etc/pdns /run/pdns 17 | 18 | COPY pdns.conf.tpl docker-entrypoint.sh / 19 | 20 | ENV VERSION=4.9 \ 21 | PDNS_guardian=yes \ 22 | PDNS_setuid=pdns \ 23 | PDNS_setgid=pdns \ 24 | PDNS_launch=gmysql 25 | 26 | EXPOSE 53 53/udp 27 | 28 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["pdns_control", "ping"] 29 | 30 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 31 | 32 | CMD [ "/usr/sbin/pdns_server" ] 33 | -------------------------------------------------------------------------------- /pdns-mysql/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | : "${DEBUG:=0}" 6 | 7 | if [ "${DEBUG}" -eq 1 ]; then 8 | set -x 9 | fi 10 | 11 | ##### Function definitions #### 12 | 13 | deriveMySQLSettingsFromExistingConfigFile() { 14 | if [ ! -f /etc/pdns/pdns.conf ]; then 15 | echo "Use of existing file /etc/pdns/pdns.conf requested but file does not exist!" 16 | exit 1 17 | fi 18 | 19 | PDNS_gmysql_host=$(sed -n 's/^gmysql-host=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 20 | PDNS_gmysql_port=$(sed -n 's/^gmysql-port=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 21 | PDNS_gmysql_user=$(sed -n 's/^gmysql-user=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 22 | PDNS_gmysql_password=$(sed -n 's/^gmysql-password=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 23 | PDNS_gmysql_dbname=$(sed -n 's/^gmysql-dbname=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 24 | } 25 | 26 | deriveMySQLSettingsFromEnvironment() { 27 | # Configure mysql env vars 28 | : "${PDNS_gmysql_host:=${MYSQL_ENV_MYSQL_HOST:-mysql}}" 29 | : "${PDNS_gmysql_port:=${MYSQL_ENV_MYSQL_PORT:-3306}}" 30 | : "${PDNS_gmysql_user:=${MYSQL_ENV_MYSQL_USER:-root}}" 31 | if [ "${PDNS_gmysql_user}" = 'root' ]; then 32 | : "${PDNS_gmysql_password:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" 33 | fi 34 | : "${PDNS_gmysql_password:=${MYSQL_ENV_MYSQL_PASSWORD:-powerdns}}" 35 | : "${PDNS_gmysql_dbname:=${MYSQL_ENV_MYSQL_DATABASE:-powerdns}}" 36 | 37 | # Use first part of node name as database name suffix 38 | if [ "${NODE_NAME:-}" ]; then 39 | NODE_NAME=$(echo "${NODE_NAME}" | sed -e 's/\..*//' -e 's/-//') 40 | PDNS_gmysql_dbname="${PDNS_gmysql_dbname}${NODE_NAME}" 41 | fi 42 | 43 | export PDNS_gmysql_host PDNS_gmysql_port PDNS_gmysql_user PDNS_gmysql_password PDNS_gmysql_dbname 44 | } 45 | 46 | generateMySQLCommand() { 47 | : "${MYSQL_CLIENT_EXTRA_PARAMS:=}" 48 | 49 | # Password Auth 50 | if [ "${PDNS_gmysql_password:-}" ]; then 51 | MYSQL_CLIENT_EXTRA_PARAMS="${MYSQL_CLIENT_EXTRA_PARAMS} -p${PDNS_gmysql_password}" 52 | fi 53 | 54 | # Allow socket connections 55 | if [ "${PDNS_gmysql_socket:-}" ]; then 56 | export PDNS_gmysql_host='localhost' 57 | MYSQL_CLIENT_EXTRA_PARAMS="${MYSQL_CLIENT_EXTRA_PARAMS} --socket=${PDNS_gmysql_socket}" 58 | fi 59 | 60 | MYSQL_COMMAND="mariadb -h ${PDNS_gmysql_host} -P ${PDNS_gmysql_port} -u ${PDNS_gmysql_user} ${MYSQL_CLIENT_EXTRA_PARAMS}" 61 | } 62 | 63 | createDatabaseIfRequested() { 64 | # Initialize DB if needed 65 | if [ "${SKIP_DB_CREATE:-false}" != 'true' ]; then 66 | $MYSQL_COMMAND -e "CREATE DATABASE IF NOT EXISTS ${PDNS_gmysql_dbname}" 67 | fi 68 | } 69 | 70 | initDatabase() { 71 | if [ "${SKIP_DB_INIT:-false}" != 'true' ]; then 72 | MYSQL_CHECK_IF_HAS_TABLE="SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '${PDNS_gmysql_dbname}';" 73 | MYSQL_NUM_TABLE=$($MYSQL_COMMAND --batch --skip-column-names -e "$MYSQL_CHECK_IF_HAS_TABLE") 74 | if [ "$MYSQL_NUM_TABLE" -eq 0 ]; then 75 | echo "Database exists and has no tables yet, doing init"; 76 | $MYSQL_COMMAND -D "$PDNS_gmysql_dbname" < /usr/share/doc/pdns/schema.mysql.sql 77 | else 78 | echo "Database exists but already has tables, will not try to init"; 79 | fi 80 | fi 81 | } 82 | 83 | migrateDatabaseTo47() { 84 | # SQL migration to version 4.7 85 | MYSQL_CHECK_IF_47="SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = '${PDNS_gmysql_dbname}' AND table_name = 'domains' AND column_name = 'options';" 86 | MYSQL_NUM_TABLE=$($MYSQL_COMMAND --batch --skip-column-names -e "$MYSQL_CHECK_IF_47") 87 | if [ "$MYSQL_NUM_TABLE" -eq 0 ]; then 88 | echo 'Migrating MySQL schema to version 4.7...' 89 | $MYSQL_COMMAND -D "$PDNS_gmysql_dbname" < /usr/share/doc/pdns/4.3.0_to_4.7.0_schema.mysql.sql 90 | fi 91 | } 92 | 93 | initSuperslave() { 94 | if [ "${PDNS_autosecondary:-no}" = 'yes' ] || [ "${PDNS_superslave:-no}" = 'yes' ]; then 95 | # Configure supermasters if needed 96 | if [ "${SUPERMASTER_IPS:-}" ]; then 97 | $MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e 'TRUNCATE supermasters;' 98 | MYSQL_INSERT_SUPERMASTERS='' 99 | if [ "${SUPERMASTER_COUNT:-0}" -eq 0 ]; then 100 | SUPERMASTER_COUNT=10 101 | fi 102 | i=1; while [ $i -le "${SUPERMASTER_COUNT}" ]; do 103 | SUPERMASTER_HOST=$(echo "${SUPERMASTER_HOSTS:-}" | awk -v col="$i" '{ print $col }') 104 | SUPERMASTER_IP=$(echo "${SUPERMASTER_IPS}" | awk -v col="$i" '{ print $col }') 105 | if [ -z "${SUPERMASTER_HOST:-}" ]; then 106 | SUPERMASTER_HOST=$(hostname -f) 107 | fi 108 | if [ "${SUPERMASTER_IP:-}" ]; then 109 | MYSQL_INSERT_SUPERMASTERS="${MYSQL_INSERT_SUPERMASTERS} INSERT INTO supermasters VALUES('${SUPERMASTER_IP}', '${SUPERMASTER_HOST}', 'admin');" 110 | fi 111 | i=$(( i + 1 )) 112 | done 113 | $MYSQL_COMMAND -D "$PDNS_gmysql_dbname" -e "$MYSQL_INSERT_SUPERMASTERS" 114 | fi 115 | fi 116 | } 117 | 118 | generateAndInstallConfigFileFromEnvironment() { 119 | # Create config file from template 120 | subvars --prefix 'PDNS_' < '/pdns.conf.tpl' > '/etc/pdns/pdns.conf' 121 | } 122 | 123 | #### End of function definitions, let's get to work ... 124 | 125 | if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'true' ]; then 126 | deriveMySQLSettingsFromExistingConfigFile 127 | else 128 | deriveMySQLSettingsFromEnvironment 129 | fi 130 | 131 | generateMySQLCommand 132 | 133 | # Wait for MySQL to respond 134 | until $MYSQL_COMMAND -e ';' ; do 135 | >&2 echo 'MySQL is unavailable - sleeping' 136 | sleep 3 137 | done 138 | 139 | createDatabaseIfRequested 140 | initDatabase 141 | migrateDatabaseTo47 142 | initSuperslave 143 | 144 | if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'false' ]; then 145 | echo "(re-)generating config file from environment variables" 146 | generateAndInstallConfigFileFromEnvironment 147 | fi 148 | 149 | exec "$@" 150 | -------------------------------------------------------------------------------- /pdns-mysql/pdns.conf.tpl: -------------------------------------------------------------------------------- 1 | {{ range $key, $value := match "PDNS_" -}} 2 | {{- $key | trimPrefix "PDNS_" | replace "_" "-" }} = {{ $value }} 3 | {{ end -}} 4 | -------------------------------------------------------------------------------- /pdns-pgsql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ 5 | && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ 6 | && sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/fedora-cisco-openh264.repo \ 7 | && dnf --refresh upgrade \ 8 | && dnf install \ 9 | hostname \ 10 | pdns \ 11 | postgresql16 \ 12 | https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ 13 | && dnf --setopt 'tsflags=' install pdns-backend-postgresql \ 14 | && dnf clean all 15 | 16 | RUN mkdir -p /run/pdns \ 17 | && chown -R pdns: /etc/pdns /run/pdns 18 | 19 | COPY pdns.conf.tpl docker-entrypoint.sh / 20 | 21 | ENV VERSION=4.9 \ 22 | PDNS_guardian=yes \ 23 | PDNS_setuid=pdns \ 24 | PDNS_setgid=pdns \ 25 | PDNS_launch=gpgsql 26 | 27 | EXPOSE 53 53/udp 28 | 29 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["pdns_control", "ping"] 30 | 31 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 32 | 33 | CMD [ "/usr/sbin/pdns_server" ] 34 | -------------------------------------------------------------------------------- /pdns-pgsql/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && apk update \ 5 | && apk upgrade \ 6 | && apk add \ 7 | pdns \ 8 | pdns-backend-pgsql \ 9 | pdns-doc \ 10 | postgresql16-client \ 11 | && wget -O subvars.apk https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.apk \ 12 | && apk add --allow-untrusted subvars.apk \ 13 | && rm -rf subvars.apk /var/cache/apk/* 14 | 15 | RUN mkdir -p /run/pdns \ 16 | && chown -R pdns: /etc/pdns /run/pdns 17 | 18 | COPY pdns.conf.tpl docker-entrypoint.sh / 19 | 20 | ENV VERSION=4.9 \ 21 | PDNS_guardian=yes \ 22 | PDNS_setuid=pdns \ 23 | PDNS_setgid=pdns \ 24 | PDNS_launch=gpgsql 25 | 26 | EXPOSE 53 53/udp 27 | 28 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["pdns_control", "ping"] 29 | 30 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 31 | 32 | CMD [ "/usr/sbin/pdns_server" ] 33 | -------------------------------------------------------------------------------- /pdns-pgsql/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | : "${DEBUG:=0}" 6 | 7 | if [ "${DEBUG}" -eq 1 ]; then 8 | set -x 9 | fi 10 | 11 | ##### Function definitions #### 12 | 13 | derivePostgreSQLSettingsFromExistingConfigFile() { 14 | if [ ! -f /etc/pdns/pdns.conf ]; then 15 | echo "Use of existing file /etc/pdns/pdns.conf requested but file does not exist!" 16 | exit 1 17 | fi 18 | 19 | PDNS_gpgsql_host=$(sed -n 's/^gpgsql-host=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 20 | PDNS_gpgsql_port=$(sed -n 's/^gpgsql-port=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 21 | PDNS_gpgsql_user=$(sed -n 's/^gpgsql-user=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 22 | PDNS_gpgsql_password=$(sed -n 's/^gpgsql-password=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 23 | PDNS_gpgsql_dbname=$(sed -n 's/^gpgsql-dbname=\(.*\)/\1/p' < /etc/pdns/pdns.conf) 24 | } 25 | 26 | derivePostgreSQLSettingsFromEnvironment() { 27 | # Configure gpgsql env vars 28 | : "${PDNS_gpgsql_host:=pgsql}" 29 | : "${PDNS_gpgsql_port:=5432}" 30 | : "${PDNS_gpgsql_user:=${PGSQL_ENV_POSTGRES_USER:-postgres}}" 31 | : "${PDNS_gpgsql_password:=${PGSQL_ENV_POSTGRES_PASSWORD:-powerdns}}" 32 | : "${PDNS_gpgsql_dbname:=${PGSQL_ENV_POSTGRES_DB:-powerdns}}" 33 | 34 | # Use first part of node name as database name suffix 35 | if [ "${NODE_NAME:-}" ]; then 36 | NODE_NAME=$(echo "${NODE_NAME}" | sed -e 's/\..*//' -e 's/-//') 37 | PDNS_gpgsql_dbname="${PDNS_gpgsql_dbname}${NODE_NAME}" 38 | fi 39 | 40 | export PDNS_gpgsql_host PDNS_gpgsql_port PDNS_gpgsql_user PDNS_gpgsql_password PDNS_gpgsql_dbname 41 | } 42 | 43 | generatePostgreSQLCommand() { 44 | PGSQL_COMMAND="psql -h ${PDNS_gpgsql_host} -p ${PDNS_gpgsql_port} -U ${PDNS_gpgsql_user}" 45 | } 46 | 47 | createDatabaseIfRequested() { 48 | # Initialize DB if needed 49 | if [ "${SKIP_DB_CREATE:-false}" != 'true' ]; then 50 | echo "SELECT 'CREATE DATABASE ${PDNS_gpgsql_dbname}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${PDNS_gpgsql_dbname}')\gexec" | $PGSQL_COMMAND 51 | fi 52 | } 53 | 54 | initDatabase() { 55 | if [ "${SKIP_DB_INIT:-false}" != 'true' ]; then 56 | PGSQL_CHECK_IF_HAS_TABLE="SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_catalog = '${PDNS_gpgsql_dbname}' AND table_schema = 'public';" 57 | PGSQL_NUM_TABLE=$($PGSQL_COMMAND -At -d "$PDNS_gpgsql_dbname" -c "$PGSQL_CHECK_IF_HAS_TABLE") 58 | if [ "$PGSQL_NUM_TABLE" -eq 0 ]; then 59 | echo "Database exists and has no tables yet, doing init"; 60 | $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" < /usr/share/doc/pdns/schema.pgsql.sql 61 | else 62 | echo "Database exists but already has tables, will not try to init"; 63 | fi 64 | fi 65 | } 66 | 67 | initSuperslave() { 68 | if [ "${PDNS_autosecondary:-no}" = 'yes' ] || [ "${PDNS_superslave:-no}" = 'yes' ]; then 69 | # Configure supermasters if needed 70 | if [ "${SUPERMASTER_IPS:-}" ]; then 71 | $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" -c 'TRUNCATE supermasters;' 72 | PGSQL_INSERT_SUPERMASTERS='' 73 | if [ "${SUPERMASTER_COUNT:-0}" -eq 0 ]; then 74 | SUPERMASTER_COUNT=10 75 | fi 76 | i=1; while [ $i -le "${SUPERMASTER_COUNT}" ]; do 77 | SUPERMASTER_HOST=$(echo "${SUPERMASTER_HOSTS:-}" | awk -v col="$i" '{ print $col }') 78 | SUPERMASTER_IP=$(echo "${SUPERMASTER_IPS}" | awk -v col="$i" '{ print $col }') 79 | if [ -z "${SUPERMASTER_HOST:-}" ]; then 80 | SUPERMASTER_HOST=$(hostname -f) 81 | fi 82 | if [ "${SUPERMASTER_IP:-}" ]; then 83 | PGSQL_INSERT_SUPERMASTERS="${PGSQL_INSERT_SUPERMASTERS} INSERT INTO supermasters VALUES('${SUPERMASTER_IP}', '${SUPERMASTER_HOST}', 'admin');" 84 | fi 85 | i=$(( i + 1 )) 86 | done 87 | $PGSQL_COMMAND -d "$PDNS_gpgsql_dbname" -c "$PGSQL_INSERT_SUPERMASTERS" 88 | fi 89 | fi 90 | } 91 | 92 | generateAndInstallConfigFileFromEnvironment() { 93 | # Create config file from template 94 | subvars --prefix 'PDNS_' < '/pdns.conf.tpl' > '/etc/pdns/pdns.conf' 95 | } 96 | 97 | #### End of function definitions, let's get to work ... 98 | 99 | if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'true' ]; then 100 | derivePostgreSQLSettingsFromExistingConfigFile 101 | else 102 | derivePostgreSQLSettingsFromEnvironment 103 | fi 104 | 105 | generatePostgreSQLCommand 106 | 107 | PGPASSWORD="${PDNS_gpgsql_password}" 108 | export PGPASSWORD 109 | 110 | # Wait for pgsql to respond 111 | until $PGSQL_COMMAND -c ';' ; do 112 | >&2 echo 'Pgsql is unavailable - sleeping' 113 | sleep 3 114 | done 115 | 116 | createDatabaseIfRequested 117 | initDatabase 118 | initSuperslave 119 | 120 | if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'false' ]; then 121 | echo "(re-)generating config file from environment variables" 122 | generateAndInstallConfigFileFromEnvironment 123 | fi 124 | 125 | unset PGPASSWORD 126 | 127 | exec "$@" 128 | -------------------------------------------------------------------------------- /pdns-pgsql/pdns.conf.tpl: -------------------------------------------------------------------------------- 1 | {{ range $key, $value := match "PDNS_" -}} 2 | {{- $key | trimPrefix "PDNS_" | replace "_" "-" }} = {{ $value }} 3 | {{ end -}} 4 | -------------------------------------------------------------------------------- /pdns-recursor/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && echo 'install_weak_deps=False' >> /etc/dnf/dnf.conf \ 5 | && echo 'assumeyes=True' >> /etc/dnf/dnf.conf \ 6 | && sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/fedora-cisco-openh264.repo \ 7 | && dnf --refresh upgrade \ 8 | && dnf install \ 9 | pdns-recursor \ 10 | https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.rpm \ 11 | && dnf clean all 12 | 13 | RUN mkdir -p /etc/pdns-recursor/api.d /run/pdns-recursor \ 14 | && chown -R pdns-recursor: /etc/pdns-recursor /run/pdns-recursor 15 | 16 | COPY recursor.conf.tpl docker-entrypoint.sh / 17 | 18 | ENV VERSION=5.1 \ 19 | PDNS_setuid=pdns-recursor \ 20 | PDNS_setgid=pdns-recursor \ 21 | PDNS_daemon=no \ 22 | PDNS_loglevel=5 23 | 24 | EXPOSE 53 53/udp 25 | 26 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["rec_control", "ping"] 27 | 28 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 29 | 30 | CMD [ "/usr/sbin/pdns_recursor" ] 31 | -------------------------------------------------------------------------------- /pdns-recursor/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21 2 | 3 | RUN arch=$([ "$(arch)" = 'aarch64' ] && echo -n 'arm64' || echo -n 'amd64') \ 4 | && apk update \ 5 | && apk upgrade \ 6 | && apk add pdns-recursor \ 7 | && wget -O subvars.apk https://github.com/TektonOps/subvars/releases/download/v0.1.5/subvars_${arch}.apk \ 8 | && apk add --allow-untrusted subvars.apk \ 9 | && rm -rf subvars.apk /var/cache/apk/* 10 | 11 | RUN mkdir -p /etc/pdns/api.d /var/run/pdns-recursor \ 12 | && chown -R recursor: /etc/pdns /var/run/pdns-recursor 13 | 14 | COPY recursor.conf.tpl docker-entrypoint.sh / 15 | 16 | ENV VERSION=5.1 \ 17 | PDNS_setuid=recursor \ 18 | PDNS_setgid=recursor \ 19 | PDNS_daemon=no \ 20 | PDNS_loglevel=5 21 | 22 | EXPOSE 53 53/udp 23 | 24 | HEALTHCHECK --interval=10s --timeout=10s --retries=3 --start-period=2s CMD ["rec_control", "ping"] 25 | 26 | ENTRYPOINT [ "/docker-entrypoint.sh" ] 27 | 28 | CMD [ "/usr/sbin/pdns_recursor" ] 29 | -------------------------------------------------------------------------------- /pdns-recursor/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | : "${DEBUG:=0}" 6 | 7 | if [ "${DEBUG}" -eq 1 ]; then 8 | set -x 9 | fi 10 | 11 | #### Function definitions 12 | 13 | deriveConfigValuesFromEnvironment() { 14 | # Configure base vars 15 | : "${PDNS_local_port:=53}" 16 | : "${PDNS_local_address:=0.0.0.0}" 17 | : "${PDNS_allow_from:=0.0.0.0/0}" 18 | 19 | export PDNS_local_port PDNS_local_address PDNS_allow_from 20 | } 21 | 22 | ### End of function definitions 23 | 24 | if [ -f /etc/fedora-release ]; then 25 | config_file=/etc/pdns-recursor/recursor.conf 26 | pdns_user=pdns-recursor 27 | elif [ -f /etc/alpine-release ]; then 28 | config_file=/etc/pdns/recursor.conf 29 | pdns_user=recursor 30 | fi 31 | 32 | if [ "${USE_EXISTING_CONFIG_FILE:-false}" = 'false' ]; then 33 | deriveConfigValuesFromEnvironment 34 | echo "Generating config file from environment" 35 | subvars --prefix 'PDNS_' < '/recursor.conf.tpl' > "${config_file}" 36 | chown "${pdns_user}:" "${config_file}" 37 | else 38 | echo "Using existing config file ${config_file}" 39 | fi 40 | 41 | exec "$@" 42 | -------------------------------------------------------------------------------- /pdns-recursor/recursor.conf.tpl: -------------------------------------------------------------------------------- 1 | {{ range $key, $value := match "PDNS_" -}} 2 | {{- $key | trimPrefix "PDNS_" | replace "_" "-" }} = {{ $value }} 3 | {{ end -}} 4 | --------------------------------------------------------------------------------