Skip to content

Commit 123e04d

Browse files
committed
1.0.38
1 parent 64b6dcd commit 123e04d

6 files changed

Lines changed: 318 additions & 5 deletions

File tree

.dockerignore

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
build/
6+
.svelte-kit/
7+
8+
# IDE
9+
.idea/
10+
.vscode/
11+
*.swp
12+
*.swo
13+
14+
# Git
15+
.git/
16+
.gitignore
17+
18+
# CI/CD
19+
.drone.yml
20+
deployment/
21+
22+
# Tests
23+
tests/
24+
25+
# Hawser agent (separate project)
26+
hawser/
27+
28+
# Updater (separate project)
29+
updater/
30+
31+
# Test image
32+
test-image/
33+
34+
# Landing page
35+
webpage/
36+
37+
# Misc
38+
.DS_Store
39+
*.log
40+
.env
41+
.env.*
42+
!.env.example
43+
44+
# Sensitive files
45+
scripts/keys/
46+
data/
47+
*.pem
48+
*.key
49+
*.crt
50+
51+
# Documentation
52+
*.md
53+
!README.md
54+
55+
# Development files
56+
docker-compose*.yml
57+
!docker-compose.yml
58+
bun.lock
59+
tsconfig.json
60+
.prettierrc
61+
.eslintrc*

Dockerfile.backup

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# syntax=docker/dockerfile:1.4
2+
# Dockhand Backup Helper - Minimal restic image (Wolfi-based, zero CVEs)
3+
#
4+
# Rebuild trigger: the dockhand-backup-image pipeline is change-gated on this
5+
# file. Bumping this comment forces a build so docker.io/fnsys/dockhand-backup:latest
6+
# is (re)published to Docker Hub — the tag DEFAULT_HELPER_IMAGE (restic.ts) pulls.
7+
# (re-triggered after fixing the ARM-builder Docker Hub login secret)
8+
# (buildx steps consolidated into one block scalar)
9+
# (remote ARM login: pipe password over stdin, no quoted interpolation)
10+
# (use write-capable dockerhub token so the Docker Hub push authorizes)
11+
# (revert rclone — the rclone: backend is unfinished/removed; see vault rclone.md)
12+
FROM alpine:3.21 AS os-builder
13+
14+
ARG TARGETARCH
15+
WORKDIR /work
16+
17+
ARG APKO_VERSION=0.30.34
18+
RUN apk add --no-cache curl \
19+
&& ARCH=$([ "$TARGETARCH" = "arm64" ] && echo "arm64" || echo "amd64") \
20+
&& curl -sL "https://github.com/chainguard-dev/apko/releases/download/v${APKO_VERSION}/apko_${APKO_VERSION}_linux_${ARCH}.tar.gz" \
21+
| tar -xz --strip-components=1 -C /usr/local/bin \
22+
&& chmod +x /usr/local/bin/apko
23+
24+
RUN APKO_ARCH=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "x86_64") \
25+
&& printf '%s\n' \
26+
"contents:" \
27+
" repositories:" \
28+
" - https://packages.wolfi.dev/os" \
29+
" keyring:" \
30+
" - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub" \
31+
" packages:" \
32+
" - wolfi-base" \
33+
" - ca-certificates" \
34+
" - busybox" \
35+
" - restic" \
36+
"entrypoint:" \
37+
" command: /bin/sh" \
38+
"archs:" \
39+
" - ${APKO_ARCH}" \
40+
> apko.yaml
41+
42+
RUN apko build apko.yaml dockhand-backup:latest output.tar \
43+
&& mkdir -p rootfs \
44+
&& tar -xf output.tar \
45+
&& LAYER=$(tar -tf output.tar | grep '.tar.gz$' | head -1) \
46+
&& tar -xzf "$LAYER" -C rootfs
47+
48+
FROM scratch
49+
COPY --from=os-builder /work/rootfs /
50+
COPY scripts/backup-entrypoint.sh /entrypoint.sh
51+
ENTRYPOINT ["/entrypoint.sh"]

Dockerfile.backup.baseline

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# syntax=docker/dockerfile:1.4
2+
# Dockhand Backup Helper — BASELINE build (Alpine/musl, amd64 only)
3+
#
4+
# The normal helper (Dockerfile.backup) is Wolfi-based; Wolfi compiles its restic
5+
# and glibc for x86-64-v2 (SSE4.2/POPCNT). On older x86_64 CPUs without those
6+
# instructions (TrueNAS, old Intel Atom/Celeron — the same hardware that needs the
7+
# baseline Dockhand image) the Wolfi helper dies immediately:
8+
# restic: "This program can only be run on AMD64 processors with v2 microarchitecture"
9+
# busybox: "Fatal glibc error: CPU does not support x86-64-v2"
10+
# so backups are completely broken for baseline users.
11+
#
12+
# Alpine's musl + its restic build run on x86-64-v1 (verified on a QEMU v1 CPU), so
13+
# the baseline helper is a plain Alpine image with restic. amd64 only — baseline is a
14+
# workaround for old x86_64 hardware, not an ARM concern.
15+
#
16+
# Rebuild trigger: the pipeline is change-gated on this file — bumping this comment
17+
# forces a rebuild so the versioned/-baseline tags are (re)published.
18+
# (revert rclone — the rclone: backend is unfinished/removed; see vault rclone.md)
19+
FROM alpine:3.21
20+
21+
# restic + tar (busybox) + a real shell + CA certs cover everything the helper does:
22+
# restic backup/restore/forget, the metadata shell script (set -e, tar), and TLS to
23+
# the backup repository.
24+
RUN apk add --no-cache restic ca-certificates tar
25+
26+
COPY scripts/backup-entrypoint.sh /entrypoint.sh
27+
RUN chmod +x /entrypoint.sh
28+
ENTRYPOINT ["/entrypoint.sh"]

Dockerfile.baseline

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ RUN gcc -shared -fPIC -O2 -o /tmp/libgetrandom-shim.so /tmp/getrandom-shim.c
2626

2727
# Copy package files and install dependencies (--ignore-scripts blocks malicious postinstall hooks)
2828
COPY package.json package-lock.json ./
29-
RUN npm ci --ignore-scripts \
30-
&& npm rebuild better-sqlite3 argon2
29+
RUN MAKEFLAGS="-j$(nproc)" npm ci --ignore-scripts \
30+
&& MAKEFLAGS="-j$(nproc)" npm rebuild better-sqlite3 argon2
3131

3232
# Copy source code and build
3333
COPY . .
@@ -44,7 +44,7 @@ RUN cp -r node_modules/better-sqlite3/build /tmp/better-sqlite3-build \
4444
# -----------------------------------------------------------------------------
4545
# Stage 2: Go Collector Builder
4646
# -----------------------------------------------------------------------------
47-
FROM golang:1.25.8 AS go-builder
47+
FROM golang:1.25.12 AS go-builder
4848
WORKDIR /app
4949
COPY collector/ ./collector/
5050
RUN cd collector && CGO_ENABLED=0 go build -o /app/bin/collection-worker .
@@ -90,7 +90,8 @@ ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
9090
HOME=/home/dockhand \
9191
PUID=1001 \
9292
PGID=1001 \
93-
LD_PRELOAD=/usr/lib/libgetrandom-shim.so
93+
LD_PRELOAD=/usr/lib/libgetrandom-shim.so \
94+
DOCKHAND_VARIANT=baseline
9495

9596
# Copy application files with correct ownership
9697
COPY --from=app-builder --chown=dockhand:dockhand /app/node_modules ./node_modules
@@ -123,6 +124,15 @@ RUN chmod +x ./scripts/*.sh ./scripts/**/*.sh 2>/dev/null || true
123124
RUN mkdir -p /home/dockhand/.dockhand/stacks /app/data \
124125
&& chown dockhand:dockhand /app/data /home/dockhand /home/dockhand/.dockhand /home/dockhand/.dockhand/stacks
125126

127+
# OCI image annotations (#1217) — lets tooling map this image back to its
128+
# source repo (image registry name differs from GitHub repo name).
129+
LABEL org.opencontainers.image.source="https://github.com/Finsys/dockhand" \
130+
org.opencontainers.image.url="https://dockhand.pro" \
131+
org.opencontainers.image.title="Dockhand" \
132+
org.opencontainers.image.description="Docker management" \
133+
org.opencontainers.image.vendor="Finsys" \
134+
org.opencontainers.image.licenses="BUSL-1.1"
135+
126136
EXPOSE 3000
127137

128138
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \

Dockerfile.riscv64

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# syntax=docker/dockerfile:1.4
2+
# =============================================================================
3+
# Dockhand Docker Image - RISC-V 64-bit (Experimental)
4+
# =============================================================================
5+
# Experimental riscv64 build. Wolfi has no riscv64 packages, and official
6+
# node:24-alpine/slim images don't include riscv64 either. Alpine edge repos
7+
# have nodejs 24 for riscv64, so we use those directly.
8+
#
9+
# docker-compose is not packaged for riscv64 in Alpine, so we build it from
10+
# source using Go (which has full riscv64 support).
11+
#
12+
# lightningcss (used by Vite) has no riscv64 prebuilt binary, so we split
13+
# the build: Vite runs on the build platform (fast, has lightningcss), then
14+
# native addons are rebuilt on riscv64 (QEMU, slower but necessary).
15+
#
16+
# Build:
17+
# docker buildx build --platform linux/riscv64 -f Dockerfile.riscv64 \
18+
# -t registry.bor6.pl/dockhand:riscv64-test --push .
19+
# =============================================================================
20+
21+
# -----------------------------------------------------------------------------
22+
# Stage 1: Docker Compose Builder (Go - cross-compile from build platform)
23+
# -----------------------------------------------------------------------------
24+
# Alpine edge has docker-cli for riscv64 but NOT docker-compose.
25+
# Build it from source since Go has excellent riscv64 cross-compilation.
26+
FROM --platform=$BUILDPLATFORM golang:1.25.9-alpine AS compose-builder
27+
ARG TARGETARCH
28+
29+
RUN apk add --no-cache git
30+
31+
RUN git clone --depth 1 --branch v2.36.1 https://github.com/docker/compose.git /src/compose
32+
33+
WORKDIR /src/compose
34+
RUN CGO_ENABLED=0 GOARCH=$TARGETARCH go build -trimpath -ldflags="-s -w" -o /usr/bin/docker-compose ./cmd
35+
36+
# -----------------------------------------------------------------------------
37+
# Stage 2: JS Builder (runs on build platform - has lightningcss binaries)
38+
# -----------------------------------------------------------------------------
39+
# Vite/lightningcss have no riscv64 prebuilt binaries. Since Vite produces
40+
# plain JS bundles with no arch dependency, we build on the host platform.
41+
FROM --platform=$BUILDPLATFORM node:24-alpine AS js-builder
42+
43+
WORKDIR /app
44+
45+
RUN apk add --no-cache git curl python3 make g++ gcc musl-dev
46+
47+
COPY package.json package-lock.json ./
48+
RUN MAKEFLAGS="-j$(nproc)" npm ci --ignore-scripts \
49+
&& MAKEFLAGS="-j$(nproc)" npm rebuild
50+
51+
COPY . .
52+
RUN npm run build
53+
54+
# -----------------------------------------------------------------------------
55+
# Stage 3: Native Addon Builder (runs on riscv64 via QEMU)
56+
# -----------------------------------------------------------------------------
57+
# better-sqlite3 and argon2 have C/C++ native addons that must be compiled
58+
# for the target architecture (riscv64).
59+
FROM --platform=$TARGETPLATFORM alpine:edge AS addon-builder
60+
61+
RUN apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \
62+
--repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \
63+
nodejs npm python3 make g++ gcc musl-dev
64+
65+
WORKDIR /app
66+
67+
COPY package.json package-lock.json ./
68+
RUN MAKEFLAGS="-j$(nproc)" npm ci --omit=dev --ignore-scripts \
69+
&& MAKEFLAGS="-j$(nproc)" npm rebuild better-sqlite3 argon2 \
70+
&& rm -rf node_modules/@types
71+
72+
# -----------------------------------------------------------------------------
73+
# Stage 4: Go Collector Builder (cross-compile from build platform)
74+
# -----------------------------------------------------------------------------
75+
FROM --platform=$BUILDPLATFORM golang:1.25.9 AS go-builder
76+
ARG TARGETARCH
77+
WORKDIR /app
78+
COPY collector/ ./collector/
79+
RUN cd collector && CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /app/bin/collection-worker .
80+
81+
# -----------------------------------------------------------------------------
82+
# Stage 5: Final Image (Alpine edge runtime)
83+
# -----------------------------------------------------------------------------
84+
FROM alpine:edge
85+
86+
# Install runtime packages from main + community repos
87+
RUN apk add --no-cache \
88+
--repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \
89+
--repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \
90+
nodejs \
91+
ca-certificates \
92+
tzdata \
93+
docker-cli \
94+
docker-cli-buildx \
95+
sqlite \
96+
postgresql17-client \
97+
git \
98+
openssh-client \
99+
curl \
100+
tini \
101+
su-exec \
102+
libstdc++
103+
104+
# Copy docker-compose built from source (not available as Alpine package for riscv64)
105+
COPY --from=compose-builder /usr/bin/docker-compose /usr/bin/docker-compose
106+
107+
# Create docker compose plugin symlink
108+
RUN mkdir -p /usr/libexec/docker/cli-plugins \
109+
&& ln -sf /usr/bin/docker-compose /usr/libexec/docker/cli-plugins/docker-compose
110+
111+
# Create dockhand user and group
112+
RUN addgroup -g 1001 dockhand \
113+
&& adduser -u 1001 -G dockhand -h /home/dockhand -D dockhand
114+
115+
WORKDIR /app
116+
117+
# Set up environment variables
118+
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
119+
NODE_ENV=production \
120+
PORT=3000 \
121+
HOST=0.0.0.0 \
122+
DATA_DIR=/app/data \
123+
HOME=/home/dockhand \
124+
PUID=1001 \
125+
PGID=1001
126+
127+
# Copy node_modules with riscv64 native addons
128+
COPY --from=addon-builder --chown=dockhand:dockhand /app/node_modules ./node_modules
129+
130+
# Copy built JS app from cross-platform builder
131+
COPY --from=js-builder --chown=dockhand:dockhand /app/package.json ./
132+
COPY --from=js-builder --chown=dockhand:dockhand /app/build ./build
133+
COPY --from=js-builder --chown=dockhand:dockhand /app/server.js ./
134+
135+
# Copy Go collector binary
136+
COPY --from=go-builder --chown=dockhand:dockhand /app/bin/collection-worker ./bin/collection-worker
137+
138+
# Copy database migrations
139+
COPY --chown=dockhand:dockhand drizzle/ ./drizzle/
140+
COPY --chown=dockhand:dockhand drizzle-pg/ ./drizzle-pg/
141+
142+
# Copy legal documents
143+
COPY --chown=dockhand:dockhand LICENSE.txt PRIVACY.txt ./
144+
145+
# Copy entrypoint script
146+
COPY docker-entrypoint-node.sh /usr/local/bin/docker-entrypoint.sh
147+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
148+
149+
# Copy emergency scripts
150+
COPY --chown=dockhand:dockhand scripts/emergency/ ./scripts/
151+
RUN chmod +x ./scripts/*.sh ./scripts/**/*.sh 2>/dev/null || true
152+
153+
# Create data directories
154+
RUN mkdir -p /home/dockhand/.dockhand/stacks /app/data \
155+
&& chown dockhand:dockhand /app/data /home/dockhand /home/dockhand/.dockhand /home/dockhand/.dockhand/stacks
156+
157+
EXPOSE 3000
158+
159+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
160+
CMD curl -f http://localhost:${PORT:-3000}/ || exit 1
161+
162+
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
163+
CMD []

src/routes/+layout.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { LayoutServerLoad } from './$types';
22
import { redirect } from '@sveltejs/kit';
33
import { isAuthEnabled, validateSession } from '$lib/server/auth';
44
import { hasAdminUser } from '$lib/server/db';
5-
import { BACKUPS_ENABLED } from '$lib/server/features';
5+
import { BACKUPS_ENABLED } from '$lib/server/features';
66

77
// Routes that don't require authentication
88
const PUBLIC_PATHS = ['/login'];

0 commit comments

Comments
 (0)