Deploying Pravah on AWS: Amplify, EC2, and Lessons from Debugging HTTPS and CORS
How I took a waterlogging and rainwater-harvesting web app from localhost to AWS using Amplify and EC2, and the real deployment problems I hit with build configuration, mixed content, and CORS.
Why I built Pravah
Cities like Gurugram face two opposite water problems at once. Heavy rain floods roads and residential areas, while valuable rainwater runs off and is wasted instead of being harvested.
I built Pravah, a water-management platform that helps residential societies understand local waterlogging risk and estimate the potential water and cost savings of rainwater harvesting. It combines rainfall data, elevation information, and reported waterlogging incidents.
This article isn't about the app's features. It's about what happened when I moved Pravah from my laptop to AWS, the problems I ran into, and how AWS services and debugging on AWS helped me solve them.
Architecture at a glance
- Frontend: React + Tailwind CSS, hosted on AWS Amplify
- Backend: Node.js + Express.js, running on Amazon EC2 (Ubuntu)
- Process management and routing: PM2 and Nginx (reverse proxy) on the EC2 instance
- Data: external APIs for rainfall and elevation, with no database
User → Amplify (HTTPS frontend) → API requests → EC2 (Nginx → Express app) → external data sources
Problem 1: Getting the frontend built correctly on Amplify
The problem: My GitHub repository keeps the frontend and backend in separate directories. When I first connected it to AWS Amplify, the build didn't behave as I expected because Amplify needed to know which directory was the actual application root.
How I solved it: I configured the app root directory and build settings so Amplify built only the frontend folder.
How AWS helped: Amplify connects directly to GitHub, builds on every push, and shows build logs for each stage (provision, build, deploy). Those logs made it easy to see exactly where the build went wrong.
Lesson: A deployment depends as much on repository structure and build configuration as on the code itself.
Problem 2: Running the backend reliably on EC2
The problem: My Express backend worked with
npm start locally, but a production server needs the app to survive disconnected SSH sessions, crashes, and reboots, and to be reachable on a standard port.How I solved it:
- Launched an Ubuntu EC2 instance and installed Node.js and dependencies.
- Ran the app with PM2 so it restarts automatically and keeps running in the background.
- Configured Nginx as a reverse proxy to forward incoming requests to the Express app.
- Used PM2 and Nginx logs to debug issues.
How AWS helped: EC2 gave me a full Linux server and full control over the environment. Compared with a fully managed platform, it was more work, but it taught me how process managers, reverse proxies, ports, and security groups fit together.
Lesson: Managed services save time, but configuring EC2 myself taught me what those services do under the hood.
Problem 3: The HTTPS "mixed content" error
The problem: After deployment, Pravah worked locally but couldn't load any data online. Amplify serves the frontend over HTTPS, but my backend was reachable only through the EC2 public IP over HTTP. Browsers block a secure page from calling an insecure API, so every request was blocked.
How I solved it (for now): To keep testing without buying a domain right away, I used ngrok to expose the backend through an HTTPS URL. That was a temporary development workaround, not a production architecture.
What I learned: Frontend-to-backend connectivity isn't just about an endpoint being reachable. Browser security rules matter. For a permanent fix, the right approach on AWS is to give the backend a proper HTTPS endpoint, for example a custom domain with an AWS Certificate Manager (ACM) certificate behind Amazon CloudFront or an Application Load Balancer. That's on my roadmap.
Problem 4: CORS and "is it the tunnel, the proxy, or the app?"
The problem: Once HTTPS worked, I hit CORS errors. The frontend (Amplify domain) and backend (a different origin) required the backend to send the correct CORS headers. On top of that, ngrok's free tier shows a browser warning page that can interfere with API calls.
How I solved it: Instead of changing everything at once, I tested one layer at a time:
- The app: called the health endpoint directly with
curlon the server
- The reverse proxy: confirmed Nginx forwarded requests correctly
- The tunnel: checked that the HTTPS URL was online and reachable
- The headers: inspected response headers with
curl -ito confirm CORS headers were present
- The frontend: only then tested the deployed Amplify app in the browser
Lesson: In a browser console, an offline tunnel, a wrong route, missing CORS headers, and an HTTPS problem can all look like the same error. Isolating layers turns a confusing bug into a checklist.
How AWS helped this project
AWS service | Role in Pravah | What it taught me |
|---|---|---|
AWS Amplify | Hosts the React frontend, builds from GitHub on every push | CI/CD, build config, monorepo structure |
Amazon EC2 | Runs the Node.js/Express backend | Linux server setup, PM2, Nginx, security groups |
Amazon CloudWatch (next step) | Planned for centralized logs, metrics, and alarms | Observability beyond SSH and pm2 logs |
As a student developer, I also kept cost in mind. I chose a small setup I could understand, configure, and troubleshoot myself, and I monitor usage so there are no surprises.
What I learned
- Deployment is part of development. A feature isn't done until it works in the deployed environment.
- Security shapes architecture. HTTPS, CORS, and mixed-content rules directly affect how frontend and backend connect.
- Isolate to debug. Testing each layer independently was faster than guessing.
- Cost awareness matters. Even small projects benefit from choosing and monitoring resources carefully.
What's next
- Replace the ngrok workaround with a permanent HTTPS setup using a custom domain, ACM, and CloudFront or an Application Load Balancer
- Add Amazon CloudWatch for logs, metrics, and alarms on the backend
- Explore more AWS-native deployment options as Pravah grows
- Improve the accuracy of the water-savings estimates and expand waterlogging report coverage
Conclusion
Pravah began as an attempt to use technology on two connected urban problems: waterlogging and rainwater conservation. AWS let me take it beyond my laptop, and the real value was in the problems I hit on the way: build configuration, process management, HTTPS, and CORS. Each one taught me another layer of how a real web application runs in the cloud.
If you're deploying your first full-stack app on AWS, my advice is to expect errors, test one layer at a time, and treat every failure as a lesson in how the system works.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article