Files
homarr/Dockerfile
T
KimP0ssible-no b6f6701eda fix: cap V8 heap and enable effective garbage collection for nextjs
Add --max-old-space-size=1024 to the node process running the Next.js
server. This caps V8's old-generation heap at 1024MB, forcing the
garbage collector to run more aggressively as memory usage approaches
the limit.

Previously, users saw Next.js RSS grow to 4GB+. This was caused by a
reference chain that prevented GC from freeing memory:

  AfterContext (vercel/next.js#89091) retained ServerResponse objects
  after client disconnect, which held zlib Transform streams (from
  compress: true), which allocated native C++ buffers outside V8's
  heap entirely — invisible to GC and uncapped by --max-old-space-size.

Combined with the prior commit's fixes (compress: false moves gzip to
nginx, httpBatchLink closes connections faster, socket-cleanup.cjs
destroys zombie CLOSE_WAIT sockets every 60s), GC can now actually
reclaim memory because:

- zlib native buffers no longer exist (compress: false)
- The AfterContext → ServerResponse reference chain is broken by
  socket cleanup destroying the underlying sockets
- The JS heap is capped at 1024MB so V8 GCs more frequently for
  the memory it does control

Also fixes the Dockerfile to copy socket-cleanup.cjs from the builder
stage instead of the host context.

Ref: https://github.com/homarr-labs/homarr/issues/3759
2026-04-15 12:49:48 +02:00

73 lines
2.4 KiB
Docker

FROM node:24.14.1-alpine AS base
FROM base AS builder
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
WORKDIR /app
RUN apk add --no-cache libc6-compat curl bash
RUN apk update
COPY . .
RUN corepack enable pnpm && pnpm install --recursive --frozen-lockfile
# Copy static data as it is not part of the build
COPY static-data ./static-data
ARG SKIP_ENV_VALIDATION='true'
ARG CI='true'
ARG DISABLE_REDIS_LOGS='true'
RUN corepack enable pnpm && pnpm build
FROM base AS runner
WORKDIR /app
# gettext is required for envsubst, openssl for generating AUTH_SECRET, su-exec for running application as non-root
RUN apk add --no-cache redis nginx bash gettext su-exec openssl
RUN mkdir /appdata
VOLUME /appdata
# Enable homarr cli
COPY --from=builder /app/packages/cli/cli.cjs /app/apps/cli/cli.cjs
RUN echo $'#!/bin/bash\ncd /app/apps/cli && node ./cli.cjs "$@"' > /usr/bin/homarr
RUN chmod +x /usr/bin/homarr
# Don't run production as root
RUN mkdir -p /var/cache/nginx && \
mkdir -p /var/log/nginx && \
mkdir -p /var/lib/nginx && \
touch /run/nginx/nginx.pid && \
mkdir -p /etc/nginx/templates /etc/nginx/ssl/certs
COPY --from=builder /app/apps/nextjs/next.config.ts .
COPY --from=builder /app/apps/nextjs/package.json .
COPY --from=builder /app/apps/tasks/tasks.cjs ./apps/tasks/tasks.cjs
COPY --from=builder /app/apps/websocket/wssServer.cjs ./apps/websocket/wssServer.cjs
COPY --from=builder /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node
COPY --from=builder /app/packages/db/migrations ./db/migrations
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder /app/apps/nextjs/.next/standalone ./
COPY --from=builder /app/apps/nextjs/socket-cleanup.cjs ./apps/nextjs/socket-cleanup.cjs
COPY --from=builder /app/apps/nextjs/.next/static ./apps/nextjs/.next/static
COPY --from=builder /app/apps/nextjs/public ./apps/nextjs/public
COPY scripts/run.sh ./run.sh
COPY --chmod=755 scripts/entrypoint.sh ./entrypoint.sh
COPY packages/redis/redis.conf /app/redis.conf
COPY nginx.conf /etc/nginx/templates/nginx.conf
ENV DB_URL='/appdata/db/db.sqlite'
ENV DB_DIALECT='sqlite'
ENV DB_DRIVER='better-sqlite3'
ENV AUTH_PROVIDERS='credentials'
ENV REDIS_IS_EXTERNAL='false'
ENV NODE_ENV='production'
ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD ["sh", "run.sh"]