diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..43a0bad --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.git +.github +.gitignore +.DS_Store + +config.yaml +config.yml + +build +dist +tmp +*.log +*.out diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..ce92c34 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,109 @@ +name: docker + +on: + pull_request: + push: + branches: + - "**" + tags: + - "v*" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + docker-ci: + name: Build Docker image + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build test image + uses: docker/build-push-action@v7 + with: + context: . + load: true + tags: wiregold:test + build-args: | + VERSION=ci-${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Smoke test help output + run: docker run --rm wiregold:test -h + + - name: Smoke test key generation + run: docker run --rm wiregold:test -g + + - name: Smoke test preshared key generation + run: docker run --rm wiregold:test -pg + + - name: Smoke test missing TUN message + run: | + set -euo pipefail + output="$(docker run --rm wiregold:test 2>&1 || true)" + printf '%s\n' "$output" + printf '%s' "$output" | grep -F "WireGold requires /dev/net/tun inside the container." + + docker-publish: + name: Publish GHCR image + runs-on: ubuntu-latest + needs: docker-ci + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) + permissions: + contents: read + packages: write + steps: + - name: Check out code + 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 GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') || github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }} + labels: | + org.opencontainers.image.title=WireGold + org.opencontainers.image.description=Container image for WireGold, a pure-Go Layer 3 VPN inspired by WireGuard. + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v7 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + annotations: ${{ steps.meta.outputs.annotations }} + build-args: | + VERSION=${{ steps.meta.outputs.version }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c0041e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +# syntax=docker/dockerfile:1.7 + +FROM --platform=$TARGETPLATFORM golang:1.25.0-bookworm AS build + +ARG VERSION=dev + +WORKDIR /src + +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY . . + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go build -trimpath -ldflags="-s -w -checklinkname=0 -X github.com/fumiama/WireGold/config.Version=${VERSION}" \ + -o /out/wg . + +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND=noninteractive + +LABEL org.opencontainers.image.title="WireGold" \ + org.opencontainers.image.description="Container image for WireGold, a pure-Go Layer 3 VPN inspired by WireGuard." \ + org.opencontainers.image.source="https://github.com/fumiama/WireGold" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates iproute2 tini \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /config + +COPY --from=build /out/wg /usr/local/bin/wg +COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh + +RUN chmod +x /usr/local/bin/wg /usr/local/bin/docker-entrypoint.sh \ + && mkdir -p /config + +VOLUME ["/config"] + +ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"] +CMD ["-c", "/config/config.yaml"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..ffb54ec --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,42 @@ +#!/bin/sh +set -eu + +if [ "$#" -eq 0 ]; then + set -- /usr/local/bin/wg -c /config/config.yaml +elif [ "${1#-}" != "$1" ]; then + set -- /usr/local/bin/wg "$@" +fi + +if [ "${1:-}" = "/usr/local/bin/wg" ]; then + need_config=1 + config_path=/config/config.yaml + prev= + + for arg in "$@"; do + case "$arg" in + -g|-pg|-h) + need_config=0 + ;; + esac + + if [ "$prev" = "-c" ]; then + config_path="$arg" + fi + prev="$arg" + done + + if [ "$need_config" -eq 1 ] && [ ! -c /dev/net/tun ]; then + echo "WireGold requires /dev/net/tun inside the container." >&2 + echo "Run with: --device /dev/net/tun --cap-add NET_ADMIN" >&2 + echo "If Network is icmp or ip, add --cap-add NET_RAW as well." >&2 + exit 1 + fi + + if [ "$need_config" -eq 1 ] && [ ! -f "$config_path" ]; then + echo "WireGold config not found: $config_path" >&2 + echo "Mount your config into /config or override -c." >&2 + exit 1 + fi +fi + +exec "$@"