Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Never bake local state, secrets or VCS data into the backend image.
.env
.env.*
!.env.example

.git
.gitignore
.github
*.md
Dockerfile*
docker-compose*.yml
.dockerignore

# Local database + logs + caches
*.db
*.db-shm
*.db-wal
*.log
__pycache__
*.pyc
.venv
venv
.pytest_cache
28 changes: 17 additions & 11 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
FROM python:3.11-slim
# =============================================================================
# NetCore Backend — FastAPI + Uvicorn
#
# No apt-get at all: every dependency in requirements.txt ships a prebuilt
# manylinux wheel, so no compiler is needed. This keeps the image small, makes
# builds hermetic, and avoids depending on the base image's apt mirror (which is
# inconsistent on this host: the index pins libssl3t64 u2 while u3 is offered,
# so installing libssl-dev fails outright).
# =============================================================================
FROM python:3.12-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*

# Python dependencies
# Python dependencies (wheels only — no build toolchain required)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Application code
COPY . .

# Create non-root user
RUN useradd -m -u 1000 nethermind && chown -R nethermind:nethermind /app
USER nethermind
RUN useradd -m -u 1000 netcore && chown -R netcore:netcore /app
USER netcore

EXPOSE 8000

# trivy DS-0026: healthcheck. Uses the bundled python so no curl/apt is needed.
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=15s \
CMD python -c "import urllib.request;urllib.request.urlopen('http://127.0.0.1:8000/health',timeout=5)" || exit 1

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
9 changes: 2 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
dockerfile: Dockerfile
container_name: nethermind-backend
ports:
- "8000:8000"
- "127.0.0.1:8000:8000"
environment:
- DATABASE_URL=${DATABASE_URL:-sqlite:///./switches.db}
- OPENAI_API_KEY=${OPENAI_API_KEY}
Expand All @@ -17,7 +17,6 @@ services:
- CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:3000,http://localhost:5173}
volumes:
- nethermind-data:/app/data
- ./backend:/app
restart: unless-stopped
networks:
- nethermind-network
Expand All @@ -34,18 +33,14 @@ services:
dockerfile: Dockerfile
container_name: nethermind-frontend
ports:
- "3000:3000"
- "127.0.0.1:3000:3000"
environment:
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:8000}
volumes:
- ./frontend:/app
- /app/node_modules
depends_on:
- backend
restart: unless-stopped
networks:
- nethermind-network
command: ["npm", "run", "dev"]

# PostgreSQL (optional — uncomment for production)
# postgres:
Expand Down
30 changes: 30 additions & 0 deletions frontend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Keep the build context small and prevent local state/secrets from reaching the image.
node_modules
.next
out
build
dist

# Local env files — never bake these into an image
.env
.env.*
!.env.example

# VCS + tooling
.git
.gitignore
.github
*.md
Dockerfile*
docker-compose*.yml
.dockerignore

# Local databases and logs
*.db
*.db-shm
*.db-wal
*.log
__pycache__
*.pyc
.venv
venv
52 changes: 41 additions & 11 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
# Development server (production build requires more memory)
FROM node:20-alpine AS runner
# =============================================================================
# NetCore Frontend — Next.js production image (standalone output)
#
# Previously this image ran `npm run dev`: a hot-reloading development server
# shipped as the production artifact. It now does a real production build and
# runs as a non-root user (trivy DS-0002).
#
# `next.config.js` sets `output: 'standalone'`, so the runtime image only needs
# the traced server bundle — not node_modules.
# =============================================================================

# ── Stage 1: dependencies ───────────────────────────────────────────────────
FROM node:20-alpine AS deps
WORKDIR /app

ENV NODE_ENV=development
ENV NEXT_TELEMETRY_DISABLED=1

# Install dependencies
COPY package.json package-lock.json* ./
RUN npm ci --prefer-offline

# Copy source
# ── Stage 2: build ──────────────────────────────────────────────────────────
FROM node:20-alpine AS builder
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js expects a public/ dir; this repo has none, so create an empty one to
# keep the standalone COPY below valid.
RUN mkdir -p public
RUN npm run build

# ── Stage 3: runtime ────────────────────────────────────────────────────────
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0

# Non-root: the node:alpine image already ships an unprivileged `node` user (uid 1000).
COPY --from=builder --chown=node:node /app/public ./public
COPY --from=builder --chown=node:node /app/.next/standalone ./
COPY --from=builder --chown=node:node /app/.next/static ./.next/static

USER node

# Expose port
EXPOSE 3000

# Run dev server
CMD ["npm", "run", "dev"]
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=20s \
CMD wget --spider -q http://127.0.0.1:3000/ || exit 1

CMD ["node", "server.js"]
Loading