├── .github └── workflows │ └── build.yaml ├── .gitignore ├── Dockerfile ├── Makefile └── readme.md /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Publish Headscale Drep Server image 2 | 3 | on: 4 | push 5 | 6 | env: 7 | REGISTRY: ghcr.io 8 | IMAGE_NAME: ${{ github.repository }} 9 | 10 | jobs: 11 | push_to_registry: 12 | name: Push Headscale Drep server to github packages 13 | runs-on: ubuntu-latest 14 | permissions: 15 | packages: write 16 | contents: read 17 | attestations: write 18 | id-token: write 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | 23 | - name: Log in to the Container registry 24 | uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 25 | with: 26 | registry: ${{ env.REGISTRY }} 27 | username: ${{ github.actor }} 28 | password: ${{ secrets.GITHUB_TOKEN }} 29 | 30 | - name: Extract metadata (tags, labels) for Docker 31 | id: meta 32 | uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 33 | with: 34 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 35 | 36 | - name: Build and push Docker image 37 | id: push 38 | uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 39 | with: 40 | context: . 41 | push: true 42 | tags: ${{ steps.meta.outputs.tags }} 43 | labels: ${{ steps.meta.outputs.labels }} 44 | - name: Generate artifact attestation 45 | uses: actions/attest-build-provenance@v1 46 | with: 47 | subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} 48 | subject-digest: ${{ steps.push.outputs.digest }} 49 | push-to-registry: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | inventory/prod.yaml -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang as builder 2 | 3 | WORKDIR /app 4 | 5 | # Install tailscale derper 6 | # https://tailscale.com/kb/1118/custom-derp-servers/ 7 | 8 | RUN git clone https://github.com/tailscale/tailscale/ && \ 9 | cd tailscale && \ 10 | CGO_ENABLED=0 go build -o derper ./cmd/derper/ 11 | 12 | 13 | FROM busybox 14 | 15 | LABEL maintainer="Tailscale/Headscale Derp server " 16 | 17 | ENV LANG C.UTF-8 18 | # 19 | ENV DERP_DOMAIN example.com 20 | ENV DERP_CERT_MODE letsencrypt 21 | ENV DERP_CERT_DIR /app/certs 22 | ENV DERP_ADDR :443 23 | ENV DERP_STUN true 24 | ENV DERP_HTTP_PORT 80 25 | ENV DERP_VERIFY_CLIENTS false 26 | 27 | WORKDIR /app 28 | 29 | COPY --from=builder /app/tailscale/derper . 30 | 31 | 32 | CMD /app/derper -hostname=$DERP_DOMAIN \ 33 | -certmode=$DERP_CERT_MODE \ 34 | -certdir=$DERP_CERT_DIR \ 35 | -a=$DERP_ADDR \ 36 | -stun=$DERP_STUN \ 37 | -http-port=$DERP_HTTP_PORT \ 38 | -verify-clients=$DERP_VERIFY_CLIENTS -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # make docker images 2 | 3 | 4 | local_image: 5 | docker buildx build --platform linux/arm64,linux/amd64 -t derp-server:v1 . --load 6 | 7 | 8 | ghcr_image: 9 | docker buildx build --platform linux/arm64,linux/amd64 -t ghcr.io/slchris/derp-server:v1 . --push -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # tailscale/headscale derp server 2 | 3 | For fast deployment of derp servers 4 | 5 | 6 | # easy to deploy 7 | 8 | Preparatory 9 | 10 | - domain DNS record (A、AAAA or CNAME) e.g example.com 11 | - certificate 12 | - docker 13 | 14 | 15 | Before you start you need to generate a certificate, which can be used certbot: 16 | 17 | ```shell 18 | docker run -it --rm --name certbot \ 19 | -p 80:80 \ 20 | -v "/etc/letsencrypt:/etc/letsencrypt" \ 21 | -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ 22 | certbot/certbot certonly 23 | ``` 24 | 25 | Follow the prompts to generate the corresponding certificate. 26 | 27 | 28 | deploy derp server: 29 | 30 | ```shell 31 | docker run --restart always \ 32 | --name derper -p 12345:443 -p 3478:3478/udp \ 33 | -v /etc/letsencrypt/live/example.com/fullchain.pem:/app/certs/example.com.crt \ 34 | -v /etc/letsencrypt/live/example.com/privkey.pem:/app/certs/example.com.key \ 35 | -e derp_CERT_MODE=manual \ 36 | -e derp_DOMAIN=example.com \ 37 | -d ghcr.io/slchris/derp-server:v1 38 | ``` 39 | 40 | 41 | ## easy to use 42 | 43 | 44 | ### headscale 45 | 46 | 47 | For headscale we need to modify the configuration to create a derp and then have headscale read that configuration. 48 | 49 | ```shell 50 | vi /etc/headscale/derp.yaml 51 | ``` 52 | 53 | The contents: 54 | 55 | ```yaml 56 | regions: 57 | 900: 58 | regionid: 900 59 | regioncode: lv 60 | regionname: Las Vegas, Nevada 61 | nodes: 62 | - name: 900a 63 | regionid: 900 64 | hostname: example.com 65 | stunport: 3478 66 | derpport: 12345 67 | ``` 68 | 69 | Modify the headscale main configuration as follows: 70 | 71 | ```yaml 72 | # vi /etc/headscale/config.yaml 73 | derp: 74 | # List of externally available derp maps encoded in JSON 75 | #urls: 76 | # - https://controlplane.tailscale.com/derpmap/default 77 | 78 | # Locally available derp map files encoded in YAML 79 | # 80 | # This option is mostly interesting for people hosting 81 | # their own derp servers: 82 | # https://tailscale.com/kb/1118/custom-derp-servers/ 83 | # 84 | # paths: 85 | # - /etc/headscale/derp-example.yaml 86 | paths: 87 | - /etc/headscale/derp.yaml 88 | 89 | # If enabled, a worker will be set up to periodically 90 | # refresh the given sources and update the derpmap 91 | # will be set up. 92 | auto_update_enabled: true 93 | 94 | # How often should we check for derp updates? 95 | update_frequency: 24h 96 | ``` 97 | 98 | for test, we can comment out the following two lines: 99 | 100 | ```yaml 101 | #urls: 102 | # - https://controlplane.tailscale.com/derpmap/default 103 | ``` 104 | 105 | Restart the headscale service: 106 | 107 | ```shell 108 | systemctl restart headscale 109 | ``` 110 | 111 | Check the link status on the client: 112 | 113 | ```shell 114 | tailscale netcheck 115 | ``` 116 | --------------------------------------------------------------------------------