Files
imperva-demo/docs/DEPLOY.md
T
matt 4d60fdd139 Initial commit: Imperva WAF demo lab
Flight-booking app scaffolded from the source running on the GCP host,
plus the four-screen frontend and three OWASP attack endpoints (SQLi,
reflected XSS, path traversal) built and locally verified against a
live uvicorn/vite dev pair. Includes deploy.sh (local build -> ship
over ssh -> swap on host) and docs/ carried over from the handoff.
2026-07-29 11:08:56 -07:00

4.0 KiB

Deploy Workflow

Local code → finished image shipped over SSH → container swapped on the host. No container registry (see DECISIONS.md D8 for why).

The two channels to the host

Both go to the same GCP box; they're used for different steps:

  • podman save … | ssh … podman load — ships the image bytes. This has to use raw ssh because it's a pipe into the remote Podman CLI.
  • podman --connection gcp-lab … — swaps the running container over the existing rootless socket, hands-free (no manual SSH). The alias is already configured and set as default: ssh://matt@35.203.147.44:22/run/user/1001/podman/podman.sock.

The socket is under UID 1001 on this host (the original architecture doc's 1000 is wrong). Using the alias means you never have to think about the UID.

Why build locally

The e2-micro can't build the Vue multi-stage image reliably (memory). Always build on the local workstation and ship the finished image. Never build on the host.

deploy.sh

Lives at the repo root and is run from there (so the relative ./backend and ./frontend build contexts resolve). Config block at the top holds host/user/key/alias.

Usage:

./deploy.sh                 # full cycle: build both, ship both, swap both containers
VERSION=v2 ./deploy.sh      # tag images v2 instead of a timestamp → named rollback point
./deploy.sh --build --ship --swap   # explicit equivalent of the default
./deploy.sh --restart-caddy # after editing the Caddyfile to add/modify routes

With no arguments it runs build → ship → swap. VERSION defaults to a timestamp; set it explicitly to create a named point you can redeploy later.

Steps the script performs

  1. build — podman build the backend and frontend images locally.
  2. ship — podman save <img> | ssh -i <key> matt@35.203.147.44 'podman load' for each image.
  3. swap — over --connection gcp-lab: rm -f then run -d each container with its name and port mapping.
  4. restart-caddy (on demand) — podman --connection gcp-lab restart caddy-proxy, needed only when the Caddyfile changed (e.g. new XSS/traversal routes).

IMPORTANT: keep swap() in sync with real run flags

The current swap() recreates containers with only --name and -p. It does not yet reproduce any bind mounts (e.g. the SQLite demo.db), config-file mounts, or network/DNS-alias flags the real containers depend on. Before relying on the script, confirm the actual podman run flags the current backend-api and frontend-vue were created with and fold them into swap(), or a deploy will silently drop them.

To inspect what the running containers actually use:

podman --connection gcp-lab inspect backend-api  | jq '.[0].Mounts, .[0].NetworkSettings'
podman --connection gcp-lab inspect frontend-vue | jq '.[0].Mounts, .[0].NetworkSettings'

Caddy config / cert deploys

The Caddyfile and certs live on the host at ~/imperva-proxy/ and are bind-mounted read-only into caddy-proxy. To change routing:

  1. Edit imperva-proxy/Caddyfile in the repo, copy it to the host ~/imperva-proxy/.
  2. Validate before restarting so you're not debugging from a crash loop:
    podman --connection gcp-lab exec caddy-proxy caddy validate --config /etc/caddy/Caddyfile
    
  3. ./deploy.sh --restart-caddy.

If the container is already crash-looping and exec won't attach, validate against the mount with a throwaway container instead:

podman run --rm -v /home/matt/imperva-proxy/Caddyfile:/etc/caddy/Caddyfile:ro,Z \
  docker.io/library/caddy:2-alpine caddy validate --config /etc/caddy/Caddyfile

Verifying a deploy

  • Origin health from the host (self-signed, so -k):
    podman --connection gcp-lab exec caddy-proxy sh -c 'wget -qO- --no-check-certificate https://localhost/ | head'
    
    (or curl -vk https://localhost/ directly on the host)
  • Real path end to end: load https://flytoouter.space/ in a browser — should show Imperva's trusted edge cert while the origin serves self-signed to Imperva only.