DP — JIMPAPADIMAS.COM ← back to portfolio
Case study — Infrastructure

How this site actually runs.

This page is hosted by the system it describes. A look under the hood of jimpapadimas.com — the AWS infrastructure, the container setup, the delivery model, and the security decision behind each piece.

host   AWS EC2 · eu-north-1
edge   nginx · Let’s Encrypt
deploy GitHub Actions · SSM
scan   Trivy

The system at a glance

01 / OVERVIEW

Everything runs on one small EC2 instance in eu-north-1 with a static Elastic IP. A single host nginx terminates TLS and routes each hostname to its own Docker container — one container per site. New projects arrive as subdomains on the same box; no new servers, no new IPs.

There is no public SSH. Operator access and deploys both go through AWS Systems Manager, so port 22 stays closed to the internet entirely. The design goal throughout: spin up a new project freely, while keeping the attack surface and the running cost small.

Request path

02 / ARCHITECTURE
Visitor
https / 443
Bluehost DNS
A record
Elastic IP · EC2
eu-north-1 · :22 closed
host nginx
TLS · vhost router
apex
127.0.0.1:8080
this page
127.0.0.1:8081

DNS points the domain and each subdomain at one Elastic IP — a static address that survives instance restarts. nginx then does the interesting work: it terminates TLS and uses name-based virtual hosting to match the incoming Host header against a per-site server block, forwarding each hostname to the right container.

Every container binds only to 127.0.0.1, so nothing is reachable from the internet except through nginx. Adding a project is three repeatable steps — a DNS record, an nginx server block on a fresh local port, and a Let’s Encrypt certificate — and the architecture above doesn’t change.

From commit to live

03 / DELIVERY
Local dev
git push
GitHub Actions
OIDC · build · Trivy
Amazon ECR
image : sha
SSM
send-command
EC2
pull · up · health-check

A push to main triggers a pipeline that authenticates to AWS via OIDC federation — no cloud keys stored in the repository. It builds the image, scans it with Trivy and fails the build on high-severity findings, then pushes a commit-SHA-tagged image to ECR. Deployment is triggered over SSM: the instance pulls the new image, swaps the container, and runs a health check that rolls back automatically if the new release doesn’t answer.

status — this is the target delivery model. Today the source lives in a private monorepo on GitHub; deploys are git pull onto the box, and the bind-mounted nginx:alpine container picks up the new files instantly. The OIDC · Trivy · ECR pipeline above is wired next — same end state, automated trigger.

Deliberate choices

04 / SECURITY

No public SSH

Operator access runs through SSM Session Manager. Port 22 is closed to the internet, and every session is recorded in CloudTrail.

No static cloud keys

CI authenticates with short-lived OIDC tokens; the local CLI uses temporary aws login credentials. Nothing long-lived sits on disk or in the repo.

Least-privilege IAM

The deploy role can push to exactly one ECR repository and send commands to exactly one instance — nothing wider.

Root as break-glass

The root account has MFA and is otherwise untouched; day-to-day work runs as a separate non-root admin identity.

Containers on localhost

Application containers bind to 127.0.0.1 only. The host nginx is the single, deliberate ingress point.

Scanning before ship

Trivy gates the image in the designed CI pipeline; ECR scans on push. A vulnerable image fails the build rather than reaching production.

TLS by default

Let’s Encrypt certificates per hostname, auto-renewing, with HTTP redirected to HTTPS.

Immutable releases

Images are tagged by commit SHA, so any deploy is reproducible and a rollback is a single re-point to the previous tag.

Where it’s going

05 / NEXT