Deploying Appwrite on AWS ECS: Secrets, Logs, and a 503 Walk Into a Cluster


Disclaimer: This is not a tutorial. This is a DevOps survival story. Bring snacks.
🚀 Phase 2 Begins: "Let's Deploy Something Real!"
After weeks of DevOps theory, CLI rituals, and nodding at diagrams like I understood them, I decided: it’s time. Time to deploy something real — not a Hello World app, but a complex, open-source platform.
Enter: Appwrite — the backend-as-a-service that wants to replace Firebase (and maybe even your backend devs).
💡 Why Appwrite?
Because it’s open-source, Docker-based, self-hostable, and throws real-world challenges at your infra setup — secrets, dependencies, health checks, workers, ports, databases... you name it.
Perfect for testing my ECS + Terraform + CloudWatch muscles.
🛠️ The Setup
🗺️ Architecture Diagram
To visualize all the moving parts, here’s a simple architecture of what Phase 2 looks like:
+----------------------------+
| User (Browser) |
+-------------+-------------+
|
v
+-------+-------+
| ALB (HTTP)|
+-------+-------+
|
v
+-------+-------+ +---------------------+
| ECS Fargate | <---> | CloudWatch Logs |
| Appwrite Task | +---------------------+
+-------+-------+
|
v
+---------------------------+
| Secrets Manager (.env) |
| IAM Role fetches Secret |
+---------------------------+
This was just Phase 2. In Phase 3, we’ll plug in RDS MySQL for persistence.
Here's what I wanted to do:
Launch Appwrite on AWS ECS Fargate
Manage infra using modular Terraform
Handle secrets via Secrets Manager
Wire everything: VPC, ALB, IAM, CloudWatch Logs
And of course... not go mad
🧱 Services Deployed (a.k.a. My Lego Stack)
ECS Cluster
➜ Fargate-powered, so I don’t manage EC2sALB
➜ Exposed the app publiclySecrets Manager
➜ Stored my Appwrite .env like a treasure mapIAM
➜ Gave my ECS task permission to fetch those secretsCloudWatch
➜ Where I watched things crash in real-time (thank you logs 🙏)
🤯 The First 503
Hit the ALB DNS, and boom — 503 Service Unavailable.
My heart said, “It’s AWS, it’ll figure itself out.”
My brain said, “No targets are healthy, dummy.”
Diagnosis: Appwrite container was stopping. Why? Because ECS couldn’t fetch secrets. Why? Because IAM role had no permission. Why? Because I hardcoded nothing. Oops.
✅ Fix: IAM Role Policy (but make it dynamic)
Instead of hardcoding the secret ARN (bad), I passed it from the secrets
module as a variable (good).
variable "appwrite_env_secret_arn" {}
resource "aws_iam_role_policy" "ecs_secrets_access" {
...
Resource = var.appwrite_env_secret_arn
}
This worked beautifully — until Appwrite tried connecting to a database that didn’t exist 😅
🕵️♂️ The Logs Never Lie
Database not ready. Retrying connection (6)...
...
Exit code: 255
So Appwrite was up... just lonely. No MySQL friend.
I could’ve gone into sleep 3600
debug mode to keep the container alive, but where’s the fun in that?
🔜 Coming Next: RDS + Full Boot
In Phase 3, I’ll:
Create RDS MySQL via Terraform
Inject DB creds into Secrets Manager
Watch Appwrite finally boot like a champ
👉 View the full Terraform code on GitHub
🧠 Key Learnings
Always log. Never guess.
CloudWatch is your DevOps third eye.
IAM will betray you unless you give it exactly what it needs.
Modular Terraform is your future self’s best friend.
Real-world open-source apps > Hello World demos for learning DevOps
🎯 TL;DR
Phase 2 wasn’t perfect, but it was real. ECS worked, secrets were pulled, Appwrite almost booted — and I understood every moving part.
I didn’t just deploy an app. I deployed confidence.
Next stop: persistent databases, HTTPS, and CI/CD pipelines. Stay tuned.
Got questions? Trying to deploy Appwrite yourself? Or just want to vent about ECS errors? Drop a comment or hit me up on LinkedIn (carrier pigeons also accepted).
Subscribe to my newsletter
Read articles from Deepak Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
