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