Learn by Doing: EC2 Deployment
6/24/2026 · 5 min read
Introduction
Though my professional engineering work has been primarily been in frontend development, my title has always been "Fullstack Engineer". This means something different in each organization, and without going on a diatribe about what it really means to be a fullstack engineer, my backend experience has been comprised of writing SQL queries/views, API endpoints, and compute or database services.
This has been a valuable series of experiences, but during my contract with the Commonwealth I took it upon myself to dive into more backend development to give my title of "Fullstack Engineer" some more credibility.
Enter: EC2
I have deployed API servers to Heroku in the past, but I sought a new challenge that would also lend me the experience that so many organizations need in their production development. I opted to deploy to an AWS EC2 instance for this specific purpose. I'll do my best to keep my gripes with AWS to a minimum as I am more than likely preaching to the choir.
Spinning up an Instance
Setting up the instance under the free tier was rather straight forward. Following the instructions, I chose the free compute tier (t3.micro) on Amazon Linux with the rest of the settings left as default.
I fumbled the SSH command for a few minutes thinking that the path to the .pem file needed to be wrapped in a string, but after I discovered that wasn't the case, we were golden.
Setting up the Environment
I had confirmed that my FastAPI server was fully functional via Insomnia before installing dependencies in my EC2 instance. Getting it to work in the EC2 was not the issue, surprisingly. What I wish I paid attention to was that the server needs to be installed in a folder /var/www/<here> and not in /home/ec2-user/~ where you initially SSH into. Lesson learned.
Side note: Why does AWS instruct developers to use
sudoas opposed to managing Linux user permissions? I would think that granting permissions toec2-useror whichever default user would make more sense as abusingsudohas a notable code smell (terminal smell?).
CI/CD and the Github Runner
My biggest headache with this process was related to folder permissions. I knew Git folders had authorship and that all folders in Linux had user and group ownership with their own permissions. What I failed to consider, however, was that the Linux user that I created for my Github runner needed permission to /var/www/<this_folder> as mentioned earlier. I'm slightly embarrassed to say this, but I managed to have the contents of this folder owned by 3 different users:
ec2-user: From when I set up the environmentroot: Due to running commands withsudorunner: From commands being ran in the pipeline as that user
Needless to say, I learned a valuable lesson regarding folder ownership and user permissions.
Fix: I granted ownership of
/var/www/server/to a shared group comprised ofec2-userandrunner. This prevented future overwriting of ownership and permission errors in the pipeline.
Full Steam Ahead
After automating the client and server pipelines on new code pushes, I pushed empty commits and saw both applications working in sync! In all, this process granted me some critical skills in Python development, deployment, and building pipelines. I look forward to using these skills in my next day job and side project work.
Feel free to check out the repo in question here: https://github.com/ploymahloy/voice-translate