Skip to content

Commit 2d8fb3e

Browse files
authored
☁️ Add FastAPI Cloud deployment (#2438)
1 parent ddb3c34 commit 2d8fb3e

7 files changed

Lines changed: 271 additions & 198 deletions

File tree

.fastapicloudignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.env
2+
!backend/app/frontend/
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Deploy with Docker Compose
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: read
8+
9+
concurrency:
10+
group: deploy-docker-compose
11+
cancel-in-progress: false
12+
13+
jobs:
14+
deploy:
15+
# Do not deploy the template repository, only projects created from it
16+
if: github.repository != 'fastapi/full-stack-fastapi-template'
17+
runs-on: self-hosted
18+
timeout-minutes: 30
19+
env:
20+
DOMAIN: ${{ vars.DOMAIN }}
21+
PROJECT_NAME: ${{ vars.PROJECT_NAME }}
22+
SECRET_KEY: ${{ secrets.SECRET_KEY }}
23+
FIRST_SUPERUSER: ${{ vars.FIRST_SUPERUSER }}
24+
FIRST_SUPERUSER_PASSWORD: ${{ secrets.FIRST_SUPERUSER_PASSWORD }}
25+
SMTP_HOST: ${{ vars.SMTP_HOST }}
26+
SMTP_USER: ${{ vars.SMTP_USER }}
27+
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
28+
EMAILS_FROM_EMAIL: ${{ vars.EMAILS_FROM_EMAIL }}
29+
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
30+
SENTRY_DSN: ${{ vars.SENTRY_DSN }}
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
34+
with:
35+
persist-credentials: false
36+
- name: Build
37+
run: docker compose -f compose.yml -f compose.deploy.yml build
38+
- name: Prepare database
39+
run: docker compose -f compose.yml -f compose.deploy.yml run --rm backend bash scripts/prestart.sh
40+
- name: Start application
41+
run: docker compose -f compose.yml -f compose.deploy.yml up -d

.github/workflows/deploy.yml

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,49 @@ on:
66
- master
77
paths-ignore:
88
- release-notes.md
9+
workflow_dispatch:
910

1011
permissions:
1112
contents: read
1213

1314
jobs:
1415
deploy:
15-
# Do not deploy in the main repository, only in user projects
16-
if: github.repository_owner != 'fastapi'
17-
runs-on: self-hosted
18-
env:
19-
DOMAIN: ${{ secrets.DOMAIN }}
20-
SECRET_KEY: ${{ secrets.SECRET_KEY }}
21-
FIRST_SUPERUSER: ${{ secrets.FIRST_SUPERUSER }}
22-
FIRST_SUPERUSER_PASSWORD: ${{ secrets.FIRST_SUPERUSER_PASSWORD }}
23-
SMTP_HOST: ${{ secrets.SMTP_HOST }}
24-
SMTP_USER: ${{ secrets.SMTP_USER }}
25-
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
26-
EMAILS_FROM_EMAIL: ${{ secrets.EMAILS_FROM_EMAIL }}
27-
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
28-
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
16+
# Do not deploy the template repository, only projects created from it
17+
if: github.repository != 'fastapi/full-stack-fastapi-template'
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 15
2920
steps:
3021
- name: Checkout
3122
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3223
with:
24+
fetch-depth: 0
3325
persist-credentials: false
34-
- run: docker compose -f compose.yml -f compose.deploy.yml build
35-
- run: docker compose -f compose.yml -f compose.deploy.yml run --rm backend bash scripts/prestart.sh
36-
- run: docker compose -f compose.yml -f compose.deploy.yml up -d
26+
- name: Set up Bun
27+
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
28+
with:
29+
bun-version: 1.3.12
30+
- name: Install frontend dependencies
31+
run: bun ci
32+
- name: Build frontend
33+
run: bun run --filter frontend build
34+
env:
35+
# Override frontend/.env so the deployed frontend uses the same origin as the API
36+
VITE_API_URL: ""
37+
- name: Set up uv
38+
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
39+
with:
40+
version: "0.11.18"
41+
- name: Prepare database
42+
run: uv run bash scripts/prestart.sh
43+
working-directory: backend
44+
env:
45+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
46+
PROJECT_NAME: ${{ vars.PROJECT_NAME }}
47+
SECRET_KEY: ${{ secrets.SECRET_KEY }}
48+
FIRST_SUPERUSER: ${{ vars.FIRST_SUPERUSER }}
49+
FIRST_SUPERUSER_PASSWORD: ${{ secrets.FIRST_SUPERUSER_PASSWORD }}
50+
- name: Deploy to FastAPI Cloud
51+
run: uv run fastapi deploy
52+
env:
53+
FASTAPI_CLOUD_TOKEN: ${{ secrets.FASTAPI_CLOUD_TOKEN }}
54+
FASTAPI_CLOUD_APP_ID: ${{ secrets.FASTAPI_CLOUD_APP_ID }}

README.md

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@
1111
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
1212
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
1313
- 🚀 [React](https://react.dev) for the frontend.
14-
- 🧩 Built into the backend image and served by FastAPI on the same domain as the API.
14+
- 🧩 Built into the backend application and served by FastAPI on the same domain as the API.
1515
- 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack.
1616
- 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components.
1717
- 🤖 An automatically generated frontend client.
1818
- 🧪 [Playwright](https://playwright.dev) for End-to-End testing.
1919
- 🦇 Dark mode support.
20-
- 🐋 [Docker Compose](https://www.docker.com) for local services and deployment.
20+
- ☁️ [FastAPI Cloud](https://fastapicloud.com) for deployment.
21+
- 🐋 [Docker Compose](https://www.docker.com) for local services and self-hosted deployment.
22+
- 📞 [Traefik](https://traefik.io) as a reverse proxy with automatic HTTPS.
2123
- 🔒 Secure password hashing by default.
2224
- 🔑 JWT (JSON Web Token) authentication.
2325
- 📫 Email based password recovery.
2426
- 📬 [Mailcatcher](https://mailcatcher.me) for local email testing during development.
2527
- ✅ Tests with [Pytest](https://pytest.org).
26-
- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer.
27-
- 🚢 Deployment instructions using Docker Compose with automatic HTTPS provided by Traefik.
28+
- 🚢 Deployment with FastAPI Cloud or self-hosting with Docker Compose and Traefik.
2829
- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.
2930

3031
### Dashboard Login
@@ -123,17 +124,7 @@ git merge --continue
123124

124125
### Configure
125126

126-
You can then update configs in the `.env` files to customize your configurations.
127-
128-
Before deploying it, make sure you change at least the values for:
129-
130-
- `SECRET_KEY`
131-
- `FIRST_SUPERUSER_PASSWORD`
132-
- `POSTGRES_PASSWORD`
133-
134-
You can (and should) pass these as environment variables from secrets.
135-
136-
Read the [deployment.md](./deployment.md) docs for more details.
127+
You can update the local settings in the `.env` file. Before deploying, configure the environment variables and secrets described in the [FastAPI Cloud deployment guide](./deployment.md) or the [Docker Compose deployment guide](./deployment-docker-compose.md). Never deploy with the default `changethis` values.
137128

138129
### Generate Secret Keys
139130

@@ -159,11 +150,13 @@ Frontend docs: [frontend/README.md](./frontend/README.md).
159150

160151
Deployment docs: [deployment.md](./deployment.md).
161152

153+
Docker Compose deployment: [deployment-docker-compose.md](./deployment-docker-compose.md).
154+
162155
## Development
163156

164157
General development docs: [development.md](./development.md).
165158

166-
This includes the local FastAPI and Vite workflow, Docker Compose services, custom local domains, `.env` configuration, and more.
159+
This includes the local FastAPI and Vite workflow, Docker Compose services, `.env` configuration, and more.
167160

168161
## Release Notes
169162

deployment-docker-compose.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# FastAPI Project - Docker Compose Deployment
2+
3+
You can deploy the project to your own remote server with Docker Compose. The deployment configuration includes Traefik to handle HTTPS and route incoming traffic to the application.
4+
5+
## Preparation
6+
7+
* Have a remote server ready and available.
8+
* Configure DNS records pointing to the server for the application domain and any supporting service subdomains you want to expose, such as `fastapi-project.example.com` and `adminer.fastapi-project.example.com`.
9+
* Install and configure [Docker](https://docs.docker.com/engine/install/) on the remote server (Docker Engine, not Docker Desktop).
10+
11+
## Copy the Code
12+
13+
```bash
14+
rsync -av --exclude=".git/" --filter=":- .gitignore" ./ root@your-server.example.com:/root/code/app/
15+
```
16+
17+
The `--filter=":- .gitignore"` option tells `rsync` to use the same ignore rules as Git, excluding files such as the Python virtual environment.
18+
19+
## Configure the Application
20+
21+
### Environment Variables
22+
23+
Set the application domain, project name, and first superuser email:
24+
25+
```bash
26+
export DOMAIN=fastapi-project.example.com
27+
export PROJECT_NAME="Full Stack FastAPI Project"
28+
export FIRST_SUPERUSER=admin@example.com
29+
```
30+
31+
You can also configure these environment variables as needed:
32+
33+
* `SMTP_HOST`: The SMTP server host from your email provider.
34+
* `SMTP_USER`: The SMTP server user.
35+
* `EMAILS_FROM_EMAIL`: The email account used to send emails.
36+
* `SENTRY_DSN`: The DSN for Sentry.
37+
38+
### Secrets
39+
40+
Generate and set secure values for the database password, token signing key, and first superuser password:
41+
42+
```bash
43+
export POSTGRES_PASSWORD="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
44+
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
45+
export FIRST_SUPERUSER_PASSWORD="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
46+
```
47+
48+
To use an authenticated email provider, also set `SMTP_PASSWORD`.
49+
50+
## Deploy
51+
52+
```bash
53+
cd /root/code/app/
54+
docker compose -f compose.yml -f compose.deploy.yml build
55+
docker compose -f compose.yml -f compose.deploy.yml run --rm backend bash scripts/prestart.sh
56+
docker compose -f compose.yml -f compose.deploy.yml up -d
57+
```
58+
59+
The `compose.deploy.yml` file adds HTTPS and automatic certificate handling to the shared `compose.yml` configuration. Explicitly listing both files excludes the local settings from `compose.override.yml`.
60+
61+
The backend Docker image builds the frontend, so the server does not need Bun or prebuilt frontend files.
62+
63+
## Deploy with GitHub Actions
64+
65+
The included `.github/workflows/deploy-docker-compose.yml` workflow runs the deployment commands on the server when manually triggered from GitHub Actions.
66+
67+
Use a self-hosted runner only for a repository whose contributors and workflow code you trust. GitHub recommends using self-hosted runners with private repositories because workflows execute directly on the runner machine.
68+
69+
### Configure Repository Variables and Secrets
70+
71+
In the repository, go to **Settings** > **Secrets and variables** > **Actions** and add these repository variables:
72+
73+
* `DOMAIN`
74+
* `PROJECT_NAME`
75+
* `FIRST_SUPERUSER`
76+
77+
To enable emails, add these optional repository variables:
78+
79+
* `SMTP_HOST`
80+
* `SMTP_USER`
81+
* `EMAILS_FROM_EMAIL`
82+
83+
To enable Sentry, add the optional `SENTRY_DSN` repository variable.
84+
85+
Add these repository secrets:
86+
87+
* `POSTGRES_PASSWORD`
88+
* `SECRET_KEY`
89+
* `FIRST_SUPERUSER_PASSWORD`
90+
91+
To use an authenticated email provider, add the optional `SMTP_PASSWORD` repository secret.
92+
93+
### Install a Self-Hosted Runner
94+
95+
On the server, create a dedicated user and grant it access to Docker:
96+
97+
```bash
98+
sudo adduser github
99+
sudo usermod -aG docker github
100+
sudo su - github
101+
```
102+
103+
In the GitHub repository, go to **Settings** > **Actions** > **Runners**, select **New self-hosted runner**, choose Linux, and follow the commands GitHub provides to download, configure, and register the runner. Install it in `/home/github/actions-runner`.
104+
105+
After registering the runner, exit the `github` user session and install the runner as a system service:
106+
107+
```bash
108+
exit
109+
cd /home/github/actions-runner
110+
sudo ./svc.sh install github
111+
sudo ./svc.sh start
112+
sudo ./svc.sh status
113+
```
114+
115+
See GitHub's guides for [adding a self-hosted runner](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners) and [configuring the runner as a service](https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/configure-the-application?platform=linux).
116+
117+
### Run the Deployment
118+
119+
When the runner is online, open the repository's **Actions** tab, select **Deploy with Docker Compose**, and select **Run workflow**.
120+
121+
## URLs
122+
123+
Replace `fastapi-project.example.com` with your domain.
124+
125+
Application (frontend and API): `https://fastapi-project.example.com`
126+
127+
Interactive API docs: `https://fastapi-project.example.com/docs`
128+
129+
Adminer: `https://adminer.fastapi-project.example.com`

0 commit comments

Comments
 (0)