Flask runs on localhost. You need it on the internet. Between those two states is a wall of configuration that has nothing to do with your application.
The traditional deploy path:
- Rent a VPS
- Install Python and set up a virtual environment
- Configure Gunicorn as a WSGI server
- Write an nginx reverse proxy config
- Set up SSL with certbot
- Create a systemd service
- Configure firewall rules
- Figure out how to get your code onto the server
That’s 45 minutes to 2 hours of setup. For an app that took 10 minutes to write with Claude Code.
The One-Command Way
instapods deploy my-flask-app --preset python
That’s it. Your Flask app is live at my-flask-app.nbg1-1.instapods.app with SSL.
What happened:
- Python 3.12 is pre-installed on the server
- Your code was uploaded
pip install -r requirements.txtran automatically- Your app started on the configured port
- Nginx is proxying with SSL
No Dockerfile. No Gunicorn config. No nginx config. No systemd service. No firewall rules. Same approach works for Node.js without Docker too.
What You Need in Your Project
Flask needs two things to deploy:
requirements.txt:
flask
gunicorn
app.py (or whatever your entry point is):
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello from Flask!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000)
InstaPods detects requirements.txt, installs dependencies, and starts your app. If you have a Procfile, it uses that. Otherwise it looks for app.py, main.py, or wsgi.py.
Flask + SQLite (It Works)
One of the biggest advantages of deploying to a real server: SQLite works. On serverless platforms (Vercel, Netlify Functions, Railway), SQLite either doesn’t work at all or loses data between invocations because the filesystem is ephemeral.
On a real server, SQLite persists to disk. Your database file stays between restarts, deployments, and reboots.
import sqlite3
def get_db():
db = sqlite3.connect('data.db')
db.row_factory = sqlite3.Row
return db
No external database service needed. No $7/mo Postgres addon. No connection strings. Just a file on disk.
Flask + Background Tasks
Need a background worker alongside your web server? On a real server, you can run your API and a background task on the same machine:
# Run your web server
# AND a background task in the same process or via a separate script
import threading
def background_worker():
while True:
# Process queue, send emails, etc.
time.sleep(60)
threading.Thread(target=background_worker, daemon=True).start()
Or install Celery, use APScheduler, or run a cron job. You have a full Linux environment with SSH access.
Debugging in Production
When something breaks in production, you need to see what’s happening. SSH in and check:
ssh instapod@my-flask-app.nbg1-1.instapods.app
# Check logs
tail -f /var/log/app.log
# Check what's running
ps aux | grep python
# Check memory
free -h
# Test an endpoint locally
curl http://localhost:3000/api/health
# Open a Python shell with your app context
python3 -c "from app import app; print(app.url_map)"
Try doing that on Vercel.
Comparison: Flask Deploy Options
| Method | Cost | Setup Time | SQLite | SSH | Background Tasks |
|---|---|---|---|---|---|
| InstaPods | $3/mo | 60 sec | Yes | Yes | Yes |
| Railway | ~$5-15/mo | 5 min | No (ephemeral) | No | Limited |
| Render | $7/mo | 5 min | No (ephemeral) | No | Separate service ($7) |
| Heroku | $7/mo | 5 min | No (ephemeral) | No | Separate dyno ($7) |
| VPS + Gunicorn | $4-6/mo | 45-120 min | Yes | Yes | Yes |
| Docker on VPS | $4-6/mo | 30-60 min | Yes | Yes | Yes |
The VPS options give you the same capabilities but cost 45-120 minutes of setup. The PaaS options (Railway, Render, Heroku alternatives) skip setup but don’t support SQLite and charge $7/mo extra for each background worker.
Common Flask Deploy Issues (and Fixes)
“Address already in use”: Your app is trying to bind to a port that’s already taken. Set the port via environment variable:
port = int(os.environ.get('PORT', 3000))
app.run(host='0.0.0.0', port=port)
“ModuleNotFoundError”: A dependency is missing from requirements.txt. Make sure you freeze your dependencies: pip freeze > requirements.txt
“Permission denied”: If your app writes to disk, make sure it writes to a directory your user owns, not system directories.
App works locally but returns 502: Usually a port mismatch. The platform expects your app on port 3000 (or the port specified in config). Check your app is binding to 0.0.0.0, not 127.0.0.1.
Get Started
If your Flask app has a requirements.txt and an entry point that binds to a port, you’re ready:
curl -fsSL https://instapods.com/install.sh | sh
instapods deploy my-flask-app --preset python
Your Flask app is live with SSL, custom domain support, and SSH access. No Docker. No Gunicorn config. No DevOps overhead.