# Notes App — AWS Cloud Deployment ## What the application does A **Notes** web application where users can create, view, and delete short text notes via a web browser. Notes are stored persistently in a PostgreSQL database. The app is publicly accessible over HTTPS at the configured domain. --- ## Cloud services and architecture **Cloud provider:** Amazon Web Services (AWS), region `eu-central-1` (Frankfurt) | Service | Purpose | |---|---| | **Amazon ECS Fargate** | Runs the frontend and backend containers serverlessly. Automatically restarts containers on failure. | | **Amazon RDS (PostgreSQL 16)** | Managed relational database. Provides persistent storage, automated backups (7-day retention). | | **Application Load Balancer (ALB)** | Receives all internet traffic. Routes `/api/*` to the backend, everything else to the frontend. Redirects HTTP → HTTPS. | | **AWS Certificate Manager (ACM)** | Issues and renews a free TLS/HTTPS certificate for the domain. | | **Amazon ECR** | Private Docker image registry. Stores the backend and frontend images. | | **AWS Secrets Manager** | Stores the database password securely. Never stored in code or Git. | | **Amazon CloudWatch Logs** | Collects access logs and application logs from both containers. | | **Amazon VPC + Security Groups** | Network isolation. ALB SG allows 80/443 from internet. ECS SG allows traffic only from ALB. RDS SG allows 5432 only from ECS. | ### Architecture ``` Browser (HTTPS) │ ▼ Application Load Balancer (port 443, ACM certificate, HTTP→HTTPS redirect) │ ├── /api/* ──▶ ECS Fargate: Backend (Flask, port 5000) │ │ │ ▼ │ RDS PostgreSQL (port 5432, private subnet) │ └── /* ──▶ ECS Fargate: Frontend (Nginx, port 80) ``` The browser loads the static frontend from the ALB. All API calls (`/api/*`) are made by the browser directly to the ALB, which forwards them to the backend. The frontend container serves only static files — it does not proxy to the backend. The backend connects to RDS using the `DATABASE_URL` environment variable. --- ## Cost analysis — 1,000 users/day, 50 GB database Estimated for **eu-central-1 (Frankfurt)**, 1 year of operation. | Resource | Specification | Unit price | Monthly | Annual | |---|---|---|---|---| | ECS Fargate — Backend | 0.25 vCPU, 0.5 GB RAM, 730 h/mo | $0.04048/vCPU-h + $0.004445/GB-h | ~$8.30 | ~$99.60 | | ECS Fargate — Frontend | 0.25 vCPU, 0.5 GB RAM, 730 h/mo | same | ~$8.30 | ~$99.60 | | RDS db.t3.micro | PostgreSQL, 1 vCPU, 1 GB RAM, 730 h/mo | ~$0.022/h | ~$16.10 | ~$193.20 | | RDS Storage | 50 GB gp2 | $0.138/GB-mo | ~$6.90 | ~$82.80 | | RDS Automated Backups | 50 GB (free up to DB size) | $0.00 | $0.00 | $0.00 | | ALB | 1 ALB + ~1,000 req/day (~30k/mo) | $0.0252/h + LCU | ~$18.50 | ~$222.00 | | ECR | ~500 MB images stored | $0.10/GB-mo | ~$0.05 | ~$0.60 | | CloudWatch Logs | ~5 GB/mo ingestion | $0.57/GB | ~$2.85 | ~$34.20 | | Data Transfer Out | ~10 GB/mo (1,000 users × ~330 KB) | $0.09/GB | ~$0.90 | ~$10.80 | | Secrets Manager | 1 secret | $0.40/secret/mo | $0.40 | $4.80 | | **Total** | | | **~$62.30** | **~$747.60** | > Prices are estimates based on AWS public pricing (2025). Actual costs depend on traffic patterns. Use the [AWS Pricing Calculator](https://calculator.aws) for exact quotes. --- ## Files and their content ``` sk1/ ├── prepare-app.sh # Creates all AWS resources and deploys the app ├── remove-app.sh # Tears down all AWS resources ├── backup.sh # Creates a manual RDS snapshot ├── .env.example # Template for required environment variables ├── .gitignore # Excludes .env from Git ├── backend/ │ ├── app.py # Flask REST API: GET/POST/DELETE /api/notes, /health │ ├── requirements.txt # Python dependencies: flask, psycopg2-binary │ └── Dockerfile # python:3.12-slim, runs app.py on port 5000 ├── frontend/ │ ├── index.html # Single-page app: dark UI, fetch() calls to /api/ │ ├── nginx.conf # Nginx: serves index.html for all paths │ └── Dockerfile # nginx:1.27-alpine, serves static files └── db/ └── init.sql # Creates notes table, inserts sample rows ``` --- ## Configuration description All secrets and environment-specific values are passed via environment variables, never hardcoded in source files: - **`DATABASE_URL`** — injected into the backend ECS task definition at deploy time. Constructed from `DB_USERNAME`, `DB_PASSWORD`, `DB_HOST`, `DB_NAME`. - **`DB_PASSWORD`** — stored in AWS Secrets Manager under `notes-app/db-password`. Set via `.env` before running the script. - **`DOMAIN_NAME`** — the public domain for the app (e.g. `notes.example.com`). Used to request the ACM certificate and configure the ALB. - **`AWS_REGION`** / **`AWS_ACCOUNT_ID`** — target AWS account and region. The `.env` file is listed in `.gitignore` and must never be committed to Git. --- ## How to run and use the application ### Prerequisites - AWS CLI installed and configured (`aws configure`) with permissions for: ECS, ECR, RDS, ELB, ACM, IAM, EC2, Secrets Manager, CloudWatch Logs - Docker installed and running - A domain name you control (to add DNS CNAME records) ### Deploy ```bash cd sk1 cp .env.example .env # Edit .env — fill in AWS_REGION, AWS_ACCOUNT_ID, DOMAIN_NAME, DB_PASSWORD source .env chmod +x prepare-app.sh remove-app.sh ./prepare-app.sh ``` During deployment the script will print two DNS records to add: 1. A CNAME for ACM certificate validation 2. A CNAME pointing your domain to the ALB Once DNS propagates and the certificate is validated, open **https://your-domain.com** in a browser. ### Use the app - Type a note in the text box and click **+ Add Note** - Notes appear below, newest first - Click **✕ Delete** to remove a note ### Remove everything ```bash source .env ./remove-app.sh ``` > The ACM certificate is not deleted automatically. Delete it manually if no longer needed: > `aws acm delete-certificate --certificate-arn --region $AWS_REGION` --- ## How to perform a data backup RDS automated backups are enabled with a **7-day retention period** and run automatically every day. **Manual snapshot using the provided script:** ```bash source .env ./backup.sh ``` This creates a timestamped RDS snapshot (e.g. `notes-app-manual-20260520-120000`) and waits for it to complete. **Restore from snapshot:** ```bash aws rds restore-db-instance-from-db-snapshot \ --db-instance-identifier notes-app-db-restored \ --db-snapshot-identifier \ --region $AWS_REGION ``` **Export data as SQL dump** (requires `psql` and RDS publicly accessible or VPN): ```bash PGPASSWORD=$DB_PASSWORD pg_dump \ -h -U $DB_USERNAME -d $DB_NAME \ > backup_$(date +%Y%m%d).sql ``` --- ## How to view access logs from the internet Container logs (including Nginx access logs) are streamed to **Amazon CloudWatch Logs**. **Live tail — frontend (Nginx access log):** ```bash aws logs tail /ecs/notes-app/frontend --follow --region $AWS_REGION ``` **Live tail — backend:** ```bash aws logs tail /ecs/notes-app/backend --follow --region $AWS_REGION ``` **Query last 100 log events:** ```bash aws logs get-log-events \ --log-group-name /ecs/notes-app/frontend \ --log-stream-name $(aws logs describe-log-streams \ --log-group-name /ecs/notes-app/frontend \ --order-by LastEventTime --descending \ --query "logStreams[0].logStreamName" --output text --region $AWS_REGION) \ --limit 100 \ --region $AWS_REGION ``` --- ## Conditions for running prepare-app.sh and remove-app.sh **prepare-app.sh:** - AWS CLI must be installed and configured with credentials that have permissions for: ECS, ECR, RDS, ELB, ACM, IAM, EC2, Secrets Manager, CloudWatch Logs - Docker must be running locally - `.env` must exist with all required variables set (`AWS_REGION`, `AWS_ACCOUNT_ID`, `DOMAIN_NAME`, `DB_PASSWORD`) - The domain in `DOMAIN_NAME` must be one you can add DNS CNAME records to - Run from the `sk1/` directory: `source .env && ./prepare-app.sh` - The script is idempotent — safe to run multiple times **remove-app.sh:** - Same AWS CLI and `.env` requirements as above - All deletions are idempotent — safe to run multiple times - Run from the `sk1/` directory: `source .env && ./remove-app.sh` **backup.sh:** - Same AWS CLI and `.env` requirements as above (`AWS_REGION` is sufficient) - RDS instance `notes-app-db` must be running - Run from the `sk1/` directory: `source .env && ./backup.sh` --- ## Use of artificial intelligence This project was developed with the assistance of **Kiro AI** (`kiro-cli chat` agent, Claude Sonnet model). | What | How AI was used | |---|---| | `prepare-app.sh`, `remove-app.sh`, `backup.sh` | Generated by AI, reviewed and verified by the author against AWS documentation | | `README.md` | Generated by AI based on assignment requirements, reviewed and corrected by the author | | `backend/app.py`, `frontend/index.html` | Originally written for a previous assignment, adapted with AI assistance | | `nginx.conf`, `Dockerfiles`, `init.sql` | Generated by AI, reviewed by the author | The AI was used as a coding assistant. All generated content was reviewed, understood, and verified by the author before submission.