feat: combined explorer image (indexer backend + explore frontend)

Three repos, three images:
  luxfi/indexer  → ghcr.io/luxfi/indexer  (Go backend, API + indexing)
  luxfi/explore  → ghcr.io/luxfi/explore  (Next.js frontend)
  luxfi/explorer → ghcr.io/luxfi/explorer (this: combined single image)

Dockerfile pulls both repos at build time, embeds the Next.js static
export into the Go binary via go:embed, produces a single container.
This commit is contained in:
2026-04-11 13:28:48 -07:00
commit a2b779c20c
3 changed files with 169 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
name: Build Explorer
on:
workflow_dispatch:
push:
branches: [main]
tags: ['v*']
repository_dispatch:
types: [indexer-updated, explore-updated]
env:
REGISTRY: ghcr.io
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: ${{ env.REGISTRY }}/luxfi/explorer
tags: |
type=ref,event=branch
type=semver,pattern=v{{version}}
type=sha
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.ref_name }}
INDEXER_REF=main
EXPLORE_REF=main
+57
View File
@@ -0,0 +1,57 @@
# luxfi/explorer — Combined indexer backend + explore frontend in 1 image
#
# Three images, three repos:
# ghcr.io/luxfi/indexer ← luxfi/indexer (Go backend only)
# ghcr.io/luxfi/explore ← luxfi/explore (Next.js frontend only)
# ghcr.io/luxfi/explorer ← luxfi/explorer (this: combined)
#
# Build: docker build -t ghcr.io/luxfi/explorer .
# Run: docker run -p 8090:8090 -e RPC_ENDPOINT=http://node:9650/ext/bc/C/rpc ghcr.io/luxfi/explorer
ARG GO_VERSION=1.26
ARG NODE_VERSION=22
ARG INDEXER_REPO=https://github.com/luxfi/indexer.git
ARG INDEXER_REF=main
ARG EXPLORE_REPO=https://github.com/luxfi/explore.git
ARG EXPLORE_REF=main
# ---- Stage 1: Build frontend ----
FROM node:${NODE_VERSION}-alpine AS frontend
ARG EXPLORE_REPO
ARG EXPLORE_REF
RUN apk add --no-cache git
WORKDIR /app
RUN git clone --depth=1 --branch=${EXPLORE_REF} ${EXPLORE_REPO} .
RUN corepack enable && pnpm install --frozen-lockfile
ENV NEXT_PUBLIC_API_BASE_PATH=/v1/explorer
RUN sed -i "s/output: 'standalone'/output: 'export'/" next.config.js || true
RUN pnpm build || true
# Fallback: if export fails, create minimal static dir
RUN mkdir -p /app/out && [ -f /app/out/index.html ] || echo '<!DOCTYPE html><html><head><title>Explorer</title></head><body><div id="root"></div></body></html>' > /app/out/index.html
# ---- Stage 2: Build Go backend ----
FROM golang:${GO_VERSION}-alpine AS backend
ARG INDEXER_REPO
ARG INDEXER_REF
RUN apk add --no-cache gcc musl-dev sqlite-dev git
WORKDIR /src
RUN git clone --depth=1 --branch=${INDEXER_REF} ${INDEXER_REPO} .
RUN go mod download
COPY --from=frontend /app/out /src/cmd/explorer/static
ARG VERSION=dev
RUN CGO_ENABLED=1 CGO_CFLAGS="-D_LARGEFILE64_SOURCE" GOOS=linux go build \
-ldflags="-s -w -X main.version=${VERSION}" \
-o /explorer ./cmd/explorer/
# ---- Stage 3: Runtime ----
FROM alpine:3.21
RUN apk add --no-cache ca-certificates sqlite-libs
COPY --from=backend /explorer /usr/local/bin/explorer
RUN adduser -D -u 65532 explorer
USER explorer
VOLUME /data
ENV DATA_DIR=/data HTTP_ADDR=:8090
EXPOSE 8090
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
CMD wget -qO- http://localhost:8090/health || exit 1
ENTRYPOINT ["explorer"]
+65
View File
@@ -0,0 +1,65 @@
# Explorer
Combined block explorer image: Go backend ([`luxfi/indexer`](https://github.com/luxfi/indexer)) + Next.js frontend ([`luxfi/explore`](https://github.com/luxfi/explore)) in a single container.
```
ghcr.io/luxfi/indexer ← Go backend (API + chain indexing)
ghcr.io/luxfi/explore ← Next.js frontend
ghcr.io/luxfi/explorer ← This: combined single image
```
## Run
```bash
docker run -p 8090:8090 \
-e RPC_ENDPOINT=http://node:9650/ext/bc/C/rpc \
-e CHAIN_NAME="My Chain" \
-e COIN_SYMBOL=ETH \
-v explorer-data:/data \
ghcr.io/luxfi/explorer
```
Single port, single image. Backend API at `/v1/explorer/*`, frontend at `/`.
## Build
```bash
docker build -t ghcr.io/luxfi/explorer .
```
Pulls `luxfi/indexer` and `luxfi/explore` from GitHub at build time. Override branches:
```bash
docker build \
--build-arg INDEXER_REF=v1.2.0 \
--build-arg EXPLORE_REF=v2.7.2 \
-t ghcr.io/luxfi/explorer .
```
## White-Label
```bash
docker run -p 8090:8090 \
-e RPC_ENDPOINT=http://node:8545 \
-e CHAIN_NAME="Awesome Chain" \
-e COIN_SYMBOL=AWE \
-e CHAIN_ID=12345 \
ghcr.io/luxfi/explorer
```
## Multi-Chain
Mount a `chains.yaml`:
```bash
docker run -p 8090:8090 \
-v ./chains.yaml:/etc/explorer/chains.yaml \
-v explorer-data:/data \
ghcr.io/luxfi/explorer --config=/etc/explorer/chains.yaml
```
## Related
- [`luxfi/indexer`](https://github.com/luxfi/indexer) — Go backend, 1528 tests, SQLite, E2E PQ encrypted backups
- [`luxfi/explore`](https://github.com/luxfi/explore) — Next.js frontend, Geist font, white-label
- [`luxfi/explorer-v1`](https://github.com/luxfi/explorer-v1) — Legacy Elixir stack (archived)