1. Context
Small businesses and solo entrepreneurs often hesitate to migrate their applications to the cloud due to concerns about cost, complexity, or vendor lock-in. However, on-premises servers involve higher and fixed operational costs — not pay-as-you-go — and limit scalability and security.
This article presents a hybrid AWS architecture tailored to this audience: low cost, high availability, and built-in security. The solution uses managed and serverless services to reduce maintenance and fixed expenses, while keeping the structure simple enough to be operated by small teams.
The model is based on separating the frontend and backend into independent environments, each optimized for its role but integrated within a single cloud infrastructure — including a centralized, secure relational database accessed by the backend. This separation enables modularity, independent deployment cycles, and on-demand scalability, with an average operational cost of around ~$45/month and $15/year for the registration of the domain.
2. Original Architecture and Monolith Limitations
As an example, let's consider a Django + DRF monolith, where the frontend and backend share the same server, deployment cycle, and hardware resources — which prevents independent updates and efficient scaling.
The migration starts by logically separating the services:
- Frontend: Django Templates, to be hosted on Elastic Beanstalk with a custom domain and SSL certificate (ACM)
- Backend: REST API on AWS Lambda, exposed via HTTP API Gateway, integrated with RDS through RDS Proxy, with credentials stored in Secrets Manager
- Communication: the frontend consumes the API via server-to-server calls — eliminating the need for direct browser requests
With this separation, each service has its own lifecycle and can evolve and scale independently.
3. Migration Implementation
3.1 Smart Hybrid Architecture
The Django frontend is hosted on Elastic Beanstalk, delivering server-side rendered (SSR) pages to ensure consistent performance and proper search engine indexing (SEO). The service offers managed autoscaling, reducing the need for manual infrastructure management while keeping costs in check.
Elastic Beanstalk is an excellent alternative to ECS due to its operational simplicity and cost-effectiveness: it abstracts infrastructure, allows direct deployments of Django apps without complex containerization, and integrates natively with ACM for HTTPS.
On the backend, using AWS Lambda removes the need to keep servers running 24/7 — a meaningful benefit for apps with low overnight traffic — making costs strictly proportional to actual usage. This approach ensures automatic scalability and financial predictability without compromising performance.
The database, which was previously running as a standalone MySQL instance on a local server in this example, uses Amazon RDS, configured in a private subnet to prevent direct internet access. Communication between Lambda and RDS goes through RDS Proxy, which maintains a pool of reusable connections.
This setup provides functional compatibility with Django's ORM, reduced latency during traffic spikes, and enhanced security, since only the Lambda function can access the database. Managed RDS eliminates admin tasks like backups and updates, keeping costs predictable and data environments isolated.
3.2 Addressing Django + Lambda Challenges
Running a traditional framework like Django in a serverless environment requires specific adjustments. Below are key considerations for stability and performance:
Event-Driven Compatibility: Django is designed for persistent WSGI servers, making it incompatible by default with AWS Lambda's on-demand model. To enable execution, use Mangum, a bridge between HTTP API Gateway and Django via ASGI. This layer adapts request cycles to the Lambda model.
-
Latency and Connection Optimization:
Lambda functions execute on-demand, causing two common delays: cold start and DB connection setup.- Cold start (2–5 seconds) happens when an instance is invoked for the first time. It’s usually negligible in apps with moderate traffic.
- DB connections can add 300–800 ms per request if each Lambda opens a new TCP session, quickly hitting MySQL's ~1000 connection limit.
- Use RDS Proxy to maintain a pool of persistent connections, reducing average latency to ~50 ms, stabilizing access, and allowing seamless scaling.
This Lambda + RDS Proxy combo ensures elastic scalability, low maintenance, and usage-based pricing.
3.3 Domain and HTTPS
Register and manage the domain via Amazon Route 53 for seamless integration with AWS Certificate Manager (ACM) and Elastic Beanstalk.
SSL Configuration: ACM issues certificates for both the main domain (e.g.,
vahltech.com
) andwww
subdomain, with automatic DNS validation through Route 53. The certificate attaches to Elastic Beanstalk's Application Load Balancer (ALB). The HTTPS listener (port 443) handles secure traffic, and the HTTP listener (port 80) is configured to redirect all traffic to HTTPS (port 443), ensuring secure connections.Domain Consistency: Route 53 configures an A record (alias) for the main domain and a CNAME for the
www
subdomain, both pointing to the same ALB endpoint. This console-based setup eliminates application-level configuration while ensuring consistent access and end-to-end encryption.
4. Layered Security
The architecture adopts a defense-in-depth approach, where each component runs with minimal privileges inside an isolated network.
Network Isolation: All backend data flows occur within a private VPC. Lambda and RDS live in private subnets, protected by restrictive security groups. Traffic between them flows through RDS Proxy, avoiding direct DB connections and minimizing exposure.
Credential Management: Passwords and access keys are stored in AWS Secrets Manager and Parameter Store, never in source code. Secret access permissions follow the least privilege principle, granted only to roles that need them.
User Authentication: The REST API uses server-managed JWTs stored in secure session cookies. The browser only receives the cookie; the JWT itself is never exposed to JavaScript or transmitted via client-side logic — reducing attack surface and preventing leaks.
Secure Admin Access: During development and testing, an EC2 instance with OpenVPN can be deployed inside the same VPC as a bastion host. This entry point allows validation of Lambda, RDS Proxy, and other components without exposing public endpoints.
Note: Choosing a self-managed OpenVPN over AWS Client VPN helps keep the budget under control. This option, however, requires familiarity with OpenVPN (DNS, routing, iptables). A preconfigured AMI from the AWS catalog can simplify setup.
5. API Documentation
To ensure high-quality documentation and alignment between development and operations, API documentation should be automatically generated.
Use DRF Spectacular to expose a clean, standards-compliant OpenAPI 3.0 schema, with an interactive interface available at /api/docs/
.
This approach reduces dependency on manual documentation, simplifies integration with external clients, and encourages consistency across environments.
6. AWS Cloud Development Kit (CDK) – Infrastructure as Code (IaC)
AWS CDK offers a more programmable approach than CloudFormation and is more AWS-integrated than Terraform. It allows reuse of real programming logic (loops, functions, classes) instead of YAML — ideal for developers familiar with Python.
While CDK doesn’t package applications by default, using the PythonFunction
class automates build and Docker packaging, avoiding extra tooling.
Even in small projects, CDK adds predictability, version control, and environment reproducibility — critical if the app grows or requires future migration.
This replaces older tools like Zappa, which lacks support for HTTP API Gateway (v2) and relies on the outdated REST model (v1), leading to issues with header passing and JWT-based auth.
Permissions follow least privilege, and stack outputs allow integration without tight coupling. This shift from manual to declarative brings reproducibility, security, and a single source of truth for the AWS environment.
7. Monitoring and Observability
Observability is kept at an essential level to maintain operational stability.
- Elastic Beanstalk performs health checks via the ALB
- API Gateway logs requests and errors to CloudWatch Logs
These tools help detect integration errors and availability issues quickly.
For better insights, consider upgrading to distributed tracing with **AWS X-Ray* and building performance dashboards in CloudWatch*.
8. Architectural Advantages
A less obvious benefit of the hybrid architecture is the elimination of CORS issues.
In SPAs, browser JavaScript makes cross-origin API requests, which introduces complexity and security risks. In this setup, the browser only talks to the frontend (vahltech.com
on Elastic Beanstalk), and Django performs internal server-to-server API calls via Python's requests
.
From the browser's perspective, all communication happens within the same domain, eliminating CORS configuration, preflight requests, and related vulnerabilities.
JWT tokens are also completely hidden from the client:
They travel only between the Django frontend and the backend API, stored in encrypted HttpOnly
session cookies — unreadable and inaccessible via JavaScript.
The result is a simpler, safer architecture with fewer failure points.
9. Cost Breakdown
Assumptions:
~1,000 API requests/day → ~30,000/month
~10,000 frontend page views/month
1 GB in DB storage, <1 GB static files
Service | Description | Est. Monthly Cost (USD) |
---|---|---|
RDS Proxy | DB connection pool | ~$14.88 |
Amazon RDS (t4g.micro) | Instance + 20 GB storage¹ | ~$11.50 |
Elastic Beanstalk (EC2) | Django frontend under light load | ~$10.00 |
Application Load Balancer | ALB for HTTPS frontend access | ~$5.00 |
API Gateway | ~30,000 HTTP requests | ~$1.50 |
Lambda | ~30,000 invocations (~60s compute) | ~$0.25 |
Route 53 | Domain + DNS | ~$0.50 |
Secrets Manager | 1 secret (DB credentials) | ~$0.40 |
S3 | Static assets (~1 GB, few requests) | ~$0.10 |
CloudWatch | Logs from Lambda and ALB | ~$0.50 |
Total Estimated (Light Use): ~$44–45/month
¹ RDS pricing reference: db.t4g.micro in us-east-1 is ~$0.016/hr → ~$11.50/mo
Source: instances.vantage.sh
Note: During development, an EC2 OpenVPN bastion + Elastic IP was used, increasing costs. In production, this is not required and was excluded.
10. Conclusion and Next Steps
This architecture proves that it's possible to build secure, scalable, and budget-friendly AWS applications, even in low-budget scenarios.
With an average cost of ~$45/month, the model balances automation, network isolation, and built-in security — offering a solid foundation for small to mid-sized systems.
Recommended next steps:
- Enhance observability with distributed tracing via AWS X-Ray
- Create performance dashboards in CloudWatch
- Automate the deployment pipeline using CDK Pipelines
- For data scaling, consider read replicas and sharding in Amazon RDS
This combination of practices consolidates a modern, sustainable, and scalable architecture — one that can serve as a real-world reference for low-cost, high-control cloud migrations.
Everything described here isn’t just theoretical — it’s implemented, deployed, and version-controlled. You can explore the full source code in this open-source repository: github.com/Val-Cantarelli/Meta-AWS-Capstone
Top comments (0)