udphole

Basic UDP wormhole proxy
git clone git://git.finwo.net/app/udphole
Log | Files | Refs | README | LICENSE

commit cbf4c967161ed814b903a636929817a6bbe8dd1e
parent 81d004b7644d9871420abd06cef84b8bc667e535
Author: Robin Bron <robin.bron@yourhosting.nl>
Date:   Mon,  2 Mar 2026 22:51:40 +0100

Docker setup

Diffstat:
A.github/workflows/docker.yml | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ADockerfile | 37+++++++++++++++++++++++++++++++++++++
Adocker-compose.yml | 24++++++++++++++++++++++++
Aentrypoint.sh | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 215 insertions(+), 0 deletions(-)

diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml @@ -0,0 +1,68 @@ +--- +name: Docker Build & Push + +on: + push: + branches: + - main + - '*.feature' + - '*.fix' + tags: + - 'v*' + pull_request: + branches: + - main + workflow_dispatch: + +env: + REGISTRY: docker.io + IMAGE_NAME: finwo/udphole + +jobs: + docker: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}}.{{minor}}.{{patch}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64/v8,linux/riscv64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile @@ -0,0 +1,37 @@ +FROM debian:bookworm-slim AS builder + +RUN apt-get update && apt-get install -y \ + gcc \ + make \ + wget \ + crossbuild-essential-amd64 \ + crossbuild-essential-arm64 \ + crossbuild-essential-riscv64 + +RUN wget -O /usr/local/bin/dep https://raw.githubusercontent.com/finwo/dep/master/dep && \ + chmod +x /usr/local/bin/dep + +WORKDIR /src +COPY . . + +RUN dep ensure && \ + make -j \ + CC=aarch64-linux-gnu-gcc CFLAGS="-static-libgcc" TARGETARCH=arm64 && \ + mv udphole udphole-arm64 && \ + make clean && \ + make -j \ + CC=riscv64-linux-gnu-gcc CFLAGS="-static-libgcc" TARGETARCH=riscv64 && \ + mv udphole udphole-riscv64 && \ + make clean && \ + make -j \ + CC=gcc CFLAGS="-static-libgcc" TARGETARCH=amd64 && \ + mv udphole udphole-amd64 + +FROM --platform=${TARGETPLATFORM} busybox:latest + +COPY --from=builder /src/udphole-${TARGETARCH} /usr/bin/udphole +COPY entrypoint.sh /etc/rc.local + +RUN chmod +x /etc/rc.local + +ENTRYPOINT ["/bin/ash", "/etc/rc.local"] diff --git a/docker-compose.yml b/docker-compose.yml @@ -0,0 +1,24 @@ +services: + udphole: + build: + context: . + platforms: + - linux/amd64 + - linux/arm64/v8 + - linux/riscv64 + ports: + - "${API_PORT:-6379}:${API_PORT:-6379}" + - "7000-7999:7000-7999/udp" + volumes: + - ./udphole.conf:/etc/udphole.conf:ro + environment: + - API_PORT=6379 + - UDP_PORTS=7000-7999 + - LOG_LEVEL=info + - API_ADMIN_USER=admin + - API_ADMIN_PASS=supers3cret + healthcheck: + test: ["CMD", "nc", "-z", "localhost", "6379"] + interval: 10s + timeout: 5s + retries: 3 diff --git a/entrypoint.sh b/entrypoint.sh @@ -0,0 +1,86 @@ +#!/bin/sh +set -e + +CONFIG_PATH="/etc/udphole.conf" +UDPHBIN="/usr/bin/udphole" + +if [ -f "$CONFIG_PATH" ]; then + echo "Using mounted config: $CONFIG_PATH" +else + echo "Generating config from environment variables..." + + { + echo "[udphole]" + echo "ports = ${UDP_PORTS:-7000-7999}" + echo "listen = :${API_PORT:-6379}" + + if [ -n "$CLUSTER" ]; then + for name in $(echo "$CLUSTER" | tr ',' ' '); do + echo "cluster = $name" + done + fi + + echo "" + echo "[user:${API_ADMIN_USER:-admin}]" + echo "permit = *" + echo "secret = ${API_ADMIN_PASS:-supers3cret}" + + if [ -n "$CLUSTER" ]; then + for name in $(echo "$CLUSTER" | tr ',' ' '); do + env_var="CLUSTER_$name" + eval "value=\$$env_var" + if [ -n "$value" ]; then + proto="${value%%://*}" + rest="${value#*://}" + + # Check if URL contains user:pass@ (has credentials) + case "$rest" in + *@*) + user="${rest%%:*}" + rest="${rest#*:}" + pass="${rest%%@*}" + rest="${rest#*@}" + has_creds=1 + ;; + *) + user="" + pass="" + has_creds=0 + ;; + esac + + host="${rest%%:*}" + port="${rest#*:}" + + echo "" + echo "[cluster:$name]" + echo "address = $value" + if [ "$has_creds" -eq 1 ]; then + echo "username = $user" + echo "password = $pass" + fi + fi + done + fi + } > "$CONFIG_PATH" + + echo "Generated config:" + cat "$CONFIG_PATH" +fi + +CMD="$UDPHBIN" + +if [ -n "$LOG_LEVEL" ]; then + CMD="$CMD --verbosity $LOG_LEVEL" +fi + +if [ -n "$CLUSTER" ]; then + CMD="$CMD cluster" +else + CMD="$CMD daemon" +fi + +CMD="$CMD --no-daemonize" + +echo "Running: $CMD" +exec $CMD