improvement: docker infrastructure overhauled.
This commit is contained in:
@@ -1,72 +1,53 @@
|
||||
# Build stage
|
||||
# Build stage — produces `.next/standalone` (see next.config.ts output: standalone)
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Set build-time environment variables
|
||||
ARG NEXT_PUBLIC_API_URL
|
||||
ARG NEXT_PUBLIC_APP_URL
|
||||
ARG NEXT_PUBLIC_APP_NAME
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||
ENV NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
|
||||
ENV NEXT_PUBLIC_APP_NAME=${NEXT_PUBLIC_APP_NAME}
|
||||
|
||||
# Build Next.js application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:18-alpine
|
||||
# Production — minimal runtime using Next.js standalone bundle
|
||||
FROM node:18-alpine AS runner
|
||||
|
||||
RUN apk add --no-cache dumb-init
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dumb-init for proper signal handling
|
||||
RUN apk add --no-cache dumb-init
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S dyolink -u 1001
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
|
||||
# Install production dependencies only
|
||||
RUN npm ci --only=production && \
|
||||
npm cache clean --force
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder /app/next.config.js ./next.config.js
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder --chown=dyolink:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=dyolink:nodejs /app/.next/static ./.next/static
|
||||
|
||||
# Create logs directory
|
||||
RUN mkdir -p /app/logs && \
|
||||
chown -R dyolink:nodejs /app
|
||||
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||
|
||||
# Set ownership
|
||||
RUN chown -R dyolink:nodejs /app
|
||||
|
||||
# Switch to non-root user
|
||||
USER dyolink
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
|
||||
CMD node -e "require('http').get('http://localhost:3000', (r) => {if(r.statusCode!==200)throw new Error()})" || exit 1
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV NODE_ENV=production
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
|
||||
CMD node -e "require('http').get('http://127.0.0.1:3000/', (r) => {if(r.statusCode!==200)process.exit(1)})"
|
||||
|
||||
# Copy entrypoint script
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||
|
||||
# Use dumb-init for signal handling
|
||||
ENTRYPOINT ["dumb-init", "--", "docker-entrypoint.sh"]
|
||||
|
||||
CMD ["npm", "start"]
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
// frontend/next.config.js
|
||||
function publicAppHostname(): string | null {
|
||||
const url = process.env.NEXT_PUBLIC_APP_URL;
|
||||
if (!url) return null;
|
||||
try {
|
||||
return new URL(url).hostname;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const appHost = publicAppHostname();
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
// Enable React strict mode
|
||||
@@ -9,12 +20,19 @@ const nextConfig = {
|
||||
// Disable x-powered-by header for security
|
||||
poweredByHeader: false,
|
||||
|
||||
// Configure allowed remote image sources
|
||||
// Configure allowed remote image sources (hostname derived from NEXT_PUBLIC_APP_URL at build time)
|
||||
images: {
|
||||
remotePatterns:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? [{ protocol: 'https', hostname: 'yourdomain.com' }]
|
||||
: [{ protocol: 'http', hostname: 'localhost' }],
|
||||
remotePatterns: [
|
||||
{ protocol: "http", hostname: "localhost" },
|
||||
...(appHost
|
||||
? [
|
||||
{ protocol: "http" as const, hostname: appHost },
|
||||
{ protocol: "https" as const, hostname: appHost },
|
||||
]
|
||||
: []),
|
||||
{ protocol: "https", hostname: "dyolink.com" },
|
||||
{ protocol: "https", hostname: "www.dyolink.com" },
|
||||
],
|
||||
},
|
||||
|
||||
// Environment variables that will be available at build time
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev -p 3001",
|
||||
"dev": "next dev -p 3000",
|
||||
"build": "next build",
|
||||
"start": "next start -p 3001",
|
||||
"start": "next start -p 3000",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
Reference in New Issue
Block a user