diff --git a/Dockerfile b/Dockerfile index 69b4ca2..ad0c1a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,100 @@ -FROM node:lts-alpine AS builder +FROM node:lts AS builder WORKDIR /app +# Install pnpm RUN npm i -g pnpm +# Copy package files COPY package.json pnpm-lock.yaml ./ +# Install dependencies RUN pnpm install +# Copy source code COPY . . + +# Build the application RUN pnpm run build -FROM node:lts-alpine AS runtime +FROM node:lts AS runtime WORKDIR /app +# Install pnpm RUN npm i -g pnpm +# Install Chrome dependencies +RUN apt-get update && apt-get install -y \ + wget \ + gnupg \ + ca-certificates \ + fonts-liberation \ + libasound2 \ + libatk-bridge2.0-0 \ + libatk1.0-0 \ + libc6 \ + libcairo-gobject2 \ + libcairo2 \ + libcups2 \ + libdbus-1-3 \ + libexpat1 \ + libfontconfig1 \ + libgbm1 \ + libgcc1 \ + libglib2.0-0 \ + libgtk-3-0 \ + libnspr4 \ + libnss3 \ + libpango-1.0-0 \ + libpangocairo-1.0-0 \ + libstdc++6 \ + libx11-6 \ + libx11-xcb1 \ + libxcb1 \ + libxcomposite1 \ + libxcursor1 \ + libxdamage1 \ + libxext6 \ + libxfixes3 \ + libxi6 \ + libxrandr2 \ + libxrender1 \ + libxss1 \ + libxtst6 \ + lsb-release \ + xdg-utils \ + && rm -rf /var/lib/apt/lists/* + +# Install Chrome +RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \ + && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \ + && apt-get update \ + && apt-get install -y google-chrome-stable \ + && rm -rf /var/lib/apt/lists/* + +# Copy built application COPY --from=builder /app/dist ./dist COPY package.json pnpm-lock.yaml ./ +# Install production dependencies RUN pnpm install --prod +# Create a non-root user for security +RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ + && mkdir -p /home/pptruser/Downloads \ + && chown -R pptruser:pptruser /home/pptruser \ + && chown -R pptruser:pptruser /app + +# Set environment variables ENV HOST=0.0.0.0 ENV PORT=4321 +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true +ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable + +# Expose port EXPOSE 4321 +# Switch to non-root user +USER pptruser + +# Start the application CMD ["node", "./dist/server/entry.mjs"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..d57597e --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,69 @@ +FROM node:lts-alpine AS builder +WORKDIR /app + +# Install pnpm +RUN npm i -g pnpm + +# Copy package files +COPY package.json pnpm-lock.yaml ./ + +# Install dependencies +RUN pnpm install + +# Copy source code +COPY . . + +# Build the application +RUN pnpm run build + +FROM node:lts-alpine AS runtime +WORKDIR /app + +# Install pnpm +RUN npm i -g pnpm + +# Install Chromium and dependencies for Alpine +RUN apk add --no-cache \ + chromium \ + nss \ + freetype \ + freetype-dev \ + harfbuzz \ + ca-certificates \ + ttf-freefont \ + font-noto-emoji \ + font-noto \ + font-noto-cjk \ + font-noto-extra \ + wqy-zenhei + +# Copy built application +COPY --from=builder /app/dist ./dist +COPY package.json pnpm-lock.yaml ./ + +# Install production dependencies +RUN pnpm install --prod + +# Create a non-root user for security +RUN addgroup -g 1001 -S pptruser \ + && adduser -S -D -H -u 1001 -s /sbin/nologin -G pptruser pptruser \ + && mkdir -p /home/pptruser/Downloads \ + && chown -R pptruser:pptruser /home/pptruser \ + && chown -R pptruser:pptruser /app + +# Set environment variables +ENV HOST=0.0.0.0 +ENV PORT=4321 +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true +ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser +ENV CHROME_BIN=/usr/bin/chromium-browser +ENV CHROME_PATH=/usr/bin/chromium-browser + +# Expose port +EXPOSE 4321 + +# Switch to non-root user +USER pptruser + +# Start the application +CMD ["node", "./dist/server/entry.mjs"] diff --git a/README.md b/README.md index 7e45a7b..bc39d7e 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ description = "Brief description of the award" 1. **Configure Resume**: Edit `src/config/data.ts` to enable/disable sections 2. **Add Resume Data**: Create `public/files/resume.toml` with your information 3. **View Resume**: Navigate to `/resume` on your site -4. **Generate PDF**: Click "Generate PDF Resume" button for downloadable PDF +4. **Generate PDF**: Click "Download Resume" button for downloadable PDF ## Development diff --git a/public/files/Atridad_Lahiji_Resume.pdf b/public/files/Atridad_Lahiji_Resume.pdf deleted file mode 100644 index 5e5191c..0000000 Binary files a/public/files/Atridad_Lahiji_Resume.pdf and /dev/null differ diff --git a/src/components/PdfDownloadButton.tsx b/src/components/PdfDownloadButton.tsx index eeb16a5..c413fed 100644 --- a/src/components/PdfDownloadButton.tsx +++ b/src/components/PdfDownloadButton.tsx @@ -67,7 +67,7 @@ export default function PdfDownloadButton({ > - Generate PDF Resume + Download Resume PDF )} diff --git a/src/pages/api/resume/pdf.ts b/src/pages/api/resume/pdf.ts index 07c89d4..8d00386 100644 --- a/src/pages/api/resume/pdf.ts +++ b/src/pages/api/resume/pdf.ts @@ -327,7 +327,22 @@ export const GET: APIRoute = async ({ request }) => { const browser = await puppeteer.launch({ headless: true, - args: ["--no-sandbox", "--disable-setuid-sandbox"], + executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined, + args: [ + "--no-sandbox", + "--disable-setuid-sandbox", + "--disable-dev-shm-usage", + "--disable-accelerated-2d-canvas", + "--no-first-run", + "--no-zygote", + "--single-process", + "--disable-gpu", + "--disable-background-timer-throttling", + "--disable-backgrounding-occluded-windows", + "--disable-renderer-backgrounding", + "--disable-features=TranslateUI", + "--disable-ipc-flooding-protection", + ], }); const page = await browser.newPage();