Menu
Login / Register

API & INTEGRATIONS

Deploying a Reverse-Proxied Flask API with Apache + Certbot on a Cloud Instance

By John Simiyu • jonysimiyu75@gmail.com

This article covers a complete, practical path from a working local Flask app to a production HTTPS API running behind Apache on a cloud instance, including turning it into a persistent systemd service and securing it with a free certificate.

Step 1: Wrap Flask as a systemd service

Running Flask in a foreground terminal session is fine for development, but you will want it to survive reboots and restart automatically if it crashes. Create a unit file:

sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Flask API
After=network.target mysql.service

[Service]
Type=simple
User=root
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Note the After= line: if your app depends on a database, make sure you reference the correct service name for it (check with systemctl list-units | grep -i sql, since it may be mysql.service rather than mariadb.service depending on your distro and install method).

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp

Step 2: Point DNS at your instance

Create an A record for your API subdomain pointing at your cloud instance's IP. Confirm propagation before moving on:

dig +short api.example.com

Step 3: Configure an Apache reverse proxy vhost

sudo nano /etc/apache2/sites-available/api.example.com.conf
<VirtualHost *:80>
    ServerName api.example.com

    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:5000/
    ProxyPassReverse / http://127.0.0.1:5000/

    ErrorLog ${APACHE_LOG_DIR}/api.example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/api.example.com-access.log combined
</VirtualHost>

Enable the required Apache modules and the site:

sudo a2enmod proxy proxy_http rewrite headers ssl
sudo a2ensite api.example.com.conf
sudo apache2ctl configtest

Only reload once configtest reports Syntax OK:

sudo systemctl reload apache2

Step 4: Secure it with Certbot

sudo certbot --apache -d api.example.com --non-interactive --agree-tos -m you@example.com

Certbot will automatically update your Apache vhost with the SSL configuration and set up auto-renewal. You can run this for multiple domains in one call if you are also serving a companion static site:

sudo certbot --apache -d app.example.com -d api.example.com --non-interactive --agree-tos -m you@example.com

Step 5: Verify end-to-end over HTTPS

Test against the real domain, not just IP:port, to confirm the whole chain, DNS, Apache, proxy, and cert, is working together:

curl -s -X POST https://api.example.com/api/your-endpoint \
  -H "Content-Type: application/json" \
  -d '{"example": "payload"}'

A proper JSON response (even an expected application-level error) confirms the pipeline is working. Only after this should you point any client application (mobile app, frontend, etc.) at the new HTTPS URL instead of a raw IP and port.

Summary

  1. Wrap your Flask app as a systemd service for persistence and auto-restart.
  2. Point DNS at your instance and confirm propagation.
  3. Configure Apache as a reverse proxy to your app's local port.
  4. Run apache2ctl configtest before every reload.
  5. Secure with Certbot, which handles both the certificate and the vhost SSL config.
  6. Verify over the real domain before switching any client to use it.