AWS USD Top-up Deploy Python environment on AWS EC2
So you want to deploy a Python environment on AWS EC2. Congratulations: you’ve picked a task that sits at the intersection of “learning cloud basics” and “why is my terminal doing that?” In the best case, you’ll walk away with a clean, reproducible environment and the quiet satisfaction of having wrangled both AWS and Python. In the worst case, you’ll spend an hour fighting with a package that needs a compiler you didn’t install. Let’s try to prevent the worst case. Mostly.
1. What “Deploy Python environment” actually means
When people say “deploy a Python environment,” they often mean one (or more) of these:
- Create a server on EC2 that runs your Python code.
- Install Python (and sometimes system dependencies).
- Create a virtual environment so your packages don’t collide with each other or with system packages.
- Install your Python dependencies from a requirements file.
- Run an application (script, web service, worker, etc.) reliably.
- Make it repeatable so you can recreate the setup without starting from scratch every time.
This guide focuses on the practical “set up EC2 + Python + venv + dependencies + run your app” path, with options for automation.
2. Prerequisites and assumptions
Before you launch anything, make sure you have:
- An AWS account.
- A basic familiarity with the AWS Console (or at least willingness to click things confidently).
- A terminal where you can run commands locally.
- An SSH key pair for EC2 access.
- Your Python project files, typically including
requirements.txt(and maybepyproject.tomlif you’re using Poetry).
We’ll assume a typical scenario: you have a Python app you can run with something like python app.py or a framework command.
3. Choose an EC2 approach: simple manual vs. automated
You can configure Python on EC2 in two main ways:
- Manual: Launch instance, SSH in, install packages, set up venv, install dependencies. Fast to get started, but less repeatable.
- Automated: Use user data (cloud-init) to install everything at boot, or build a script you can run. More repeatable, and future-you will send you a thank-you note.
This article includes both. You’ll learn the manual steps first, then you’ll see how to automate them.
4. Pick the right EC2 instance and OS
4.1 Select a Linux distribution
The easiest route is usually an Ubuntu or Amazon Linux image. For most Python setups, you’ll find:
- Ubuntu: Friendly package management, widely documented.
- Amazon Linux: Tightly integrated with AWS, often a smooth default in AWS ecosystems.
Either works. The steps below are written in a way that works similarly for common Debian/Ubuntu-like systems.
4.2 Choose an instance type
For a small service or learning project, a t3.micro or t3.small instance often suffices. If you’re doing heavy ML workloads, compilation, or large builds, you’ll want more CPU and memory.
Also consider whether you need:
- Persistent storage (EBS) for logs, models, or uploads.
- Networking for pulling dependencies and accessing databases.
5. Launch EC2 instance
Let’s walk through a typical EC2 launch flow:
- Open the AWS Management Console.
- Go to EC2.
- Click Launch instances.
- AWS USD Top-up Pick an AMI (Amazon Machine Image). Choose a Linux distribution (Ubuntu or Amazon Linux recommended).
- Select an instance type (start small if appropriate).
- Configure security group settings (this is crucial).
- Choose storage size (default is often fine to start).
- Review and launch.
5.1 Security group: don’t open the world
Your EC2 security group is like your front door. If you leave it unlocked, random people (and bots) might wander in and ask uncomfortable questions.
At minimum:
- AWS USD Top-up SSH (port 22) should be allowed only from your IP address (or your office/VPN IP range).
- If you’ll run a web service, allow the required inbound port (commonly 80/443 or your app’s port like 8000).
For application security, prefer limiting source IPs rather than using 0.0.0.0/0 unless this is strictly a sandbox environment.
6. Connect to your EC2 instance via SSH
After the instance launches, you’ll need to connect to it. In the EC2 Console, find the instance and locate:
- AWS USD Top-up Public IPv4 address
- SSH username (depends on AMI; Ubuntu often uses
ubuntu, Amazon Linux often usesec2-user).
Then run something like:
ssh -i /path/to/your-key.pem ubuntu@YOUR_PUBLIC_IP
If SSH complains about permissions on your key file, fix it locally. A common fix is:
chmod 400 /path/to/your-key.pem
If you’re getting a “connection timed out,” it’s usually a security group rule or networking issue. If you’re getting “permission denied,” it’s usually username/key mismatch.
7. Install Python and build tools
Now we install Python. On many modern instances, Python 3 is available already. But we still need to check versions and install helper tools for packages that compile native extensions.
7.1 Update package lists
sudo apt-get update
If you’re on a distribution that uses a different package manager, use the appropriate equivalent.
7.2 Install Python 3 and pip
For Ubuntu/Debian-like systems:
sudo apt-get install -y python3 python3-pip python3-venv
This installs:
- python3 the interpreter
- python3-pip pip installer
- python3-venv support for virtual environments
AWS USD Top-up 7.3 Install build essentials (often required)
Many Python packages (like certain cryptography, numpy variants, or database adapters) may need compilers or system headers. Install a sensible default set:
sudo apt-get install -y build-essential libssl-dev libffi-dev
You might also need other libraries depending on your dependencies. The point is: install common ones up front so you’re not surprised later.
7.4 Verify Python version
python3 --version pip3 --version
Good sign: you have Python 3.x and pip working.
8. Create and activate a virtual environment (venv)
Now we keep your project dependencies tidy and isolated. That’s what virtual environments are for. Without a venv, you’re one pip install away from a dependency drama soap opera.
8.1 Choose a directory for your project
Let’s say your app will live under:
/home/ubuntu/myapp
Create and enter it:
mkdir -p ~/myapp cd ~/myapp
8.2 Copy your project files
How you transfer your code is up to you. Common options:
- Upload your files via SFTP or a file transfer tool.
- Clone a repository from Git.
If you use Git:
git clone YOUR_REPOSITORY_URL cd YOUR_REPO_NAME
Now you should have files like requirements.txt or your project structure.
8.3 Create the venv
python3 -m venv .venv
We use .venv as a convention. The dot prefix helps keep it tidy.
8.4 Activate the venv
source .venv/bin/activate
When activated, your terminal prompt often shows something like (.venv). That’s your cue: you’re now installing into the sandbox, not the system.
8.5 Upgrade pip tooling inside the venv
It’s usually a good idea to upgrade pip-related tools:
pip install --upgrade pip setuptools wheel
9. Install Python dependencies from requirements.txt
Now install what your project needs.
9.1 Install requirements
pip install -r requirements.txt
If your project uses Poetry, you might have pyproject.toml instead. For now, this guide assumes requirements.txt exists.
9.2 Common dependency issues (and how to handle them)
- Package compilation failures: You’ll see errors about missing compilers or headers. Install missing system packages (often
build-essential,libssl-dev, or database-specific libraries). - Version conflicts: Pin your dependencies in
requirements.txtso upgrades don’t break your environment. - AWS USD Top-up Python version mismatch: If your
requirements.txtexpects Python<3.11(for example), you may need to upgrade or change instance Python version. - AWS USD Top-up Slow installs: Use a wheel-friendly setup or consider caching dependencies. For small projects, this is usually fine.
A helpful trick: if the installation fails, don’t panic-install random packages. Read the error. It often tells you what system library is missing.
10. Store your environment configuration (optional but smart)
Most apps need environment variables for things like database URLs, API keys, or runtime settings. In a production-ish environment, you don’t want to hardcode secrets inside your repository.
There are multiple ways to manage environment variables:
- .env files (convenient for dev; be careful not to commit secrets)
- AWS Systems Manager Parameter Store or Secrets Manager (more “grown-up”)
- Export variables in your shell/session (fine for quick tests)
If you’re doing a quick test, you can export values temporarily:
export MY_API_KEY='...'
If you’re running a persistent service, use a method that survives reboots (like systemd with an EnvironmentFile, or an AWS secrets integration).
11. Run your Python app on EC2
Time for the moment of truth: does the app start without throwing exceptions that sound like a villain monologue?
11.1 Run it in the activated venv
Examples:
- Simple script:
python app.py - Flask:
flask run --host=0.0.0.0 --port=8000 - Django:
python manage.py runserver 0.0.0.0:8000
If your app uses a WSGI server like Gunicorn, you might run:
cd ~/myapp source .venv/bin/activate gunicorn app:app --bind 0.0.0.0:8000
For a real service, running directly with runserver is usually for development. Use Gunicorn/Uvicorn/etc. for production patterns.
11.2 Test connectivity
If your service runs on port 8000, verify from your local machine (assuming security groups allow it):
curl http://YOUR_PUBLIC_IP:8000/
If curl hangs or times out, it’s often a firewall/security group issue. If it returns an error, it’s probably your application.
12. Make it reliable: systemd service
Running the app manually is fine until you realize EC2 instance reboots can happen for updates or whatever cosmic event AWS feels like delivering. To avoid “it worked yesterday” energy, use systemd.
12.1 Create a systemd unit file
Let’s say your app entry point is app.py and you want to run it with Python. Create a file:
sudo nano /etc/systemd/system/myapp.service
Example content:
[Unit] Description=My Python App After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/myapp Environment=PATH=/home/ubuntu/myapp/.venv/bin ExecStart=/home/ubuntu/myapp/.venv/bin/python /home/ubuntu/myapp/app.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
Adjust paths and usernames to match your setup.
12.2 Enable and start the service
sudo systemctl daemon-reload sudo systemctl enable myapp.service sudo systemctl start myapp.service
12.3 Check logs
sudo systemctl status myapp.service sudo journalctl -u myapp.service -f
AWS USD Top-up If something breaks, logs will tell you why your app is refusing to behave. Usually it’s a missing environment variable, a wrong working directory, or a dependency error that never appeared when you manually ran the app (because your shell had variables set, for example).
13. Automate with user data (cloud-init)
Manual steps are useful while learning. But if you ever need to redeploy (and you will, because you are human and therefore will inevitably rebuild), automation is your best friend.
EC2 user data allows you to run a script at instance launch. You can install Python, create venv, install dependencies, and start the service.
13.1 The idea
You create a script that does the setup. Something like:
- Update packages
- Install Python 3 + venv + build tools
- Create project directory
- Clone repository (requires Git access)
- Create venv and install dependencies
- Set up and start systemd service
13.2 Example user data script
This is an illustrative example. You’ll adapt it to your project.
#!/bin/bash set -e sudo apt-get update sudo apt-get install -y python3 python3-pip python3-venv build-essential libssl-dev libffi-dev git # Variables (edit these) APP_DIR=/home/ubuntu/myapp REPO_URL=YOUR_REPOSITORY_URL # Ensure directory exists sudo -u ubuntu mkdir -p $APP_DIR # Clone repo if not present if [ ! -d "$APP_DIR/.git" ]; then sudo -u ubuntu git clone $REPO_URL $APP_DIR fi # Create venv and install deps sudo -u ubuntu bash -lc "cd $APP_DIR && python3 -m venv .venv" sudo -u ubuntu bash -lc "cd $APP_DIR && source .venv/bin/activate && pip install --upgrade pip setuptools wheel && pip install -r requirements.txt" # Create systemd service sudo bash -lc "cat > /etc/systemd/system/myapp.service <<'EOF' [Unit] Description=My Python App After=network.target [Service] Type=simple User=ubuntu WorkingDirectory=/home/ubuntu/myapp Environment=PATH=/home/ubuntu/myapp/.venv/bin ExecStart=/home/ubuntu/myapp/.venv/bin/python /home/ubuntu/myapp/app.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target EOF" sudo systemctl daemon-reload sudo systemctl enable myapp.service sudo systemctl restart myapp.service
Important notes:
- You must ensure
REPO_URLis accessible from the instance (public repo or proper credentials). - If your repo is private, you’ll need a secure method to fetch it (SSH deploy keys, HTTPS with credentials, or AWS CodeCommit + IAM policies).
- Secrets should not be pasted into user data in plain text if you can avoid it.
14. Troubleshooting checklist (a.k.a. the “why won’t it work?” survival kit)
When something fails, don’t guess blindly. Use this checklist in order:
14.1 Confirm the instance is reachable
- Can you SSH into it?
- Are your security group inbound rules correct?
14.2 Confirm Python and venv exist
python3 --version ls -la ~/.venv ls -la .venv/bin
If .venv doesn’t exist, your commands didn’t run in the expected directory.
14.3 Confirm dependencies installed
source .venv/bin/activate pip freeze | head
If pip freeze shows almost nothing, your pip install -r requirements.txt may have failed earlier.
14.4 Confirm your app runs from the correct working directory
Sometimes the app depends on relative file paths. That means your systemd unit needs a correct WorkingDirectory.
14.5 Check systemd logs
sudo journalctl -u myapp.service --no-pager -n 200
Logs will usually tell you exactly which import failed or which environment variable is missing.
14.6 Beware of “it works on my machine”
Your local environment might differ:
- Different Python version
- Different OS libraries available
- Different environment variables
If you want fewer surprises, pin your dependencies and specify compatible Python versions.
15. Recommended best practices (so you can sleep)
- Pin dependencies: Use a requirements file with explicit versions.
- Use a virtual environment: Never mix project packages into system Python.
- Use a process manager: systemd is a solid choice for basic services.
- Automate provisioning: user data or an infrastructure-as-code approach prevents configuration drift.
- Keep secrets out of code: use AWS services or environment variable injection mechanisms.
16. Optional upgrade paths: containers and managed services
If you find yourself doing more and more environment wrangling, consider:
- Docker: Package your Python dependencies and runtime in a container. Then EC2 just runs containers.
- AWS Elastic Beanstalk: For simpler app deployment patterns.
- ECS/Fargate: Container orchestration without managing servers.
But if your goal is specifically “deploy Python environment on EC2,” you’re already on track.
AWS USD Top-up 17. Mini example: a complete flow you can copy
Here’s a compact version of a typical manual workflow, all in one place:
- Launch EC2 instance with a Linux AMI.
- Configure security group: allow SSH from your IP.
- SSH in.
sudo apt-get updatesudo apt-get install -y python3 python3-pip python3-venv build-essential libssl-dev libffi-devcd ~/myapp(create it if needed)python3 -m venv .venvsource .venv/bin/activatepip install --upgrade pip setuptools wheelpip install -r requirements.txtpython app.py(or your framework command)- Set up systemd so it runs after reboot.
That’s the whole dance. The trick is repeating it without forgetting the steps that matter (like python3-venv).
18. Final thoughts
Deploying a Python environment on AWS EC2 is less like a single action and more like building a little ecosystem: you provide Python, you isolate dependencies, you install what your app needs, and then you make sure it keeps running. If you do it carefully with virtual environments and systemd, you’ll end up with a setup that’s not only functional today, but also survivable tomorrow.
If you want, tell me what your app is (Flask, Django, FastAPI, plain script, Celery worker, etc.) and whether you have requirements.txt or pyproject.toml, and I can tailor the exact commands and the systemd unit/service setup.

