A Python web application needs more than python app.py to run in production: something to serve it reliably, something to restart it when it crashes, and a web server in front to handle HTTPS. This guide walks through deploying a Flask, Django or FastAPI application on a Domain India VPS, from a fresh server to a live site with SSL, and shows how to keep it updated afterwards.
On a VPS, run your Python app inside a virtual environment, serve it with Gunicorn (with Uvicorn workers for async frameworks such as FastAPI), keep it running with a systemd service, and put nginx in front with a free Let's Encrypt certificate. A Domain India VPS is self-managed: you get root access and install, secure and update the software yourself. For a small app you would rather not administer, Python on shared hosting or the App Platform may fit better.
1. First, pick the right place to run it
A VPS is the most flexible option, but not the only one. Choose by how much server work you want to do.
| Option | Good for | What you manage |
|---|---|---|
| Shared hosting (cPanel or DirectAdmin) | Small Flask or Django sites, low traffic | Only your app; the panel's Python tool runs it |
| App Platform | Apps you can package in a Dockerfile | Your code and Dockerfile; we run the servers |
| VPS | Any stack, background workers, custom services | Everything: OS, security, updates, backups |
On shared hosting, Python apps run through the panel's Setup Python App tool; see deploying a Python app on shared hosting. On the App Platform, only Node.js is detected automatically, so a Python app deploys from your own Dockerfile; see getting started with the App Platform. The rest of this guide covers the VPS route.
2. Get the application ready for production
Before you touch the server, make the app deployable:
- Pin your dependencies. Keep a
requirements.txt(or a lock file from your tool of choice) with exact versions, so the server installs what you tested. - Move settings into environment variables. Database passwords, secret keys and API tokens belong in an environment file on the server, never in your Git repository.
- Turn off debug mode. Set
DEBUG = Falsein Django and never run Flask's debugger in production. Debug pages leak code and settings. - Know your entry point. Flask usually exposes
appin a module such aswsgi.py; Django hasproject/wsgi.py; FastAPI exposes an ASGIapp. - Add a health check. A simple
/healthroute that returns 200 makes monitoring easy.
3. Prepare the VPS
Start with a current long-term-support release. Ubuntu 24.04 LTS ships Python 3.12; AlmaLinux and Rocky Linux 9 ship an older default Python, with newer versions available as separate packages. Use SSH keys to log in; see how to access your VPS using SSH.
On Ubuntu 24.04:
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-venv python3-pip nginx git
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableOn AlmaLinux or Rocky Linux 9:
sudo dnf update -y
sudo dnf install -y python3.12 python3.12-pip nginx git
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
sudo setsebool -P httpd_can_network_connect 1 # let nginx proxy to your app under SELinuxCreate a dedicated user and folder for the app, so it never runs as root:
sudo useradd --system --create-home --shell /bin/bash myapp
sudo mkdir -p /srv/myapp
sudo chown myapp:myapp /srv/myappFor the wider hardening checklist, see essential security and optimisation tips for your VPS.
4. Copy the code and install dependencies
Git is the cleanest way to get code onto the server, because updates become a git pull. Use a read-only deploy key for a private repository.
sudo -iu myapp
cd /srv/myapp
git clone https://github.com/you/yourapp.git app
cd app
python3 -m venv .venv # use python3.12 on AlmaLinux/Rocky
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt gunicornFor an async framework such as FastAPI, also install uvicorn. Create /srv/myapp/app/.env with your settings and make it readable only by the app user (chmod 600 .env). If you use Django, run python manage.py migrate and python manage.py collectstatic now.
Test the app before going further:
gunicorn --bind 127.0.0.1:8000 wsgi:appReplace wsgi:app with your module and object, for example myproject.wsgi:application for Django. For FastAPI, add -k uvicorn.workers.UvicornWorker and point it at your ASGI app. Press Ctrl+C once it answers on curl http://127.0.0.1:8000/health.
5. Keep it running with systemd
systemd starts the app at boot and restarts it if it crashes. Create /etc/systemd/system/myapp.service as root:
[Unit]
Description=My Python app
After=network.target
[Service]
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp/app
EnvironmentFile=/srv/myapp/app/.env
ExecStart=/srv/myapp/app/.venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 wsgi:app
Restart=on-failure
[Install]
WantedBy=multi-user.targetThen enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myappA common starting point is two to four workers per CPU core; watch memory use and adjust. Background jobs (Celery, RQ or a scheduler) get their own service files in the same way.
6. Put nginx in front and add HTTPS
nginx receives visitors on ports 80 and 443, serves static files directly and passes everything else to Gunicorn. Create a site file (on Ubuntu in /etc/nginx/sites-available/myapp, then link it into sites-enabled; on AlmaLinux or Rocky in /etc/nginx/conf.d/myapp.conf):
server {
listen 80;
server_name example.com www.example.com;
location /static/ {
alias /srv/myapp/app/static/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Test and reload with sudo nginx -t && sudo systemctl reload nginx. Point your domain's A record at the VPS IP address, wait for DNS to update, then get a free certificate:
sudo apt install -y certbot python3-certbot-nginx # Ubuntu
sudo certbot --nginx -d example.com -d www.example.comOn AlmaLinux or Rocky, install certbot and python3-certbot-nginx from the EPEL repository. Certbot sets up automatic renewal.
Gunicorn should listen on 127.0.0.1 only, and your firewall should allow just SSH, HTTP and HTTPS. If you bind Gunicorn to 0.0.0.0 and open port 8000, visitors can bypass nginx and HTTPS entirely.
7. Update, monitor and back up
- Deploy updates.As the app user:
git pull,source .venv/bin/activate,pip install -r requirements.txt, run migrations, thensudo systemctl restart myapp. - Read the logs.
journalctl -u myapp -fshows the app's output; nginx logs are in/var/log/nginx/. - Patch the server.Install security updates regularly, or turn on automatic security updates (
unattended-upgradeson Ubuntu,dnf-automaticon AlmaLinux and Rocky). - Watch it from outside.An external uptime check on your
/healthURL tells you when the site is down before your customers do. - Back up off the server.Dump the database and copy it, with uploaded files, to storage outside the VPS. Test a restore now and then.
For a complete FastAPI example with PostgreSQL and zero-downtime reloads, see FastAPI production deployment. For Django-specific settings, see the Django production deployment checklist.
8. Where Domain India fits
A Domain India VPS gives you root access on KVM virtualisation, and it is self-managed: you install and look after the software yourself. cPanel is not offered on our VPS plans. For start, stop, force restart, reinstall or console access, open a ticket and support will do it; you can reboot a healthy server yourself over SSH. See managing your VPS.
- 1 vCPU
- 2 GB DDR4 RAM
- 64 GB NVMe SSD Storage
- 2 TB Monthly Bandwidth
- 2 vCPU
- 4 GB DDR4 RAM
- 128 GB NVMe SSD Storage
- 3 TB Monthly Bandwidth
The cards show live Domain India list prices, excluding 18% GST. A small Flask or FastAPI API runs comfortably on an entry plan; add memory if you run background workers, a database and the app on the same server.
Frequently asked questions
Should I use Gunicorn or Uvicorn?
Use Gunicorn for WSGI frameworks such as Flask and Django. For ASGI frameworks such as FastAPI, run Gunicorn with Uvicorn workers (-k uvicorn.workers.UvicornWorker), or Uvicorn on its own with several workers. Either way, keep it behind nginx.
Why use a virtual environment on a server?
A virtual environment keeps your app's packages separate from the operating system's Python, so an OS update can't break your app and your pip installs can't break OS tools.
Can I run the Django or Flask development server in production?
No. The built-in development servers are single-process, unhardened and not designed for real traffic. Use Gunicorn or Uvicorn behind nginx.
Does Domain India install or manage Python on my VPS?
No. A Domain India VPS is self-managed. You have root access and install, configure, secure and update the software yourself.
Can I run a Python app without a VPS?
Yes. Small apps can run on cPanel or DirectAdmin shared hosting through the panel's Python app tool, or on the App Platform from a Dockerfile. A VPS is best when you need background workers, custom services or full control.
How do I restart my app after changing the code?
Pull the new code, install any new requirements in the virtual environment, run migrations if needed, then run sudo systemctl restart followed by your service name.
Ready to deploy? Compare VPS plans, try the App Platform for a container-based app, or open a support ticket if you are not sure which fits your project.
Root access on KVM virtualisation, with the stack you choose.
See VPS plans