forked from fastapi/full-stack-fastapi-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
📝 Update deployment files and docs (fastapi#660)
- Loading branch information
Showing
7 changed files
with
269 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,124 @@ | ||
# FastAPI Project - Deployment | ||
|
||
You can deploy the using Docker Compose with a main Traefik proxy outside handling communication to the outside world and HTTPS certificates. | ||
You can deploy the project using Docker Compose in a remote server. | ||
|
||
And you can use CI (continuous integration) systems to do it automatically. | ||
It expects you to have a Traefik proxy handling communication to the outside world and HTTPS certificates. | ||
|
||
And you can use CI (continuous integration) systems to deploy automatically. | ||
|
||
But you have to configure a couple things first. | ||
|
||
## Traefik network | ||
## Preparation | ||
|
||
* Have a remote server ready and available. | ||
* Configure the DNS records of your domain to point to the IP of the server you just created. | ||
* Install and configure [Docker](https://docs.docker.com/engine/install/). | ||
* Create a remote directory to store your code, for example: | ||
|
||
```bash | ||
mkdir -p /root/code/fastapi-project/ | ||
``` | ||
|
||
## Public Traefik | ||
|
||
We need a Traefik proxy to handle incoming connections and HTTPS certificates. | ||
|
||
### Traefik Docker Compose | ||
|
||
Copy the Traefik Docker Compose file to your server, to your code directory. You could do it with `rsync`: | ||
|
||
```bash | ||
rsync -a docker-compose.traefik.yml root@your-server.example.com:/root/code/fastapi-project/ | ||
``` | ||
|
||
### Traefik Public Network | ||
|
||
This Traefik will expect a Docker "public network" named `traefik-public` to communicate with your stack(s). | ||
|
||
This way, there will be a single public Traefik proxy that handles the communication (HTTP and HTTPS) with the outside world, and then behind that, you could have one or more stacks. | ||
|
||
This stack expects the public Traefik network to be named `traefik-public`. | ||
To create a Docker "public network" named `traefik-public` run: | ||
|
||
If you need to use a different Traefik public network name, update it in the `docker-compose.yml` files, in the section: | ||
```bash | ||
docker network create traefik-public | ||
``` | ||
|
||
### Traefik Environment Variables | ||
|
||
The Traefik Docker Compose file expects some environment variables to be set. | ||
|
||
```YAML | ||
networks: | ||
traefik-public: | ||
external: true | ||
Create the environment variables for HTTP Basic Auth. | ||
|
||
* Create the username, e.g.: | ||
|
||
```bash | ||
export USERNAME=admin | ||
``` | ||
|
||
* Create an environment variable with the password, e.g.: | ||
|
||
```bash | ||
export PASSWORD=changethis | ||
``` | ||
|
||
* Use openssl to generate the "hashed" version of the password and store it in an environment variable: | ||
|
||
```bash | ||
export HASHED_PASSWORD=$(openssl passwd -apr1 $PASSWORD) | ||
``` | ||
|
||
Change `traefik-public` to the name of the used Traefik network. And then update it in the file `.env`: | ||
* Create an environment variable with the domain name, e.g.: | ||
|
||
```bash | ||
TRAEFIK_PUBLIC_NETWORK=traefik-public | ||
export DOMAIN=fastapi-project.example.com | ||
``` | ||
|
||
* Create an environment variable with the email for Let's Encrypt, e.g.: | ||
|
||
```bash | ||
export EMAIL=admin@example.com | ||
``` | ||
|
||
### Start the Traefik Docker Compose | ||
|
||
Now with the environment variables set and the `docker-compose.traefik.yml` in place, you can start the Traefik Docker Compose: | ||
|
||
```bash | ||
docker compose -f docker-compose.traefik.yml up -d | ||
``` | ||
|
||
## Deploy the FastAPI Project | ||
|
||
Now that you have Traefik in place you can deploy your FastAPI project with Docker Compose. | ||
|
||
You could configure the variables in the `.env` file to match your domain, or you could override them before running the `docker compose` command. | ||
|
||
For example: | ||
|
||
```bash | ||
export DOMAIN=fastapi-project.example.com | ||
``` | ||
|
||
And then deploy with Docker Compose: | ||
|
||
```bash | ||
docker compose -f docker-compose.yml up -d | ||
``` | ||
|
||
For production you wouldn't want to have the overrides in `docker-compose.override.yml`, so you would need to explicitly specify the file to use, `docker-compose.yml`. | ||
|
||
## URLs | ||
|
||
Replace `fastapi-project.example.com` with your domain: | ||
|
||
Frontend: https://fastapi-project.example.com | ||
|
||
Backend API docs: https://fastapi-project.example.com/docs | ||
|
||
Backend API base URL: https://fastapi-project.example.com/api/ | ||
|
||
PGAdmin: https://pgadmin.fastapi-project.example.com | ||
|
||
Flower: https://flower.fastapi-project.example.com | ||
|
||
Traefik UI: https://traefik.fastapi-project.example.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
services: | ||
traefik: | ||
image: traefik:v2.3 | ||
ports: | ||
# Listen on port 80, default for HTTP, necessary to redirect to HTTPS | ||
- 80:80 | ||
# Listen on port 443, default for HTTPS | ||
- 443:443 | ||
restart: always | ||
labels: | ||
# Enable Traefik for this service, to make it available in the public network | ||
- traefik.enable=true | ||
# Use the traefik-public network (declared below) | ||
- traefik.docker.network=traefik-public | ||
# Define the port inside of the Docker service to use | ||
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080 | ||
# Make Traefik use this domain (from an environment variable) in HTTP | ||
- traefik.http.routers.traefik-dashboard-http.entrypoints=http | ||
- traefik.http.routers.traefik-dashboard-http.rule=Host(`traefik.${DOMAIN?Variable not set}`) | ||
# traefik-https the actual router using HTTPS | ||
- traefik.http.routers.traefik-dashboard-https.entrypoints=https | ||
- traefik.http.routers.traefik-dashboard-https.rule=Host(`traefik.${DOMAIN?Variable not set}`) | ||
- traefik.http.routers.traefik-dashboard-https.tls=true | ||
# Use the "le" (Let's Encrypt) resolver created below | ||
- traefik.http.routers.traefik-dashboard-https.tls.certresolver=le | ||
# Use the special Traefik service api@internal with the web UI/Dashboard | ||
- traefik.http.routers.traefik-dashboard-https.service=api@internal | ||
# https-redirect middleware to redirect HTTP to HTTPS | ||
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https | ||
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true | ||
# traefik-http set up only to use the middleware to redirect to https | ||
- traefik.http.routers.traefik-dashboard-http.middlewares=https-redirect | ||
# admin-auth middleware with HTTP Basic auth | ||
# Using the environment variables USERNAME and HASHED_PASSWORD | ||
- traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME?Variable not set}:${HASHED_PASSWORD?Variable not set} | ||
# Enable HTTP Basic auth, using the middleware created above | ||
- traefik.http.routers.traefik-dashboard-https.middlewares=admin-auth | ||
volumes: | ||
# Add Docker as a mounted volume, so that Traefik can read the labels of other services | ||
- /var/run/docker.sock:/var/run/docker.sock:ro | ||
# Mount the volume to store the certificates | ||
- traefik-public-certificates:/certificates | ||
command: | ||
# Enable Docker in Traefik, so that it reads labels from Docker services | ||
- --providers.docker | ||
# Do not expose all Docker services, only the ones explicitly exposed | ||
- --providers.docker.exposedbydefault=false | ||
# Create an entrypoint "http" listening on port 80 | ||
- --entrypoints.http.address=:80 | ||
# Create an entrypoint "https" listening on port 443 | ||
- --entrypoints.https.address=:443 | ||
# Create the certificate resolver "le" for Let's Encrypt, uses the environment variable EMAIL | ||
- --certificatesresolvers.le.acme.email=${EMAIL?Variable not set} | ||
# Store the Let's Encrypt certificates in the mounted volume | ||
- --certificatesresolvers.le.acme.storage=/certificates/acme.json | ||
# Use the TLS Challenge for Let's Encrypt | ||
- --certificatesresolvers.le.acme.tlschallenge=true | ||
# Enable the access log, with HTTP requests | ||
- --accesslog | ||
# Enable the Traefik log, for configurations and errors | ||
- --log | ||
# Enable the Dashboard and API | ||
- --api | ||
networks: | ||
# Use the public network created to be shared between Traefik and | ||
# any other service that needs to be publicly available with HTTPS | ||
- traefik-public | ||
|
||
volumes: | ||
# Create a volume to store the certificates, even if the container is recreated | ||
traefik-public-certificates: | ||
|
||
networks: | ||
# Use the previously created public network "traefik-public", shared with other | ||
# services that need to be publicly available via this Traefik | ||
traefik-public: | ||
external: true |
Oops, something went wrong.