mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 21:33:02 +01:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bdca8c21 | ||
|
|
25700c12da | ||
|
|
a252f63ae8 | ||
|
|
3919ed2e91 | ||
|
|
4847d8d72b | ||
|
|
08081d7abf | ||
|
|
da9d0681b8 | ||
|
|
f635bb1084 | ||
|
|
ccb8961ed2 | ||
|
|
de993f37a4 | ||
|
|
c839e82b93 | ||
|
|
ac47073988 | ||
|
|
6ad0c33340 | ||
|
|
14bb2de584 | ||
|
|
1d62552046 | ||
|
|
d84c45d332 | ||
|
|
1f197f748a | ||
|
|
0484bbb0c3 | ||
|
|
5009879f9f | ||
|
|
4b9bf95f20 | ||
|
|
d1dff61bef | ||
|
|
966ae9062e | ||
|
|
0e3c1db334 | ||
|
|
2e4a967559 | ||
|
|
d8c98d1bdb | ||
|
|
f56067ac5c | ||
|
|
5878870809 | ||
|
|
40ba888e05 | ||
|
|
342caf2e6b | ||
|
|
f30ccec451 | ||
|
|
8d3de1a1e5 | ||
|
|
f5e404e6cd | ||
|
|
62dc9f83c2 | ||
|
|
3922b13696 |
49
.github/workflows/clear-stale-docker-images.yml
vendored
49
.github/workflows/clear-stale-docker-images.yml
vendored
@@ -6,20 +6,47 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
delete-untagged-images:
|
delete-old-images-main:
|
||||||
name: Delete Untagged Images
|
name: Delete Untagged Images
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- uses: dataaxiom/ghcr-cleanup-action@v1
|
- name: Fetch multi-platform package version SHAs
|
||||||
|
id: multi-arch-digests
|
||||||
|
run: |
|
||||||
|
package1=$(docker manifest inspect ghcr.io/sysadminsmedia/homebox | jq -r '.manifests.[] | .digest' | paste -s -d ' ' -)
|
||||||
|
echo "multi-arch-digests=$package1" >> $GITHUB_OUTPUT
|
||||||
|
- uses: snok/container-retention-policy@v3.0.0
|
||||||
with:
|
with:
|
||||||
dry-run: false
|
skip-shas: ${{ steps.multi-arch-digests.outputs.multi-arch-digests }}
|
||||||
package: homebox
|
# The type of account. Can be either 'org' or 'personal'.
|
||||||
delete-ghost-images: true
|
account: sysadminsmedia
|
||||||
delete-orphaned-images: true
|
# Image name to delete. Supports passing several names as a comma-separated list.
|
||||||
delete-partial-images: true
|
image-names: homebox
|
||||||
delete-untagged: true
|
# The cut-off for which to delete images older than. For example '2 days ago UTC'. Timezone is required.
|
||||||
# Make sure to update this to include the latest major tags
|
cut-off: 90d
|
||||||
exclude-tags: main,vnext,latest,0.*,1.*
|
# Personal access token with read and delete scopes.
|
||||||
older-than: 3 months
|
token: ${{ secrets.CLEANUP_PAT }}
|
||||||
|
# Restrict deletions to images without specific tags. Supports Unix-shell style wildcards
|
||||||
|
skip-tags: "!latest,!latest-rootless,!0.*,!0.*-rootless,!main,!main-rootless,!vnext,!vnext-rootless,!0,!0-rootless" # optional
|
||||||
|
# Do not actually delete images. Print output showing what would have been deleted.
|
||||||
|
dry-run: true # optional, default is false
|
||||||
|
|
||||||
|
delete-old-images-devcache:
|
||||||
|
name: Delete Cache Old Images
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- uses: snok/container-retention-policy@v3.0.0
|
||||||
|
with:
|
||||||
|
# The type of account. Can be either 'org' or 'personal'.
|
||||||
|
account: sysadminsmedia
|
||||||
|
image-names: devcache
|
||||||
|
# The cut-off for which to delete images older than. For example '2 days ago UTC'. Timezone is required.
|
||||||
|
cut-off: 90d
|
||||||
|
# Personal access token with read and delete scopes.
|
||||||
|
token: ${{ secrets.CLEANUP_PAT }}
|
||||||
|
# Do not actually delete images. Print output showing what would have been deleted.
|
||||||
|
dry-run: true # optional, default is false
|
||||||
|
|||||||
31
.github/workflows/docker-publish-rootless.yaml
vendored
31
.github/workflows/docker-publish-rootless.yaml
vendored
@@ -31,10 +31,10 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # Allows access to repository contents (read-only)
|
contents: read
|
||||||
packages: write # Allows pushing to GHCR
|
packages: write
|
||||||
id-token: write # Allows identity token write access for authentication
|
id-token: write
|
||||||
attestations: write # Needed for signing and attestation (if required)
|
attestations: write
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -54,7 +54,6 @@ jobs:
|
|||||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
branch=${{ github.event.pull_request.number || github.ref_name }}
|
branch=${{ github.event.pull_request.number || github.ref_name }}
|
||||||
echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV
|
echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
@@ -75,7 +74,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }} # The GitHub token with the necessary permissions
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
@@ -92,12 +91,20 @@ jobs:
|
|||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
|
context: . # Explicitly specify the build context
|
||||||
|
file: ./Dockerfile.rootless # Explicitly specify the Dockerfile
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless
|
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless
|
||||||
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }}-rootless,mode=max
|
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless,mode=max
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ github.ref_name }}
|
||||||
|
COMMIT=${{ github.sha }}
|
||||||
|
provenance: true
|
||||||
|
sbom: true
|
||||||
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
mkdir -p /tmp/digests
|
mkdir -p /tmp/digests
|
||||||
@@ -115,10 +122,10 @@ jobs:
|
|||||||
merge:
|
merge:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # Allows access to repository contents (read-only)
|
contents: read
|
||||||
packages: write # Allows pushing to GHCR!
|
packages: write
|
||||||
id-token: write # Allows identity token write access for authentication
|
id-token: write
|
||||||
attestations: write # Needed for signing and attestation (if required)
|
attestations: write
|
||||||
needs:
|
needs:
|
||||||
- build
|
- build
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/docker-publish.yaml
vendored
6
.github/workflows/docker-publish.yaml
vendored
@@ -94,6 +94,12 @@ jobs:
|
|||||||
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}
|
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}
|
||||||
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }},mode=max
|
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }},mode=max
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ github.ref_name }}
|
||||||
|
COMMIT=${{ github.sha }}
|
||||||
|
provenance: true
|
||||||
|
sbom: true
|
||||||
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
|
||||||
- name: Export digest
|
- name: Export digest
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,73 +1,97 @@
|
|||||||
# Node dependencies
|
# Node dependencies stage
|
||||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies
|
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install pnpm globally (caching layer)
|
||||||
RUN npm install -g pnpm
|
RUN npm install -g pnpm
|
||||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
|
||||||
|
# Copy package.json and lockfile to leverage caching
|
||||||
|
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||||
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||||
|
|
||||||
# Build Nuxt
|
# Build Nuxt (frontend) stage
|
||||||
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder
|
FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY frontend ./
|
|
||||||
|
# Install pnpm globally again (it can reuse the cache if not changed)
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Copy over source files and node_modules from dependencies stage
|
||||||
|
COPY frontend .
|
||||||
COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
COPY --from=frontend-dependencies /app/node_modules ./node_modules
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
# Build Go dependencies
|
# Go dependencies stage
|
||||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies
|
FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
COPY ./backend/go.mod ./backend/go.sum ./
|
|
||||||
RUN apk update && apk add --no-cache git \
|
|
||||||
&& go mod download
|
|
||||||
|
|
||||||
# Build API
|
# Copy go.mod and go.sum for better caching
|
||||||
|
COPY ./backend/go.mod ./backend/go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Build API stage
|
||||||
FROM public.ecr.aws/docker/library/golang:alpine AS builder
|
FROM public.ecr.aws/docker/library/golang:alpine AS builder
|
||||||
ARG BUILD_TIME
|
ARG BUILD_TIME
|
||||||
ARG COMMIT
|
ARG COMMIT
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
|
|
||||||
RUN apk update && apk upgrade && apk add --no-cache git build-base gcc g++ \
|
# Install necessary build tools
|
||||||
&& addgroup -S nonroot && adduser -S nonroot -G nonroot
|
RUN apk update && \
|
||||||
|
apk upgrade && \
|
||||||
|
apk add --no-cache git build-base gcc g++
|
||||||
|
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
COPY ./backend ./
|
|
||||||
|
# Copy Go modules (from dependencies stage) and source code
|
||||||
|
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
||||||
|
COPY ./backend .
|
||||||
|
|
||||||
|
# Clear old public files and copy new ones from frontend build
|
||||||
RUN rm -rf ./app/api/public
|
RUN rm -rf ./app/api/public
|
||||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||||
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
|
|
||||||
|
|
||||||
# Use cache for Go build
|
# Use cache for Go build artifacts
|
||||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||||
CGO_ENABLED=0 GOOS=linux go build \
|
CGO_ENABLED=0 GOOS=linux go build \
|
||||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||||
-o /go/bin/api ./app/api/*.go
|
-o /go/bin/api \
|
||||||
|
-v ./app/api/*.go
|
||||||
|
|
||||||
# Change ownership of files to nonroot
|
RUN mkdir /data
|
||||||
RUN chown -R nonroot:nonroot /go/bin/api /go/src/app
|
|
||||||
|
|
||||||
# Production stage with distroless
|
|
||||||
FROM ghcr.io/distroless/static:latest
|
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM public.ecr.aws/docker/library/alpine:latest
|
||||||
ENV HBOX_MODE=production
|
ENV HBOX_MODE=production
|
||||||
ENV HBOX_STORAGE_DATA=/data/
|
ENV HBOX_STORAGE_DATA=/data/
|
||||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1&_time_format=sqlite
|
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
|
||||||
|
|
||||||
# Copy the binary and data directory, change ownership
|
# Install necessary runtime dependencies
|
||||||
COPY --from=builder /go/bin/api /app
|
RUN apk --no-cache add ca-certificates wget
|
||||||
COPY --from=builder /data /data
|
# Create a nonroot user with UID/GID 65532
|
||||||
COPY --from=ghcr.io/rockylinux/alpine:latest /bin/wget /usr/bin/wget
|
RUN addgroup -g 65532 nonroot && adduser -u 65532 -G nonroot -S nonroot
|
||||||
|
|
||||||
|
# Create application directory and copy over built Go binary
|
||||||
|
RUN mkdir /app
|
||||||
|
COPY --from=builder --chown=nonroot /go/bin/api /app
|
||||||
|
COPY --from=builder --chown=nonroot /data /data
|
||||||
|
RUN chmod +x /app/api
|
||||||
|
|
||||||
|
# Labels and configuration for the final image
|
||||||
LABEL Name=homebox Version=0.0.1
|
LABEL Name=homebox Version=0.0.1
|
||||||
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
|
||||||
|
|
||||||
|
# Expose necessary ports for Homebox
|
||||||
EXPOSE 7745
|
EXPOSE 7745
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s \
|
# Healthcheck configuration
|
||||||
--timeout=5s \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||||
--start-period=5s \
|
CMD [ "wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status" ]
|
||||||
--retries=3 \
|
|
||||||
CMD ["/usr/bin/wget", "--no-verbose", "--tries=1", "-O", "-", "http://localhost:7745/api/v1/status"]
|
|
||||||
|
|
||||||
VOLUME ["/data"]
|
# Persist volume
|
||||||
|
VOLUME [ "/data" ]
|
||||||
|
|
||||||
# Use nonroot user
|
# Entrypoint and CMD
|
||||||
USER nonroot
|
USER nonroot
|
||||||
ENTRYPOINT ["/app"]
|
ENTRYPOINT [ "/app/api" ]
|
||||||
CMD ["/data/config.yml"]
|
CMD [ "/data/config.yml" ]
|
||||||
|
|||||||
Reference in New Issue
Block a user