fix: Add entrypoint script to fix volume permissions at runtime
- Add docker-entrypoint.sh that runs as root to fix mounted volume permissions - Creates required subdirectories (logs, users, packages) before app starts - Copies default config.js if missing - Drops to node user via su-exec before running the app - Update Dockerfile to use entrypoint and install su-exec - Update docker-compose.yml with UID/GID mapping and separate volume mounts - Wrap filesystem operations in try-catch to handle permission errors gracefully
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
FROM node:20-alpine
|
||||
RUN apk add --no-cache --virtual=build-dependencies build-base git python3-dev py3-setuptools && \
|
||||
apk add --no-cache yarn
|
||||
apk add --no-cache yarn su-exec
|
||||
WORKDIR /var/opt/hardlounge-src
|
||||
ENV THELOUNGE_HOME /var/opt/hardlounge
|
||||
COPY --chown=node:node package.json yarn.lock .
|
||||
@@ -13,8 +13,9 @@ RUN NODE_ENV=production yarn build && \
|
||||
ln -s /var/opt/hardlounge-src/index.js /var/opt/hardlounge-src/hardlounge
|
||||
USER root
|
||||
RUN apk del --purge build-dependencies && \
|
||||
mkdir -p /var/opt/hardlounge && \
|
||||
mkdir -p /var/opt/hardlounge/logs /var/opt/hardlounge/users /var/opt/hardlounge/packages && \
|
||||
chown -R node:node /var/opt/hardlounge
|
||||
USER node
|
||||
COPY --chmod=755 docker-entrypoint.sh /docker-entrypoint.sh
|
||||
EXPOSE 9000
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["/var/opt/hardlounge-src/hardlounge", "start"]
|
||||
@@ -2,7 +2,10 @@ services:
|
||||
hardlounge:
|
||||
image: git.supernets.org/supernets/hardlounge:latest
|
||||
build: .
|
||||
user: "${UID}:${GID}"
|
||||
ports:
|
||||
- "9000:9000"
|
||||
volumes:
|
||||
- "$PWD/config:/var/opt/hardlounge"
|
||||
- ./data/logs:/var/opt/hardlounge/logs
|
||||
- ./data/packages:/var/opt/hardlounge/packages
|
||||
- ./config:/var/opt/hardlounge
|
||||
|
||||
19
docker-entrypoint.sh
Normal file
19
docker-entrypoint.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Fix permissions on mounted volume at runtime
|
||||
chown -R node:node /var/opt/hardlounge 2>/dev/null || true
|
||||
chmod -R 755 /var/opt/hardlounge 2>/dev/null || true
|
||||
|
||||
# Create required subdirectories
|
||||
mkdir -p /var/opt/hardlounge/logs /var/opt/hardlounge/users /var/opt/hardlounge/packages 2>/dev/null || true
|
||||
chown -R node:node /var/opt/hardlounge 2>/dev/null || true
|
||||
|
||||
# Copy default config if it doesn't exist
|
||||
if [ ! -f /var/opt/hardlounge/config.js ]; then
|
||||
cp /var/opt/hardlounge-src/dist/defaults/config.js /var/opt/hardlounge/config.js 2>/dev/null || true
|
||||
chown node:node /var/opt/hardlounge/config.js 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Run as node user
|
||||
exec su-exec node "$@"
|
||||
@@ -22,26 +22,37 @@ program
|
||||
|
||||
function initalizeConfig() {
|
||||
if (!fs.existsSync(Config.getConfigPath())) {
|
||||
fs.mkdirSync(Config.getHomePath(), {recursive: true});
|
||||
|
||||
try {
|
||||
fs.chmodSync(Config.getHomePath(), "0700");
|
||||
} catch (e) {
|
||||
// Ignore chmod errors (e.g., on mounted volumes)
|
||||
}
|
||||
fs.mkdirSync(Config.getHomePath(), {recursive: true});
|
||||
|
||||
fs.copyFileSync(
|
||||
path.resolve(path.join(__dirname, "..", "..", "defaults", "config.js")),
|
||||
Config.getConfigPath()
|
||||
);
|
||||
log.info(`Configuration file created at ${colors.green(Config.getConfigPath())}.`);
|
||||
try {
|
||||
fs.chmodSync(Config.getHomePath(), "0700");
|
||||
} catch (e) {
|
||||
// Ignore chmod errors (e.g., on mounted volumes)
|
||||
}
|
||||
|
||||
fs.copyFileSync(
|
||||
path.resolve(path.join(__dirname, "..", "..", "defaults", "config.js")),
|
||||
Config.getConfigPath()
|
||||
);
|
||||
log.info(`Configuration file created at ${colors.green(Config.getConfigPath())}.`);
|
||||
} catch (e) {
|
||||
log.error(
|
||||
"Unable to create config directory/file. Please ensure the config volume is writable or pre-create config.js"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
fs.mkdirSync(Config.getUsersPath(), {recursive: true, mode: 0o700});
|
||||
} catch (e) {
|
||||
// Ignore permission errors on mounted volumes
|
||||
fs.mkdirSync(Config.getUsersPath(), {recursive: true});
|
||||
try {
|
||||
fs.mkdirSync(Config.getUsersPath(), {recursive: true});
|
||||
} catch (e2) {
|
||||
// Ignore if this also fails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ class Config {
|
||||
try {
|
||||
fs.mkdirSync(userLogsPath, {recursive: true, mode: 0o750});
|
||||
} catch (e: any) {
|
||||
log.error("Unable to create logs directory", e);
|
||||
log.warn("Unable to create logs directory, logging to disk may not work");
|
||||
}
|
||||
} else if (logsStat && logsStat.mode & 0o001) {
|
||||
log.warn(
|
||||
|
||||
Reference in New Issue
Block a user