Skip to content

build: serve frontend and marketing via unprivileged nginx on 8080 - #1198

Draft
ital0 wants to merge 3 commits into
mainfrom
cursor/sec-nonroot-nginx
Draft

build: serve frontend and marketing via unprivileged nginx on 8080#1198
ital0 wants to merge 3 commits into
mainfrom
cursor/sec-nonroot-nginx

Conversation

@ital0

@ital0 ital0 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes code-scanning alert #11 (dockerfile.security.missing-user on frontend.Dockerfile). marketing.Dockerfile has the identical pattern and is fixed alongside for consistency.

Changes

Both nginx images now use nginxinc/nginx-unprivileged:alpine (runs as nginx, uid 101) instead of nginx:alpine (root). It's built from the same official entrypoint scripts, so the /etc/nginx/templates/*.template envsubst machinery the frontend relies on keeps working. Non-root can't bind port 80, so nginx moves to 8080, updated across every layer:

  • deploy/config/nginx.conf.template + deploy/config/marketing-nginx.conflisten 8080
  • Pulumi — frontend/marketing target-group ports and ECS containerPort/portMappings in alb.ts, per-pr-stack.ts, services.ts. The public ALB HTTP listener and ALB security group stay on 80/443. servicesSg already allows TCP 0–65535 from the ALB SG, so no SG change was needed.
  • k8scontainerPort, readiness-probe port and explicit Service targetPort: 8080 in frontend.yaml/marketing.yaml (external Service ports unchanged).
  • deploy/docker-compose.yml — host mapping now targets 8080 (external port unchanged, ${FRONTEND_PORT:-3000}).
  • Docs updated (deploy/README.md, deploy/docker/README.md, docs/self-hosting/docker-compose.md).

Deploy note

Changing a TargetGroup's port forces replacement; namePrefix gives create-before-destroy, but existing stacks will briefly re-register targets on their next pulumi up. Per-PR preview stacks are ephemeral, so impact there is minimal. This PR's own preview deploy exercises the new port wiring end to end.

Validation

  • Both images built locally; curl returns 200 and the nginx process runs as uid=101(nginx) in both.
  • bunx tsc --noEmit passes in deploy/pulumi.

ital0 added 3 commits August 5, 2026 16:39
- run nginx as non-root uid 101 and move container, service target, and target-group traffic from port 80 to 8080
- keep public ALB listeners on port 80
- note that the target-group port change replaces target groups on the next Pulumi update
- satisfy container hardening and code-scanning checks with an explicit runtime user
- retain port 8080 target-group and container mappings for non-root nginx
- keep deployment guidance aligned with the hardened container base
- document the frontend container's port 8080 target
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Semgrep Security Scan

No security issues found.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Preview environment deployed 🚀

Service URL
Marketing / blog / docs https://thunderbolt-pr-1198.preview.thunderbolt.io
App https://app-pr-1198.preview.thunderbolt.io
API https://api-pr-1198.preview.thunderbolt.io
Keycloak https://auth-pr-1198.preview.thunderbolt.io
PowerSync https://powersync-pr-1198.preview.thunderbolt.io

Stack: preview-pr-1198 · Commit: 9ee24673458ebc9a2f27da681e0a334ca8563967

Auto-destroys on PR close/merge. Login via the bundled Keycloak realm — demo@thunderbolt.io / demo by default.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR Metrics

Metric Value
Lines changed (prod code) +34 / -26
JS bundle size (gzipped) 🟢 589.2 KB → 591.2 KB (+1.9 KB, +0.3%)
Test coverage 🟢 81.28% → 81.34% (+0.1%)
Performance (preview) Preview not ready — Render deploy may have timed out
Accessibility
Best Practices
SEO

Updated Wed, 05 Aug 2026 20:49:33 GMT · run #2608

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant