Tools: Latest: 🐍 How to deploy Django AWS Elastic Beanstalk RDS — the smart way

Tools: Latest: 🐍 How to deploy Django AWS Elastic Beanstalk RDS — the smart way

🐍 Django Setup — Local First, Cloud Later

📦 Requirements & WSGI — The Invisible Glue

🛠️ Static Files — Don’t Let CSS Break Your App

☁️ AWS Elastic Beanstalk — Where Your App Lives

⚙️ Environment Variables — Keep Secrets Safe

🏗️ .ebextensions — Customize Your Instance

🗄️ RDS — The Real Database

🔐 Security Groups — Don’t Block Yourself

🚀 Deploy — And Then Breathe

🟩 Final Thoughts

❓ Frequently Asked Questions

Can I use MySQL instead of PostgreSQL with RDS on Elastic Beanstalk?

How do I run Django management commands after deployment?

Is Elastic Beanstalk free with RDS? "You don't need to be a DevOps wizard to ship Django to AWS — just someone who doesn’t mind breaking things once or twice before chai break." 🫖 Yeah, I learned this the hard way. I remember the time I proudly told my manager, “Site’s live!” — only to realize 10 minutes later that none of the migrations had run. User registration failed silently. The logs? Buried under 300 lines of Apache garbage. And the worst part? My junior had already shared the link with the client on WhatsApp. Spoiler: I didn’t sleep that night. Coffee. Cursing. And one panicked call to a friend who actually knew what container_commands were. Look — you don’t need Kubernetes. You don’t need to memorize IAM policies like poetry. But if you’re trying to deploy Django on AWS Elastic Beanstalk with RDS , and you want it to actually work , then let me save you from my 2 AM meltdowns. Because honestly?

It’s not about knowing everything.It’s about knowing what breaks — and how to fix it before standup. And that’s why this guide exists. Not just commands. Not just copy-paste. But the why. The gotchas. The “** wait, why is the CSS 404?** ” moments. So let’s walk through it. Step by step. Like I’m pairing with you over a late Sunday chai. Here’s the thing — if it doesn’t work on your laptop, it won’t work on AWS.I don’t care how many eb deploy commands you smash. First: clean environment. No global packages. No lingering pip install django from 2020. Wait — why psycopg2-binary?Because RDS loves PostgreSQL. And PostgreSQL hates SQLite drivers. Now, the big one: settings. So many juniors I’ve mentored — and yeah, me once — just edited settings.py directly. Hardcoded DEBUG = False, slapped in a DB URL, pushed to GitHub.And then wondered why the app crashed with a SECRET_KEY leak on a public repo. Use django-environ. Seriously. Create .env in your root — same level as manage.py: Boom.Local uses SQLite.Production reads RDS vars.And you never commit secrets. (And yes — add .env to .gitignore. Like this one — because I’ve seen it happen. Twice.) You think requirements.txt is just formality? I had a project — team of five — where the deploy failed because one guy ran pip freeze on Windows.Blew up the whole CI with pywin32==227 in requirements. So generate it clean: Double-check: no OS-specific packages. No **pycache**. No comments. And wsgi.py?It needs to be in your project folder. Like, the same folder as settings.py. Not inside an app. Beanstalk looks for it.If it’s missing — 502 Gateway Timeout.No logs. No mercy. You deploy. UI looks broken. Fonts missing. Buttons misaligned. But the Django admin? Perfect. Turns out — static files weren’t collected. In production, Django doesn’t serve static files. Apache does. And it looks in staticfiles/. And in urls.py — only serve static locally: Simple. But skip it — and your landing page looks like 2003. Alright. Time to go cloud. First — install the EB CLI: And when it asks: “Platform,” pick Python — not Docker. Not “Other.”You’re not trying to overcomplicate things. Not today. Hardcoding SECRET_KEY in settings.py? Please don’t.I’ve seen apps get scraped in under 2 hours. Use environment variables. These show up in os.environ. And django-environ already reads them. Easy. Secure. No leaks. This is the magic folder. Create .ebextensions at your project root. Now drop in .ebextensions/django.config: Without this?Manual ssh.Manual migrate.Manual swearing. Here’s the truth — yes, you can use SQLite on Elastic Beanstalk. But.It gets wiped on every deploy. So if your client adds 200 users today — and you push a typo fix tomorrow — poof. Data gone. In the EB console:Environment → Configuration → Database → Modify. AWS spins up RDS, hooks it to your VPC, and injects env vars:RDS_HOSTNAME, RDS_DB_NAME, etc. And because you used env.db() in settings? It just works. Maps the vars. Connects securely. No extra code. No custom logic. I once spent 90 minutes debugging “database timeout” — only to realize the RDS security group blocked the EC2 instance. By default, RDS isn’t public. Good. But it must allow inbound from your EB security group on port 5432 (PostgreSQL) or 3306 (MySQL). If your app hangs on /admin, this is probably why. And yes — it’s usually fixed in 2 clicks.But finding it? That’s the pain. Waits 5-10 minutes.It’s creating EC2, RDS, load balancer, security groups — the whole circus. See the logs stream. Watch migrate run. collectstatic complete. And boom — your Django app, live.With RDS.With static files.With zero downtime (okay, maybe 30 seconds). You just deploy Django AWS Elastic Beanstalk RDS — no PhD required. "A successful deployment isn’t one that works the first time — it’s one you understand when it breaks." 🔧 And yeah — custom domains, SSL, background tasks with Celery?All coming. I once deployed a startup MVP, forgot collectstatic, and showed the CEO a white page with “Server Error (500)” in Comic Sans.Team screenshot it. Still haunts me. You?You’re already ahead. Let’s be real.You don’t need Docker.You don’t need Helm charts. For most Django apps — a blog, a CRM, an internal tool — Elastic Beanstalk is enough. It gives you automation.It handles scaling.It integrates with RDS, S3, and CloudWatch. And if it breaks?You understand why. Not just that your app is online.But that you know the flow:From manage.py runserver to eb deploy.From local SQLite to RDS.From hardcoded secrets to env vars. These concepts? They transfer. To Heroku.To EC2.To your next side hustle. And next time someone says “deploy this Django app” —You won’t panic. You’ll just do it.Maybe even before lunch.

With chai on the side. Yes, absolutely. During environment setup or in .ebextensions, choose MySQL as the RDS engine. Just make sure you have mysqlclient in your requirements.txt and adjust your local testing accordingly. Use the EB CLI: eb ssh to log into the instance, activate the virtual environment, then run commands. Example: python manage.py createsuperuser. Or automate them in container_commands inside .ebextensions. Not entirely. AWS Free Tier includes 750 hours/month of a single t3.micro instance and 750 hours of a db.t3.micro DB instance for 12 months. Beyond that, you pay for EC2, RDS, and data transfer. Always monitor your usage. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ python -m venv venv source venv/bin/activate # Linux/Mac # or venvScriptsactivate on Windows python -m venv venv source venv/bin/activate # Linux/Mac # or venvScriptsactivate on Windows python -m venv venv source venv/bin/activate # Linux/Mac # or venvScriptsactivate on Windows -weight: 500;">pip -weight: 500;">install django boto3 django-environ psycopg2-binary -weight: 500;">pip -weight: 500;">install django boto3 django-environ psycopg2-binary -weight: 500;">pip -weight: 500;">install django boto3 django-environ psycopg2-binary # .env DEBUG=False ALLOWED_HOSTS=.elasticbeanstalk.com,127.0.0.1 DATABASE_URL=sqlite:///db.sqlite3 # fallback for local SECRET_KEY=your-super-secret-dev-key # .env DEBUG=False ALLOWED_HOSTS=.elasticbeanstalk.com,127.0.0.1 DATABASE_URL=sqlite:///db.sqlite3 # fallback for local SECRET_KEY=your-super-secret-dev-key # .env DEBUG=False ALLOWED_HOSTS=.elasticbeanstalk.com,127.0.0.1 DATABASE_URL=sqlite:///db.sqlite3 # fallback for local SECRET_KEY=your-super-secret-dev-key # settings.py import environ import os env = environ.Env() environ.Env.read_env() DEBUG = env('DEBUG', default=False) ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['127.0.0.1']) SECRET_KEY = env('SECRET_KEY') # Use DATABASE_URL from environment or fallback DATABASES = { 'default': env.db(default='sqlite:///db.sqlite3') } # settings.py import environ import os env = environ.Env() environ.Env.read_env() DEBUG = env('DEBUG', default=False) ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['127.0.0.1']) SECRET_KEY = env('SECRET_KEY') # Use DATABASE_URL from environment or fallback DATABASES = { 'default': env.db(default='sqlite:///db.sqlite3') } # settings.py import environ import os env = environ.Env() environ.Env.read_env() DEBUG = env('DEBUG', default=False) ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['127.0.0.1']) SECRET_KEY = env('SECRET_KEY') # Use DATABASE_URL from environment or fallback DATABASES = { 'default': env.db(default='sqlite:///db.sqlite3') } -weight: 500;">pip freeze > requirements.txt -weight: 500;">pip freeze > requirements.txt -weight: 500;">pip freeze > requirements.txt STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # your URL patterns ] if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # your URL patterns ] if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # your URL patterns ] if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) -weight: 500;">pip -weight: 500;">install awsebcli -weight: 500;">pip -weight: 500;">install awsebcli -weight: 500;">pip -weight: 500;">install awsebcli eb setenv DEBUG=False SECRET_KEY='your-real-secret' ALLOWED_HOSTS=.elasticbeanstalk.com eb setenv DEBUG=False SECRET_KEY='your-real-secret' ALLOWED_HOSTS=.elasticbeanstalk.com eb setenv DEBUG=False SECRET_KEY='your-real-secret' ALLOWED_HOSTS=.elasticbeanstalk.com option_settings: aws:elasticbeanstalk:application:environment: DJANGO_SETTINGS_MODULE: myproject.settings aws:elasticbeanstalk:container:python: WSGIPath: myproject/wsgi.py aws:elasticbeanstalk:command: timeout: 600 container_commands: 01_migrate: command: "source /var/app/venv/*/bin/activate && python manage.py migrate" leader_only: true 02_collectstatic: command: "source /var/app/venv/*/bin/activate && python manage.py collectstatic --noinput" option_settings: aws:elasticbeanstalk:application:environment: DJANGO_SETTINGS_MODULE: myproject.settings aws:elasticbeanstalk:container:python: WSGIPath: myproject/wsgi.py aws:elasticbeanstalk:command: timeout: 600 container_commands: 01_migrate: command: "source /var/app/venv/*/bin/activate && python manage.py migrate" leader_only: true 02_collectstatic: command: "source /var/app/venv/*/bin/activate && python manage.py collectstatic --noinput" option_settings: aws:elasticbeanstalk:application:environment: DJANGO_SETTINGS_MODULE: myproject.settings aws:elasticbeanstalk:container:python: WSGIPath: myproject/wsgi.py aws:elasticbeanstalk:command: timeout: 600 container_commands: 01_migrate: command: "source /var/app/venv/*/bin/activate && python manage.py migrate" leader_only: true 02_collectstatic: command: "source /var/app/venv/*/bin/activate && python manage.py collectstatic --noinput" DATABASES = { 'default': env.db() } DATABASES = { 'default': env.db() } DATABASES = { 'default': env.db() } eb create my-django-env --database.engine postgres --database.size 5 --sample eb create my-django-env --database.engine postgres --database.size 5 --sample eb create my-django-env --database.engine postgres --database.size 5 --sample - Region? Pick one close to users. Mumbai if you’re in India. - App name? Make it clean. my-django-app, not final_final_v2. - Python version? 3.9 or higher. Trust me, I’ve seen 3.6 fail on zoneinfo. - Migrations (only on leader instance — critical in multi-server setups) - Collectstatic (so your CSS actually loads) - Sets WSGI path (so Apache knows where to look) - Engine: PostgreSQL (my pick) or MySQL - Instance: db.t3.micro — free tier - Username: admin - Password: store it in SECRET_ENV, not a sticky note - DB name: ebdb (default is fine) - requirements.txt (missing package?) - .ebextensions (YAML hates tabs — use spaces) - Migrations (did one fail silently?) - ALLOWED_HOSTS (did you forget .elasticbeanstalk.com?)