Base image for compiling LumeWeb Portal with custom plugins via xportal. Designed for use with docker buildx multi-stage builds.
- Base image pattern: Extend in your own Dockerfile for custom builds
- Pre-configured build environment: Based on
golang:1.25-alpine - xportal binary: Pre-installed for building Portal
- yq YAML parser: For parsing plugin manifests
- JSON schema validation: Built-in validation for plugin manifests
- Flexible configuration: Supports both YAML manifests and environment variables
- Custom Portal versions: Build any Portal version via
PORTAL_VERSION - Go module cache: Pre-populated with Portal core dependencies for faster builds
The portal-builder image includes a pre-populated Go module cache at /go/pkg/mod to significantly speed up builds in child images.
- The image pre-downloads the Portal core module (
go.lumeweb.com/portal@develop) during the build process - When child images run
build-portal, xportal uses the cached modules instead of downloading them - The
GOMODCACHEenvironment variable is set to/go/pkg/modto ensure consistent cache location
- Faster builds: Cached modules are available instantly, reducing download time
- Reduced network usage: Dependencies are only downloaded once when building the base image
- Consistent builds: All child images use the same cached dependencies
- The cache includes only the Portal core module at
latestversion - Custom plugins not in the cache will still be downloaded during builds
- Different Portal versions (e.g.,
develop, specific tags) may require additional downloads
If you need to cache additional modules or specific versions, you can extend the builder image:
FROM ghcr.io/lumeweb/portal-builder:latest AS builder
# Cache specific plugin dependencies
WORKDIR /tmp/plugin-cache
RUN go mod init plugin-cache && \
go get go.lumeweb.com/portal-plugin-dashboard@latest && \
go mod download && \
rm -rf /tmp/plugin-cache
COPY portal-plugins.yaml .
RUN build-portalCreate a Dockerfile:
FROM ghcr.io/lumeweb/portal-builder:latest AS builder
COPY portal-plugins.yaml .
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]Create a portal-plugins.yaml:
plugins:
- module: go.lumeweb.com/portal-plugin-dashboard
version: latest
- module: go.lumeweb.com/portal-plugin-core
version: latestBuild your image:
docker build -t my-portal .# Build stage
FROM ghcr.io/lumeweb/portal-builder:latest AS builder
# Copy configuration
COPY portal-plugins.yaml .
# Optional: Set portal version via ARG/ENV
ARG PORTAL_VERSION=latest
ENV PORTAL_VERSION=${PORTAL_VERSION}
# Build portal
RUN build-portal
# Runtime stage
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]FROM ghcr.io/lumeweb/portal-builder:latest AS builder
ARG PORTAL_VERSION=develop
ENV PORTAL_VERSION=${PORTAL_VERSION}
COPY portal-plugins.yaml .
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]Build:
docker build --build-arg PORTAL_VERSION=develop -t my-portal .FROM ghcr.io/lumeweb/portal-builder:latest AS builder
ARG PORTAL_VERSION=a1b2c3d
ENV PORTAL_VERSION=${PORTAL_VERSION}
COPY portal-plugins.yaml .
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]Build:
docker build --build-arg PORTAL_VERSION=a1b2c3d -t my-portal .Or use full hash:
docker build --build-arg PORTAL_VERSION=a1b2c3d4e5f6789012345678901234567890abcd -t my-portal .FROM ghcr.io/lumeweb/portal-builder:latest AS builder
ARG PLUGINS
ENV PLUGINS=${PLUGINS}
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]Build:
docker build --build-arg PLUGINS="go.lumeweb.com/portal-plugin-core@develop" -t my-portal .Create portal-plugins.yaml:
portalVersion: develop # Optional: Portal core version (supports semantic version, latest, develop, or git hash)
plugins:
- module: go.lumeweb.com/portal-plugin-dashboard
version: latest
- module: go.lumeweb.com/portal-plugin-core
version: latestOr with git hashes:
portalVersion: a1b2c3d
plugins:
- module: go.lumeweb.com/portal-plugin-dashboard
version: a1b2c3d
- module: go.lumeweb.com/portal-plugin-core
version: a1b2c3d4e5f6789012345678901234567890abcdFROM ghcr.io/lumeweb/portal-builder:latest AS builder
ENV PORTAL_VERSION=develop
ENV PLUGINS="go.lumeweb.com/portal-plugin-dashboard@latest,go.lumeweb.com/portal-plugin-core@latest"
RUN build-portalBoth sources can be used together - plugins from both will be combined.
| Variable | Description | Default |
|---|---|---|
PORTAL_VERSION |
Portal core version to build | latest |
PLUGINS |
Comma or space-separated plugin list (format: module@version) |
- |
PLUGIN_MANIFEST |
Path to YAML plugin manifest | portal-plugins.yaml |
OUTPUT_DIR |
Output directory for compiled binary | /dist |
SCHEMA_PATH |
Path to JSON schema for validation | /usr/local/share/portal-builder/schema.json |
portalVersion: develop # Optional: Portal core version (supports semantic version, latest, develop, or git hash)
plugins:
- module: go.lumeweb.com/portal-plugin-example # Go module path (required)
version: latest # Version (supports semantic version, latest, develop, or git hash)The manifest is validated against the built-in schema. The schema enforces:
module: Go module path (alphanumeric, dots, slashes, hyphens, underscores)version: Semantic version,latest,develop, or git hash (e.g.,v1.0.0,1.2.3,latest,v2.0.0-beta.1,a1b2c3d,a1b2c3d4e5f6789012345678901234567890abcd)portalVersion: Portal core version (optional, supportslatest,develop, semantic versions, or git hashes)
FROM ghcr.io/lumeweb/portal-builder:latest AS builder
COPY custom-schema.json /usr/local/share/portal-builder/schema.json
COPY portal-plugins.yaml .
RUN build-portalBuild for multiple platforms:
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t my-portal:latest \
--push \
.FROM ghcr.io/lumeweb/portal-builder:latest AS builder
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]FROM ghcr.io/lumeweb/portal-builder:latest AS builder
ENV PORTAL_VERSION=develop
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]FROM ghcr.io/lumeweb/portal-builder:latest AS builder
ARG PORTAL_VERSION=latest
ENV PORTAL_VERSION=${PORTAL_VERSION}
COPY portal-plugins.yaml .
RUN build-portal
FROM alpine:latest
COPY --from=builder /dist/portal /usr/local/bin/portal
CMD ["portal"]- Plugin versions support semantic versioning (e.g.,
v1.2.3),latest,develop, or git hashes - The
@latestversion can be omitted (e.g.,go.lumeweb.com/plugin@latest=go.lumeweb.com/plugin) - All plugins are built into a single Portal binary
- The build process requires internet access to download Go modules
- The image includes a non-root user setup following security best practices
- Go module cache is pre-populated, but custom plugins may still need downloads
When using git hashes for portalVersion or plugin versions, the following validation rules apply:
- Minimum length: 7 characters
- Maximum length: 40 characters
- Character set: Only lowercase hexadecimal characters (
0-9,a-f) - Case sensitivity: Must be lowercase (uppercase hashes will be rejected)
# Short hash (7 characters)
portalVersion: 84c073f
# Medium hash (8 characters)
version: bfc88b3c
# Full hash (40 characters)
version: 84c073f181430439ca4dd539064480748cd654a0The following formats will be rejected by schema validation:
- Too short:
84c073(6 characters) - Too long:
84c073f181430439ca4dd539064480748cd654a01(41 characters) - Uppercase:
84C073F(must be lowercase) - Invalid characters:
g1b2c3d(contains 'g' which is not a valid hex character) - Mixed case:
A1b2C3d(must be all lowercase)
- Use exact git commit hashes from your repository
- Short hashes (7-8 characters) are sufficient for most use cases
- Full hashes (40 characters) provide complete uniqueness
- Always verify hashes are lowercase before using them in manifests
Build and push to GHCR:
docker build -t ghcr.io/lumeweb/portal-builder:latest .
docker push ghcr.io/lumeweb/portal-builder:latestTest changes locally:
# Build the builder image
docker build -t portal-builder .
# Test with example
docker build -f Dockerfile.example -t my-portal .
# Run the built portal
docker run -p 8080:8080 my-portal