Step-by-Step Guide to Deploying a Flask API with CloudPanel, Custom Domain, SSL, and GitHub Actions
Deploying a Flask API with CloudPanel, Custom Domain, SSL, and GitHub Actions CI/CD
This guide walks you through the process of deploying a Flask API on a CloudPanel server with a custom domain name, free SSL certificates, and automated deployments using GitHub Actions.
Prerequisites
Before you begin, you should have:
- A CloudPanel server set up and running
- A domain or subdomain you control
- A GitHub repository containing your Flask application
- Basic knowledge of Linux commands and SSH
Step 1: Create a Python Site in CloudPanel
- Log in to your CloudPanel dashboard
- Navigate to "Sites" in the left sidebar
- Click "Add Site"
- Fill in the following details:
- Domain:
your-domain.com
(e.g.,api.examplesite.com
) - Select "Python" as the application type
- Leave the port settings as default (note the port number, e.g.,
8090
)
- Domain:
- Click "Add" to create the site
CloudPanel will automatically set up a Python environment for your site.
Step 2: Configure DNS Records
- Log in to your domain registrar's dashboard
- Create an A record pointing your domain or subdomain to your CloudPanel server's IP address:
Type: A
Name: api (or @ for the root domain)
Value: YOUR_SERVER_IP
TTL: 3600 (or as recommended by your provider)
- Wait for DNS propagation (can take up to 24 hours, but usually much less)
Step 3: Create a SSH Account
- In CloudPanel, navigate to "Users & Permissions"
- Click "Add User"
- Create a new SSH user for your site:
- Username:
your-username
(e.g.,example-flask-ssh
) - Choose appropriate permissions
- Username:
- Save the user
Step 4: Generate and Configure SSH Keys
From your local computer:
- Generate a SSH key pair without a passphrase:
ssh-keygen -t ed25519 -C "github-actions" -f ./github-actions-key
-
Add the public key to your CloudPanel SSH user:
- In CloudPanel, go to "Users & Permissions"
- Select your user
- Click "Add Public Key"
- Paste the content of
github-actions-key.pub
- Save
-
Securely store the private key (
github-actions-key
) for use with GitHub Actions
Step 5: Note Site Directory
Take note of your site's directory path. In CloudPanel, Python sites typically follow this pattern:
/home/[site-name]/htdocs/[domain]
For example: /home/example-api/htdocs/api.examplesite.com
Step 6: Verify Manual Deployment
Connect to your server as the root user:
ssh root@YOUR_SERVER_IP
Navigate to your site directory and run the following commands to ensure your environment is ready:
cd /home/example-api/htdocs/api.examplesite.com
# Create a virtual environment
python3.12 -m venv venv
# Activate the virtual environment
source venv/bin/activate
# Install required packages
pip install flask waitress
Create a simple Flask application to test:
cat > app.py << 'EOL'
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return jsonify({"status": "success", "message": "API is running"})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8090)
EOL
Create a startup script for Waitress:
cat > start_app.py << 'EOL'
from waitress import serve
from app import app
if __name__ == "__main__":
serve(app, host="0.0.0.0", port=8090, threads=4)
EOL
Create a requirements file:
cat > requirements.txt << 'EOL'
flask
waitress
EOL
Step 7: Configure Proper Permissions
Set appropriate permissions for your SSH user:
# Replace these with your actual SSH username and site directory
SSH_USER="example-flask-ssh"
SITE_DIR="/home/example-api/htdocs/api.examplesite.com"
# Change ownership
sudo chown -R $SSH_USER:$SSH_USER $SITE_DIR
# Set permissions
sudo chmod -R u+rwX $SITE_DIR
Step 8: Set Up GitHub Actions
- In your Flask application repository, create a
.github/workflows
directory:
mkdir -p .github/workflows
- Create a
deploy.yml
file in this directory:
name: Deploy Flask App
on:
push:
branches: [ main, master ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Copy Files to Server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ vars.HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "app.py,requirements.txt,start_app.py"
target: "/tmp/deployment_temp"
strip_components: 0
- name: Deploy and Run Application
uses: appleboy/ssh-action@master
with:
host: ${{ vars.HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Set up variables
APP_DIR=${{ vars.DIRECTORY }}
echo "๐ Starting deployment process..."
# Stop any existing PM2 processes for this app
pm2 delete audit 2>/dev/null || echo "No existing PM2 process to delete"
# Ensure target directory exists
mkdir -p $APP_DIR
# Move new files to target directory
echo "๐ Updating application files..."
cp /tmp/deployment_temp/app.py $APP_DIR/app.py
cp /tmp/deployment_temp/requirements.txt $APP_DIR/requirements.txt
cp /tmp/deployment_temp/start_app.py $APP_DIR/start_app.py
# Prepare Python environment
echo "๐ฆ Setting up Python environment..."
cd $APP_DIR
# Determine Python version
PYTHON_CMD=$(command -v python3.12 || command -v python3.11 || command -v python3.10 || command -v python3.9 || command -v python3)
echo "Using Python: $PYTHON_CMD"
# Create venv if it doesn't exist
if [ ! -d "venv" ]; then
echo "Creating new virtual environment..."
$PYTHON_CMD -m venv venv || {
echo "Failed to create venv, installing dependencies..."
sudo apt-get update
sudo apt-get install -y python3-venv python3-full
$PYTHON_CMD -m venv venv
}
fi
# Install dependencies
echo "Installing Python dependencies..."
./venv/bin/pip install -r requirements.txt
# Start the application with PM2
echo "๐ Starting Flask app with PM2..."
cd $APP_DIR
pm2 start --name audit --interpreter ./venv/bin/python start_app.py
# Save PM2 configuration to persist across reboots
pm2 save
# Check if the app is running
echo "๐ PM2 status:"
pm2 list
# Test the application
echo "๐ Testing the application endpoint..."
curl -I http://127.0.0.1:8090 || echo "โ Curl failed, application may not be running correctly"
# Clean up
echo "๐งน Cleaning up temporary files..."
rm -rf /tmp/deployment_temp
echo "โ
Deployment completed!"
Step 9: Configure GitHub Secrets and Variables
-
In your GitHub repository, go to "Settings" > "Secrets and variables" > "Actions"
-
Add the following secrets:
SSH_USERNAME
: Your SSH username (e.g.,example-flask-ssh
)SSH_PRIVATE_KEY
: The content of your private key file (github-actions-key
)
-
Add the following variables:
HOST
: Your server IP addressDIRECTORY
: The path to your site directory (e.g.,/home/example-api/htdocs/api.examplesite.com
)
Step 10: Test the CI/CD Pipeline
-
Make sure your repository contains at least these files:
app.py
: Your Flask applicationrequirements.txt
: List of dependenciesstart_app.py
: Script to start your application with Waitress.github/workflows/deploy.yml
: GitHub Actions workflow file
-
Push a change to your
main
ormaster
branch:
git add .
git commit -m "Set up CI/CD pipeline"
git push origin main
-
Go to the "Actions" tab in your GitHub repository to monitor the workflow execution
-
Once completed, visit your domain (e.g.,
https://api.examplesite.com
) to verify the deployment
Monitoring and Troubleshooting
PM2 Commands
After deployment, you can SSH into your server and use these PM2 commands:
# List all applications
pm2 list
# View detailed information
pm2 show audit
# View logs
pm2 logs audit
# Restart application
pm2 restart audit
# Stop application
pm2 stop audit
# Set up PM2 to start on system boot (run once)
pm2 startup
# Then follow the instructions displayed
# Save current process list (run after updating processes)
pm2 save
SSL Configuration
CloudPanel automatically configures Let's Encrypt SSL certificates for your domain. You can check the SSL status in the CloudPanel dashboard under:
- Sites > Your Site
- Click on the site name
- Navigate to the "SSL/TLS" tab
If SSL isn't automatically configured, you can request a certificate through the CloudPanel interface.
Troubleshooting Common Issues
-
Application not accessible:
- Check if PM2 is running:
pm2 list
- Verify the port number in your code matches the one assigned by CloudPanel
- Check firewall rules:
sudo ufw status
- Check if PM2 is running:
-
GitHub Actions failing:
- Check the SSH keys are correctly set up
- Verify permissions on the site directory
- Review logs in the GitHub Actions tab
-
SSL certificate issues:
- Ensure DNS records are properly configured
- Wait for DNS propagation
- Try manually requesting a certificate in CloudPanel
This completes the documentation for deploying a Flask API on CloudPanel with a custom domain, free SSL, and automated CI/CD using GitHub Actions. The system uses PM2 as the process manager for reliable application hosting and automatic restarts if needed. If you need any assistance with such automated deployments, feel free to reach out to Jazzed Technology, the most well-established and responsive web development company in Surrey, BC, and serving all of Lower Mainland.