Add Dockerfile and .dockerignore for improved containerization and security

This commit is contained in:
David Dyer committed 2026-10-25 17:09:05 -04:00
1 parent bb65ecd43c
commit 759c22afaf
3 files changed
+52 -21

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
# Secrets and runtime state — never in the build context.
config.php
db/fitz.sqlite*
cache/
# Rebuilt inside the image.
node_modules/
dist/
styles.css
styles.css.map
# Dev-only.
.git/
.claude/
.DS_Store
.hintrc
dev.sh
+20
View File
@@ -0,0 +1,20 @@
# syntax=docker/dockerfile:1
# Build stage: compile Sass and assemble the allowlisted dist/ folder.
# config.php never enters the image (.dockerignore), and build-dist.js
# doesn't copy it anyway.
FROM node:24-alpine AS build
WORKDIR /src
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run dist
# Runtime stage. Production php.ini and expose_php = Off are baked in here,
# replacing the startup `command:` in docker-compose.yaml. Files are owned
# by root with 644/755 (normalized by build-dist.js), so www-data can read
# the site but not modify it; data/ and config/ arrive as mounts.
FROM php:8.5-apache
RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& printf 'expose_php = Off\n' > "$PHP_INI_DIR/conf.d/zz-hardening.ini"
COPY --from=build /src/dist/ /var/www/html/
+15 -21
View File
@@ -1,12 +1,15 @@
# The Old Fitz — production compose for the VPS. # The Old Fitz — compose for any Docker host (test or production).
# #
# Expected layout, one folder per site: # The site itself is baked into the image (see Dockerfile); the host only
# holds state. Expected layout, one folder per site:
# theoldfitz/ # theoldfitz/
# docker-compose.yaml (this file) # docker-compose.yaml (this file)
# .env (optional, see PROXY_NETWORK below) # .env (FITZ_IMAGE, and PROXY_NETWORK if not "proxy")
# www/ (contents of `npm run dist`) # config/config.php (live secrets — never in the image)
# config/config.php (live secrets — never inside www/, never in dist/) # data/ (fitz.sqlite + cache/ — never in the image)
# data/ (fitz.sqlite + cache/ — never inside www/) #
# Deploy: `docker compose pull && docker compose up -d`.
# Manual fallback from a checkout of the repo: `docker compose up -d --build`.
# #
# First run: create data/ and `chown 33:33 data` (www-data in the image). # First run: create data/ and `chown 33:33 data` (www-data in the image).
# Copy config.example.php to config/config.php, fill it in, and make it # Copy config.example.php to config/config.php, fill it in, and make it
@@ -27,27 +30,18 @@ networks:
services: services:
the-old-fitz: the-old-fitz:
image: php:8.5-apache # Servers set FITZ_IMAGE in .env to the registry image, e.g.
# gitea.example.com/david/the-old-fitz:latest. Unset, it falls back to a
# local tag so `up --build` works from a checkout.
image: ${FITZ_IMAGE:-the-old-fitz:local}
build: .
container_name: the-old-fitz container_name: the-old-fitz
restart: unless-stopped restart: unless-stopped
# The image ships without a php.ini, so PHP falls back to dev-style
# defaults and shows errors (with server paths) to visitors. Activate
# the image's bundled production ini — display_errors off, errors to
# the log — and hide the PHP version header, then start Apache as usual.
# Paths are spelled out (the image's $PHP_INI_DIR) rather than using
# the variable, so no $-escaping is needed.
command:
- bash
- -c
- cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && echo 'expose_php = Off' > /usr/local/etc/php/conf.d/zz-hardening.ini && exec apache2-foreground
networks: networks:
- proxy - proxy
volumes: volumes:
- type: bind
source: ./www
target: /var/www/html
# Database and cache live outside the web root so Apache can't serve # Database and cache live outside the web root so Apache can't serve
# them and deploys to www/ never touch them. # them, and outside the image so deploys never touch them.
- type: bind - type: bind
source: ./data source: ./data
target: /var/www/data target: /var/www/data