Add Python form API + harden nginx web root

- New api/ Python service (stdlib only — no pip install, no packages):
  validates fields server-side, verifies reCAPTCHA, sends via Resend
  with idempotency key, rate-limited (5 req/IP/15min)
- Matches existing project tooling (build_locations.py, build_services.py)
- Front-end form.js stays vanilla JS, no JS frameworks anywhere
- docker-compose runs nginx + python:3.13-alpine api with healthcheck
- nginx proxies /api/ to Python service, strips prefix
- Dockerfile now copies only public folders into web root (was
  copying everything, exposing /Dockerfile, /build_*.py, /api/.env)
- nginx.conf denies dotfiles, .env, .conf, .yml, .py, .md, .txt
  and Dockerfile as defense in depth
- .dockerignore keeps sensitive files out of build context
- .gitignore protects api/.env and __pycache__ from being committed
This commit is contained in:
Concept Agent
2026-05-08 18:22:46 +02:00
parent b363d19da7
commit e0b9e27b90
9 changed files with 338 additions and 1 deletions
+13 -1
View File
@@ -1,6 +1,18 @@
FROM nginx:alpine
# nginx config (server-only, not served as a static file)
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY . /usr/share/nginx/html/
# Copy only public website assets — everything else (api/, build scripts,
# Dockerfile, .env, docs, screenshots) stays out of the web root.
COPY index.html /usr/share/nginx/html/
COPY assets /usr/share/nginx/html/assets/
COPY components /usr/share/nginx/html/components/
COPY about /usr/share/nginx/html/about/
COPY blog /usr/share/nginx/html/blog/
COPY contact /usr/share/nginx/html/contact/
COPY locations /usr/share/nginx/html/locations/
COPY reviews /usr/share/nginx/html/reviews/
COPY services /usr/share/nginx/html/services/
EXPOSE 80