This guide will walk you through the process of deploying your ShipClojure application to Fly.io, including setting up a PostgreSQL database, configuring secrets, and enabling automated deployments through GitHub Actions.
Prerequisites
Before starting, ensure you have:
Created a Fly.io account and logged in:
fly auth login
A GitHub repository for your project
Step 1: Create Fly.io Apps
Create two applications on Fly.io - one for production and one for staging:
Edit this file with your actual production secrets:
{:oauth2-providers {:google {:client-id "your-client-id", :client-secret "your-client-secret"}}
:db {:dbtype "postgresql"
:port 5432
:host "your-db-host" ; Will be set by DATABASE_URL
:user "postgres" ; Will be set by DATABASE_URL
:password "your-password" ; Will be set by DATABASE_URL
:dbname "your-dbname" ; Will be set by DATABASE_URL
:serverTimezone "UTC"
:idleConnectionTestPeriod 30
:autoReconnect true
:characterEncoding "UTF-8"}
:stripe {:api-key "your-stripe-api-key"
:webhook-signing-secret "your-webhook-secret"}
:jwt {:access-token "your-access-token-secret"
:refresh-token "your-refresh-token-secret"}
:email {:api-key "your-email-service-api-key"}
:totp {:secret "your-totp-secret"}
:cookie-secret "your-cookie-secret"
:cookie-name "saas-session"}
4.2: Generate Secure Random Secrets
For security-critical values, generate secure random secrets:
# Generate JWT secrets
ACCESS_TOKEN_SECRET=$(openssl rand -hex 64)
REFRESH_TOKEN_SECRET=$(openssl rand -hex 64)
# Generate cookie secret
COOKIE_SECRET=$(openssl rand -hex 32)
# Update your .prod-secrets.edn file with these values
4.3: Set Cookie Secret on Fly.io
Set the cookie secret on both apps:
fly secrets set COOKIE_SECRET=$(openssl rand -hex 32) --app [YOUR_APP_NAME]
fly secrets set COOKIE_SECRET=$(openssl rand -hex 32) --app [YOUR_APP_NAME]-staging
4.4: Prevent Search Engine Indexing on Staging
fly secrets set ALLOW_INDEXING=false --app [YOUR_APP_NAME]-staging
Step 5: Set Up GitHub Actions for CI/CD
5.1: Create a Fly API Token
Generate a token for GitHub Actions to deploy your app:
fly tokens create org
This will output a token that starts with FlyV1. Save this token securely.
5.2: Add the Token to GitHub Secrets
Go to your GitHub repository
Navigate to Settings > Secrets and variables > Actions
Click "New repository secret"
Name: FLY_API_TOKEN
Value: Paste the token you generated
Click "Add secret"
5.3: Add Your Production Secrets to GitHub
Create another GitHub secret named PROD_SECRETS_CONTENT
Copy the entire content of your resources/.prod-secrets.edn file
Paste it as the value of this secret
5.4: Create CI/CD Workflow File
Create a file at .github/workflows/ci.yml with the following content:
If you haven't set up your repository yet, follow these steps:
# If you cloned from ShipClojure and set upstream as described in Getting Started
git add .
git commit -m "Configure deployment"
git push -u origin main
# OR if you need to initialize a new repository
git add .
git commit -m "Configure deployment"
git remote add origin <ORIGIN_URL>
git push -u origin main
Step 7: Verify Deployment
After pushing to the main branch, GitHub Actions will:
Run linting and tests
If successful, deploy to your production environment
Every commit to main will deploy to production after passing tests and linting
Every commit to dev will deploy to staging after passing tests and linting
Pull requests to either branch will run tests and linting without deploying
Troubleshooting
Database Connection Issues
If your app can't connect to the database:
# Check if the DATABASE_URL is set
fly secrets list -a [YOUR_APP_NAME]
# You can manually set it if needed
fly secrets set DATABASE_URL=postgres://postgres:password@[YOUR_DB_NAME].internal:5432/postgres -a [YOUR_APP_NAME]
Deployment Failures
Check the deployment logs:
fly logs -a [YOUR_APP_NAME]
Accessing the Database Console
To directly access your PostgreSQL database:
fly postgres connect -a [YOUR_DB_NAME]
This opens a psql shell where you can run SQL commands.
Scaling Your Database
If you need more resources for your database:
# Scale up the VM
fly machine update [MACHINE_ID] --vm-memory 1024 --app [YOUR_DB_NAME]
# Scale out by adding a replica (for HA clusters)
fly machine clone [MACHINE_ID] --region [REGION] --app [YOUR_DB_NAME]
Security Considerations
Rotate your Fly API token periodically
Update your application secrets regularly
Review GitHub repository access controls to protect your workflows
Monitor your application and database logs for suspicious activity
By following this guide, you've set up a complete CI/CD pipeline for your ShipClojure application, with automated testing and deployment to both staging and production environments on Fly.io.
Assuming you've already set up your repository as described in , push your changes to GitHub: