diff --git a/Dockerfile b/Dockerfile index d786de9..fc12671 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM node:20-alpine AS base +FROM node:20-slim AS base # Install dependencies only when needed FROM base AS deps -RUN apk add --no-cache libc6-compat +RUN apt-get update && apt-get install -y libc6-compat WORKDIR /app # Install dependencies based on the preferred package manager @@ -34,8 +34,8 @@ WORKDIR /app ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs +RUN groupadd --system --gid 1001 nodejs +RUN useradd --system --uid 1001 nextjs # Create directories for mounted volumes with proper permissions RUN mkdir -p /app/scripts /app/data /app/snippets && \ @@ -58,6 +58,9 @@ COPY --from=builder /app/yarn.lock ./yarn.lock # Copy node_modules for production dependencies COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules +# Don't set default user - let docker-compose decide +# USER nextjs + EXPOSE 3000 ENV PORT=3000 diff --git a/app/_utils/system.ts b/app/_utils/system.ts index 21cc798..a8be44e 100644 --- a/app/_utils/system.ts +++ b/app/_utils/system.ts @@ -33,50 +33,15 @@ async function readCronFiles(): Promise { } } + // In Docker, use the host's crontab binary try { - const crontabPath = "/host/crontab"; - const crontabsDir = "/host/cron/crontabs"; - - let cronContent = ""; - - try { - const systemCrontab = await fs.readFile(crontabPath, "utf-8"); - cronContent += systemCrontab + "\n"; - } catch (error) { - console.log("System crontab not found or not readable"); - } - - try { - const files = await fs.readdir(crontabsDir); - for (const file of files) { - if (file !== "root") { - try { - const userCrontab = await fs.readFile( - path.join(crontabsDir, file), - "utf-8" - ); - if (userCrontab.trim()) { - cronContent += `# User: ${file}\n${userCrontab}\n`; - } - } catch (error) { - console.log(`Could not read crontab for user ${file}`); - } - } - } - } catch (error) { - console.log("User crontabs directory not found or not readable"); - } - - return cronContent || ""; + const { stdout } = await execAsync( + '/host/usr/bin/crontab -l 2>/dev/null || echo ""' + ); + return stdout; } catch (error) { - console.error("Error reading cron files:", error); - try { - const { stdout } = await execAsync('crontab -l 2>/dev/null || echo ""'); - return stdout; - } catch (fallbackError) { - console.error("Fallback crontab command also failed:", fallbackError); - return ""; - } + console.error("Error reading crontab:", error); + return ""; } } diff --git a/docker-compose.yml b/docker-compose.yml index 9871687..f22904b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,13 +3,13 @@ services: image: ghcr.io/fccview/cronmaster:main container_name: cronmaster user: "root" - ports: - # Mapping custom port 40123 due to 3000 being very common - - "40123:3000" + network_mode: host environment: - NODE_ENV=production - DOCKER=true - NEXT_PUBLIC_CLOCK_UPDATE_INTERVAL=30000 + # Feel free to change port, as we're running this as host you won't be able to externally map it + - PORT=40123 # Enter the FULL relative path to the project directory where this docker-compose.yml file is located (use `pwd` to find it) - NEXT_PUBLIC_HOST_PROJECT_DIR=/absolute/path/to/project/directory volumes: @@ -20,6 +20,7 @@ services: - /proc:/host/proc:ro - /sys:/host/sys:ro - /etc:/host/etc:ro + - /usr:/host/usr:ro # Mount scripts directory for script execution - ./scripts:/app/scripts # Mount data directory for persistence