cd ../case-studies

// case study 01

From shared server passwords to new projects live in 30 minutes

Software agency 40+ developers 30+ projects 3 years AWS · GCP · DigitalOcean
~30 min to take a new project live, given the repo and database
99.99% uptime, measured in Grafana
10k / 5 min marketing emails sent without taking servers down
0 times developers needed to touch a server

The situation

A growing software agency ran 30+ projects in Node.js, React, PHP, Go and Python, across its own DigitalOcean servers and its clients' AWS and GCP accounts. Server configuration was inconsistent, everyone had the server passwords, and every new project meant setting things up by hand again.

What changed

access & security

Replaced password logins with key-based (PEM) SSH, allowed only from approved IP addresses. Defined roles and permissions for admins and developers, down to who could see PM2 processes. Added UFW, security groups, fail2ban, closed unused ports and a regular patching schedule. When someone left, credentials were rotated immediately.

standard setups

Reusable templates for Apache sites and subdomains, PM2 apps and Go binary deployments, all behind Let's Encrypt SSL with DNS on Cloudflare. Separate PM2 run modes for development and production builds, and servers tuned so RAM and disk were used efficiently.

client infrastructure

Provisioned AWS EC2 and GCP VMs to each client's requirements, with separate read and write database roles, read replicas and a Redis/Valkey caching layer. Docker for many of the services.

automation & visibility

CI/CD pipelines in GitHub Actions, GitLab CI and Jenkins for dev, staging and production, plus a scripted release process for PM2 apps. Make-based recipes and Bash scripts for setup, and backup/restore templates storing to local disk or AWS/GCP buckets. Loki and Grafana for logs, metrics and analytics.

incident.log

When marketing campaigns took the servers down

[problem]

Marketing newsletters and product campaigns were sent straight from the application, which talked directly to the database. During large sends, the database or the Apache server regularly went down.

[diagnosis]

Debugging showed it wasn't a bug but volume: every send created load the database couldn't absorb. That traffic had to be moved off the database.

[fix]

Redirected the high-volume traffic to a Redis/Valkey caching layer and built a queue with worker processes in front of SendGrid, with batching, rate limiting and automatic retries for failed sends.

[result]

10,000 emails sent in about 5 minutes. The servers stayed up through campaigns, and email tracking kept working.

Stack

Linux Apache Nginx PM2 Docker Let's Encrypt Cloudflare AWS EC2 GCP DigitalOcean MySQL PostgreSQL MongoDB Redis / Valkey SendGrid GitHub Actions GitLab CI Jenkins Loki Grafana Bash Make

Client details are anonymized to protect confidentiality.

Running into the same problems?

Let's talk it through. 30 minutes, free.

Book your free 30-min call