Files
pangolin/Dockerfile.dns
T

91 lines
3.3 KiB
Docker

# Standalone image that runs only the authoritative DNS server
# (server/private/dnsServer.ts) against an existing Pangolin database.
#
# Build: docker build -f Dockerfile.dns -t pangolin-dns .
# Run: docker run -v ./config:/app/config -p 53:53/udp pangolin-dns
#
# The mounted config directory needs the same config.yml (database
# connection) and privateConfig.yml (dns section with
# enabled: true) as the Pangolin server whose database it reads.
# Mirror of docker.io/library/node, kept in sync by
# .github/workflows/mirror-node.yml (avoids Docker Hub / ECR pull rate limits)
ARG NODE_IMAGE=ghcr.io/fosrl/node:24.22.1-slim
FROM ${NODE_IMAGE} AS builder
WORKDIR /app
COPY package.json ./
# esbuild.mjs marks every npm package external, so bundling needs only the
# bundler's own tooling (at the versions package.json pins), not the full
# dependency tree. Installed outside /app so the root package.json's
# dependencies aren't pulled in with it.
RUN mkdir /tools && cd /tools && echo '{"private": true}' > package.json && \
npm install --no-audit --no-fund --no-package-lock $(node -p ' \
const p = require("/app/package.json"); \
const all = { ...p.dependencies, ...p.devDependencies }; \
["esbuild", "esbuild-node-externals", "yargs"] \
.map((n) => `${n}@${all[n]}`).join(" ")') && \
ln -s /tools/node_modules /app/node_modules
COPY . .
# The DNS server is private code, so only saas/enterprise builds include it
ARG BUILD=enterprise
ARG DATABASE=pg
# Bundle, then write a package.json listing only the packages the bundle
# imports at runtime
RUN npm run set:$DATABASE && \
npm run set:$BUILD && \
mkdir -p dist && \
node esbuild.mjs -e server/private/dnsServer.ts -o dist/dns.mjs -m dist/dns.meta.json && \
node scripts/bundle-package-json.mjs dist/dns.meta.json /out/package.json
FROM ${NODE_IMAGE} AS deps
WORKDIR /app
# Installing the trimmed package.json against the root lockfile keeps every
# transitive version pinned to what the main Pangolin image ships
COPY --from=builder /out/package.json ./package.json
COPY package-lock.json .npmrc ./
RUN npm install --omit=dev --no-audit --no-fund
FROM ${NODE_IMAGE} AS runner
WORKDIR /app
RUN apt-get update && apt-get install -y tzdata && rm -rf /var/lib/apt/lists/*
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/package.json ./package.json
COPY --from=builder /app/dist/dns.mjs ./dist/dns.mjs
ENV ENVIRONMENT=prod
ENV NODE_ENV=production
EXPOSE 53/udp
# HTTP health check (GET /healthz)
EXPOSE 8053/tcp
ARG VERSION="dev"
ARG REVISION=""
ARG CREATED=""
LABEL org.opencontainers.image.source="https://github.com/fosrl/pangolin" \
org.opencontainers.image.url="https://github.com/fosrl/pangolin" \
org.opencontainers.image.documentation="https://docs.pangolin.net" \
org.opencontainers.image.vendor="Fossorial" \
org.opencontainers.image.licenses="Fossorial Commercial License" \
org.opencontainers.image.title="Pangolin DNS" \
org.opencontainers.image.description="Standalone Pangolin authoritative DNS server" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${REVISION}" \
org.opencontainers.image.created="${CREATED}"
CMD ["node", "--disable-warning=ExperimentalWarning", "--enable-source-maps", "dist/dns.mjs"]