Flask Deploying on Linux Server
Deploying Flask on a Linux server (like a VPS from DigitalOcean, Linode, or AWS EC2) gives you full control over your environment. The production stack uses Nginx as the web server and Gunicorn as the WSGI server, with your Flask app running between them.
The Production Stack
Internet │ ▼ Nginx (port 80/443) │ ── handles static files directly │ ── handles SSL/HTTPS │ ── passes dynamic requests to Gunicorn ▼ Gunicorn (port 8000, internal only) │ ── manages multiple worker processes │ ── passes requests to Flask ▼ Flask Application │ ── processes the request │ ── returns the response ▼ Gunicorn → Nginx → Browser
Step 1: Set Up the Server
# SSH into your server
ssh root@your-server-ip
# Update the system
apt update && apt upgrade -y
# Install required packages
apt install python3 python3-pip python3-venv nginx git -yStep 2: Upload Your App
# Clone from GitHub (recommended)
git clone https://github.com/yourusername/yourapp.git /var/www/yourapp
# Or copy files with scp from your computer
scp -r ./myapp root@your-server-ip:/var/www/yourappStep 3: Set Up the Virtual Environment
cd /var/www/yourapp
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install gunicornStep 4: Create the .env File
nano /var/www/yourapp/.envAdd your environment variables:
SECRET_KEY=your-super-secret-production-key
DATABASE_URL=postgresql://user:password@localhost/myapp
FLASK_ENV=productionSet permissions so only the server user can read it:
chmod 600 /var/www/yourapp/.envStep 5: Run Database Migrations
cd /var/www/yourapp
source venv/bin/activate
flask db upgradeStep 6: Test Gunicorn Manually
gunicorn --bind 0.0.0.0:8000 run:appVisit http://your-server-ip:8000 to confirm the app runs. Press Ctrl+C to stop.
Step 7: Create a Systemd Service
A systemd service starts Gunicorn automatically when the server boots and restarts it if it crashes:
nano /etc/systemd/system/yourapp.service[Unit]
Description=Gunicorn instance for Flask app
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/yourapp
Environment="PATH=/var/www/yourapp/venv/bin"
EnvironmentFile=/var/www/yourapp/.env
ExecStart=/var/www/yourapp/venv/bin/gunicorn \
--workers 3 \
--bind unix:/var/www/yourapp/yourapp.sock \
run:app
[Install]
WantedBy=multi-user.target# Enable and start the service
systemctl daemon-reload
systemctl enable yourapp
systemctl start yourapp
systemctl status yourappStep 8: Configure Nginx
nano /etc/nginx/sites-available/yourappserver {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location /static/ {
alias /var/www/yourapp/app/static/;
expires 30d;
}
location / {
proxy_pass http://unix:/var/www/yourapp/yourapp.sock;
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;
}
}# Enable the site
ln -s /etc/nginx/sites-available/yourapp /etc/nginx/sites-enabled/
nginx -t # test configuration syntax
systemctl restart nginxStep 9: Enable HTTPS with Certbot
apt install certbot python3-certbot-nginx -y
certbot --nginx -d yourdomain.com -d www.yourdomain.comCertbot installs a free SSL certificate from Let's Encrypt and configures Nginx to use it automatically. Certificates renew automatically every 90 days.
Deployment Update Workflow
# Pull latest code
cd /var/www/yourapp
git pull origin main
# Activate venv and install new dependencies
source venv/bin/activate
pip install -r requirements.txt
# Run migrations if models changed
flask db upgrade
# Restart Gunicorn to load new code
systemctl restart yourappSummary
A production Linux deployment uses Nginx to handle incoming traffic and serve static files, Gunicorn to run multiple Flask worker processes, and systemd to keep Gunicorn running across reboots. Nginx passes dynamic requests to Gunicorn through a Unix socket. Certbot adds free HTTPS in one command. This stack handles thousands of concurrent users and is the standard deployment pattern for Flask applications worldwide.
