All Projects

Everything, not just what fits on the homepage — two production case studies alongside three smaller side builds. Each links out to a full write-up.

URL Shortener on ECS Fargate

In progress

A Python/FastAPI URL shortener being built in phases from an empty AWS account, targeting ECS Fargate provisioned by Terraform, with a GitHub Actions pipeline and CloudWatch observability in later phases. Phases 0 and 1 are done: IAM bootstrap, and a multi-stage Docker build running as a non-root user — 230MB versus the 1GB+ a naive single-stage build produces.

The build log is the point. It records the real reasoning — why root credentials can't be scoped down the way an IAM identity can, why health checks belong on a dedicated dependency-light route rather than a business-logic one — and the mistakes as they happened, including a credential exposure that led to adding gitleaks pre-commit scanning, and the discovery that gitleaks' AWS rule doesn't flag a bare AKIA key without valid checksum structure. Most portfolios show only the polished result.

  • AWS
  • IAM
  • Docker
  • FastAPI
  • gitleaks
  • ECS Fargate
  • Terraform
  • GitHub Actions
  • CloudWatch

DevOps Engineering Portfolio

Live

Three sanitized case studies from production work at Keel Digital. Each documents the actual constraints and the reasoning behind the architecture that answered them, with before/after diagrams rather than just the finished state.

Proxmox bare-metal migration

14 DigitalOcean droplets migrated to a single OVHcloud bare-metal box behind a NAT gateway — ~$1,500 CAD/month saved, no VM left with a public IP.

Self-managed OpenSearch SIEM

40+ services, Sigma detection rules, and tiered retention for a HIPAA/FedRAMP-scoped environment — data residency ruled out a third-party SIEM.

OPKSSH dev access

Static SSH keys replaced with OPKSSH-issued, Google Workspace-bound certificates for tiered dev access — offboarding no longer depends on someone remembering to edit authorized_keys.

  • Proxmox VE
  • OVHcloud
  • OpenSearch
  • Sigma
  • OPKSSH
  • Google Workspace
  • Keycloak
  • AWS

Keycloak Monitoring via Zabbix

Live

A Zabbix template and alert pipeline for Keycloak's Prometheus metrics, built to avoid standing up a separate Prometheus/Alertmanager stack just to watch one service. A single HTTP master item scrapes the metrics endpoint every minute; dependent items extract series using Zabbix's Prometheus preprocessing, so identity monitoring lives in the same place — and the same on-call rotation — as everything else.

Triggers watch for what actually matters: failed-login spikes, service-to-service auth errors that a quietly rotated client secret would cause, and the metrics endpoint going dark. Alerts route to Google Chat through a custom webhook media type, and a CI job lints the template on every push.

  • Zabbix
  • Keycloak
  • Prometheus
  • Sigma
  • Google Chat Webhook
  • GitHub Actions

Terraform Module: Scheduled Lambda + EventBridge

Live

A Terraform module for the ops-automation shape I kept rebuilding by hand: a Lambda function on an EventBridge schedule, with the IAM and logging defaults done correctly instead of copy-pasted. The execution role is scoped to just this function's log group rather than the AWS-managed policy's account-wide logs:* grant, and the CloudWatch log group is created explicitly so retention is enforced from the first invocation.

The module packages a pre-built Lambda zip rather than building it — CI stays out of the module and in the pipeline where it belongs. Ships with a working example, tflint checks, and release-please for versioned releases.

  • Terraform
  • AWS Lambda
  • EventBridge
  • IAM
  • CloudWatch
  • GitHub Actions
  • tflint

Grocery Bot: Meal Planning on GitHub Actions

Live

Weekly meal-planning and grocery-list automation with zero hosting cost — the whole thing runs as two scheduled GitHub Actions jobs talking to a Discord channel. Sunday morning, one workflow posts the week's meal options from a YAML file and adds a reaction emoji per meal; family votes by reacting during the day; Sunday evening, a second workflow reads the reactions, maps each pick back to its ingredients, and posts an aggregated, deduped grocery list.

The two-run design exists because GitHub Actions can't listen for replies in real time — reactions become the persistence layer instead of a live bot process. The morning post's message ID is committed back to the repo so the evening run can find it, and Discord is driven through a small hand-rolled REST wrapper (with 429 retry handling) rather than a full bot framework — no gateway connection, no privileged intents. Ingredients live in a manually maintained YAML pool instead of a recipe API: exact quantities, no rate limits, no extra keys.

  • Python
  • GitHub Actions
  • Discord REST API
  • requests
  • PyYAML
  • cron