Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Environment variable: PUID and PGID (#240) #2011

Merged
merged 3 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure these changes need to be committed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change under this file is whitespace removed from end of file.
imagen

This fixes a mysterious issue during building:

You can reproduce this issue from clean scenary:

docker run --rm -it node:20.2.0-slim bash
And then, try to clone and build this project:

apt update && apt -y install git
git clone https://github.com/ajnart/homarr.git
cd homarr
yarn install
cp .env.example .env
yarn build

After that, throw next error caused by end whitespace:

Invalid environment variables: { NEXT_PUBLIC_DEFAULT_COLOR_SCHEME: [ 'Invalid input' ] }
- error Failed to load next.config.js, see more info .....

imagen

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's mindblowing 🤯 Totally didn't expect it could cause so many issues

Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ NEXTAUTH_SECRET="anything"
# Disable analytics
NEXT_PUBLIC_DISABLE_ANALYTICS="true"

DEFAULT_COLOR_SCHEME="light"
DEFAULT_COLOR_SCHEME="light"
130 changes: 101 additions & 29 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,33 +1,106 @@
FROM node:20.2.0-slim
FROM node:20.2.0-slim as compiler

#RUN apt-get update && apt-get -y install git wget openssl

WORKDIR /app

# Define node.js environment variables
#RUN git clone https://github.com/ajnart/homarr.git .
COPY . .

RUN yarn install
COPY .env.example .env
RUN yarn build


FROM node:20.2.0-alpine3.18

#ARGS is only for build

ARG PORT=7575

# Keep free id >= 1000 for user, under node:x image by default node user uses 1000:1000
ARG NODE_UID=800
ARG NODE_GID=800

#PUID can be set during build and run time
ARG PUID=801
ARG PGID=801

#it must be the same as the host, temporary 802 or any, automatically changed at runtime
ARG DOCKER_GID=802

#By default, ping group using gid 999, keep free to possible docker host gid
ARG PING_GID=803

# Expose the default application port
EXPOSE $PORT
ENV PORT=${PORT}

# Define node.js environment variables
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
ENV NODE_OPTIONS '--no-experimental-fetch'

COPY next.config.js ./
COPY public ./public
COPY package.json ./temp_package.json
COPY yarn.lock ./temp_yarn.lock
# App environment variables
ENV DATABASE_URL "file:/app/data/db.sqlite"
ENV NEXTAUTH_URL "http://localhost:7575"
ENV NEXTAUTH_SECRET NOT_IN_USE_BECAUSE_JWTS_ARE_UNUSED

# Must be same as host user when using bind mount volumes
ENV PUID $PUID
ENV PGID $PGID

RUN apk update && apk add --no-cache \
supervisor docker-cli shadow

RUN usermod -u $NODE_UID node
RUN groupmod -g $NODE_GID node

RUN groupmod -g $PING_GID ping

# Creating local homarr user and group
RUN groupadd -g $PGID homarr
RUN useradd homarr -u $PUID -g homarr --home-dir /app --shell /sbin/nologin
RUN usermod -aG node homarr

# Creating a local Docker group and add docker group to homarr user
RUN groupadd -g $DOCKER_GID docker
RUN usermod -aG docker homarr

# Enable sudo for homarr user, only for debug and testing purposes
#RUN apk add sudo
#RUN echo "homarr ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# Configure entrypoint
COPY ./docker/entrypoint /
RUN chmod +x /entrypoint.sh
RUN chmod +x /docker-entrypoint.d/*.sh

# Configure supervisord
COPY ./docker/etc/supervisord.conf /etc/supervisord.conf
COPY ./docker/etc/supervisor /etc/supervisor

#RUN chown homarr:homarr /app
USER node
WORKDIR /app

COPY --from=compiler --chown=node:homarr /app/next.config.js ./
COPY --from=compiler --chown=node:homarr /app/public ./public
COPY --from=compiler --chown=node:homarr /app/package.json ./temp_package.json
COPY --from=compiler --chown=node:homarr /app/yarn.lock ./temp_yarn.lock
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY .next/standalone ./
COPY .next/static ./.next/static
COPY ./scripts/run.sh ./scripts/run.sh
RUN chmod +x ./scripts/run.sh
COPY ./drizzle ./drizzle

COPY ./drizzle/migrate ./migrate
COPY ./tsconfig.json ./migrate/tsconfig.json
COPY ./cli ./cli
COPY --from=compiler --chown=node:homarr /app/.next/standalone ./
COPY --from=compiler --chown=node:homarr /app/.next/static ./.next/static

RUN mkdir /data
COPY --from=compiler --chown=node:homarr /app/scripts/run.sh ./scripts/run.sh
RUN chmod +x ./scripts/run.sh
COPY --from=compiler --chown=node:homarr /app/drizzle ./drizzle

# Install dependencies
RUN apt update && apt install -y openssl wget
COPY --from=compiler --chown=node:homarr /app/drizzle/migrate ./migrate
COPY --from=compiler --chown=node:homarr /app/tsconfig.json ./migrate/tsconfig.json
COPY --from=compiler --chown=node:homarr /app/cli ./cli

# Move node_modules to temp location to avoid overwriting
RUN mv node_modules _node_modules
Expand All @@ -45,22 +118,21 @@ RUN mv node_modules ./migrate/node_modules
# Copy temp node_modules of app to app folder
RUN mv _node_modules node_modules

RUN echo '#!/bin/bash\nnode /app/cli/cli.js "$@"' > /usr/bin/homarr
RUN chmod +x /usr/bin/homarr
#RUN echo '#!/bin/bash\nnode /app/cli/cli.js "$@"' > /usr/bin/homarr
manuel-rw marked this conversation as resolved.
Show resolved Hide resolved
#RUN chmod +x /usr/bin/homarr
RUN cd /app/cli && yarn --immutable

# Expose the default application port
EXPOSE $PORT
ENV PORT=${PORT}
# Root is needed for supervisord
USER root

ENV DATABASE_URL "file:/data/db.sqlite"
ENV NEXTAUTH_URL "http://localhost:7575"
ENV PORT 7575
ENV NEXTAUTH_SECRET NOT_IN_USE_BECAUSE_JWTS_ARE_UNUSED
RUN echo '#!/bin/bash\nnode /app/cli/cli.js "$@"' > /usr/bin/homarr
RUN chmod +x /usr/bin/homarr

HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT} || exit 1

VOLUME [ "/app/data/configs" ]
VOLUME [ "/data" ]
ENTRYPOINT ["sh", "./scripts/run.sh"]
#VOLUME [ "/app/data/configs" ]
#VOLUME [ "/data" ]
manuel-rw marked this conversation as resolved.
Show resolved Hide resolved

ENTRYPOINT [ "/entrypoint.sh" ]
CMD []
23 changes: 23 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: "2.1"
services:
#---------------------------------------------------------------------#
# Homarr - A simple, yet powerful dashboard for your server. #
#---------------------------------------------------------------------#
homarr:
container_name: homarr
#image: ghcr.io/ajnart/homarr:latest
build: # only for dev branch...
context: .
dockerfile: Dockerfile
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- DOCKER_GID=999 # Must be same as host docker group id
- DATABASE_URL=file:/app/data/configs/db.sqlite
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration
- ./homarr_persistence/configs:/app/data/configs
- ./homarr_persistence/icons:/app/public/icons
ports:
- '7575:7575'
26 changes: 26 additions & 0 deletions docker/entrypoint/docker-entrypoint.d/00-user-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh

HOMARR_USER_PATHS="/app/data /app/public/icons"

for path in $HOMARR_USER_PATHS
do
if [ ! -d "$path" ]; then
mkdir -p $path
fi

find $path ! -user $PUID -print0 | while read -d $'\0' FILE
do
echo "${FILE} is not own by current user, fixing..."
chown $PUID:$PGID ${FILE}
done
done

echo Setting homarr UID to $PUID and GID to $PGID please wait...
usermod -u $PUID homarr
groupmod -g $PGID homarr

DOCKER_GID=$(stat -c %g /var/run/docker.sock 2>/dev/null)
if [[ $? -eq 0 ]]; then
echo "SETTING DOCKER GID TO ${DOCKER_GID}"
groupmod -g $DOCKER_GID docker
fi
68 changes: 68 additions & 0 deletions docker/entrypoint/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/sh
# vim:sw=4:ts=4:et

set -e
echo "Entering entrypoint..."

echo "Param \$1: $1"
echo "User: "$(whoami)


entrypoint_log() {
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
echo "$@"
fi
}

if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration"

entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/"
find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do
case "$f" in
*.envsh)
if [ -x "$f" ]; then
entrypoint_log "$0: Sourcing $f";
. "$f"
else
# warn on shell scripts without exec bit
entrypoint_log "$0: Ignoring $f, not executable";
fi
;;
*.sh)
if [ -x "$f" ]; then
entrypoint_log "$0: Launching $f";
"$f"
else
# warn on shell scripts without exec bit
entrypoint_log "$0: Ignoring $f, not executable";
fi
;;
*) entrypoint_log "$0: Ignoring $f";;
esac
done

entrypoint_log "$0: Configuration complete; ready for start up"
else
entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration"
fi

#exec "$@"

# sys container init:
#
# If no command is passed to the container, supervisord becomes init and
# starts all its configured programs (per /etc/supervisord.conf).
#
# If a command is passed to the container, it runs in the foreground;
# supervisord runs in the background and starts all its configured
# programs.
#
# In either case, supervisord always starts its configured programs.

if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
exec supervisord -n "$@"
else
supervisord -c /etc/supervisord.conf &
exec "$@"
fi
13 changes: 13 additions & 0 deletions docker/etc/supervisor/conf.d/homarr.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[program:homarr]
command=/app/scripts/run.sh
environment=HOME="/app",USER="homarr",LOGNAME="homarr"
user=homarr
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=0
stopasgroup=true
killasgroup=true
stopsignal=KILL