You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You can deploy the using Docker Compose with a main Traefik proxy outside handling communication to the outside world and HTTPS certificates.
3
+
You can deploy the project using Docker Compose in a remote server.
4
4
5
-
And you can use CI (continuous integration) systems to do it automatically.
5
+
It expects you to have a Traefik proxy handling communication to the outside world and HTTPS certificates.
6
+
7
+
And you can use CI (continuous integration) systems to deploy automatically.
6
8
7
9
But you have to configure a couple things first.
8
10
9
-
## Traefik network
11
+
## Preparation
12
+
13
+
* Have a remote server ready and available.
14
+
* Configure the DNS records of your domain to point to the IP of the server you just created.
15
+
* Install and configure [Docker](https://docs.docker.com/engine/install/).
16
+
* Create a remote directory to store your code, for example:
17
+
18
+
```bash
19
+
mkdir -p /root/code/fastapi-project/
20
+
```
21
+
22
+
## Public Traefik
23
+
24
+
We need a Traefik proxy to handle incoming connections and HTTPS certificates.
25
+
26
+
### Traefik Docker Compose
27
+
28
+
Copy the Traefik Docker Compose file to your server, to your code directory. You could do it with `rsync`:
29
+
30
+
```bash
31
+
rsync -a docker-compose.traefik.yml root@your-server.example.com:/root/code/fastapi-project/
32
+
```
33
+
34
+
### Traefik Public Network
35
+
36
+
This Traefik will expect a Docker "public network" named `traefik-public` to communicate with your stack(s).
37
+
38
+
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.
10
39
11
-
This stack expects the public Traefik network to be named `traefik-public`.
40
+
To create a Docker "public network" named `traefik-public` run:
12
41
13
-
If you need to use a different Traefik public network name, update it in the `docker-compose.yml` files, in the section:
42
+
```bash
43
+
docker network create traefik-public
44
+
```
45
+
46
+
### Traefik Environment Variables
47
+
48
+
The Traefik Docker Compose file expects some environment variables to be set.
14
49
15
-
```YAML
16
-
networks:
17
-
traefik-public:
18
-
external: true
50
+
Create the environment variables for HTTP Basic Auth.
51
+
52
+
* Create the username, e.g.:
53
+
54
+
```bash
55
+
export USERNAME=admin
56
+
```
57
+
58
+
* Create an environment variable with the password, e.g.:
59
+
60
+
```bash
61
+
export PASSWORD=changethis
62
+
```
63
+
64
+
* Use openssl to generate the "hashed" version of the password and store it in an environment variable:
Change `traefik-public` to the name of the used Traefik network. And then update it in the file `.env`:
70
+
* Create an environment variable with the domain name, e.g.:
22
71
23
72
```bash
24
-
TRAEFIK_PUBLIC_NETWORK=traefik-public
73
+
export DOMAIN=fastapi-project.example.com
25
74
```
75
+
76
+
* Create an environment variable with the email for Let's Encrypt, e.g.:
77
+
78
+
```bash
79
+
export EMAIL=admin@example.com
80
+
```
81
+
82
+
### Start the Traefik Docker Compose
83
+
84
+
Now with the environment variables set and the `docker-compose.traefik.yml` in place, you can start the Traefik Docker Compose:
85
+
86
+
```bash
87
+
docker compose -f docker-compose.traefik.yml up -d
88
+
```
89
+
90
+
## Deploy the FastAPI Project
91
+
92
+
Now that you have Traefik in place you can deploy your FastAPI project with Docker Compose.
93
+
94
+
You could configure the variables in the `.env` file to match your domain, or you could override them before running the `docker compose` command.
95
+
96
+
For example:
97
+
98
+
```bash
99
+
export DOMAIN=fastapi-project.example.com
100
+
```
101
+
102
+
And then deploy with Docker Compose:
103
+
104
+
```bash
105
+
docker compose -f docker-compose.yml up -d
106
+
```
107
+
108
+
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`.
109
+
110
+
## URLs
111
+
112
+
Replace `fastapi-project.example.com` with your domain:
113
+
114
+
Frontend: https://fastapi-project.example.com
115
+
116
+
Backend API docs: https://fastapi-project.example.com/docs
117
+
118
+
Backend API base URL: https://fastapi-project.example.com/api/
# Middleware to redirect www, to disable it remove the next line
60
-
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
61
-
# Middleware to redirect www, and redirect HTTP to HTTPS
62
-
# to disable www redirection remove the section: ${STACK_NAME?Variable not set}-www-redirect,
63
-
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-http.middlewares=${STACK_NAME?Variable not set}-www-redirect,${STACK_NAME?Variable not set}-https-redirect
64
-
65
3
db:
66
4
image: postgres:12
67
5
volumes:
@@ -74,19 +12,19 @@ services:
74
12
pgadmin:
75
13
image: dpage/pgadmin4
76
14
networks:
77
-
- ${TRAEFIK_PUBLIC_NETWORK?Variable not set}
15
+
- traefik-public
78
16
- default
79
17
depends_on:
80
18
- db
81
19
env_file:
82
20
- .env
83
21
labels:
84
22
- traefik.enable=true
85
-
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK?Variable not set}
86
-
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG?Variable not set}
23
+
- traefik.docker.network=traefik-public
24
+
- traefik.constraint-label=traefik-public
87
25
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.rule=Host(`pgadmin.${DOMAIN?Variable not set}`)
88
26
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.entrypoints=http
89
-
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.middlewares=${STACK_NAME?Variable not set}-https-redirect
27
+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.middlewares=https-redirect
90
28
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.rule=Host(`pgadmin.${DOMAIN?Variable not set}`)
91
29
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.entrypoints=https
92
30
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.tls=true
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK?Variable not set}
118
-
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG?Variable not set}
55
+
- traefik.docker.network=traefik-public
56
+
- traefik.constraint-label=traefik-public
119
57
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.rule=Host(`flower.${DOMAIN?Variable not set}`)
120
58
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.entrypoints=http
121
-
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.middlewares=${STACK_NAME?Variable not set}-https-redirect
59
+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.middlewares=https-redirect
122
60
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.rule=Host(`flower.${DOMAIN?Variable not set}`)
123
61
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.entrypoints=https
124
62
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.tls=true
@@ -127,6 +65,9 @@ services:
127
65
128
66
backend:
129
67
image: '${DOCKER_IMAGE_BACKEND?Variable not set}:${TAG-latest}'
68
+
networks:
69
+
- traefik-public
70
+
- default
130
71
depends_on:
131
72
- db
132
73
env_file:
@@ -143,10 +84,21 @@ services:
143
84
INSTALL_DEV: ${INSTALL_DEV-false}
144
85
labels:
145
86
- traefik.enable=true
146
-
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
147
-
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`)
87
+
- traefik.docker.network=traefik-public
88
+
- traefik.constraint-label=traefik-public
89
+
148
90
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=80
149
91
92
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`) && PathPrefix(`/api`, `/docs`, `/redoc`)
93
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.entrypoints=http
94
+
95
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`) && PathPrefix(`/api`, `/docs`, `/redoc`)
96
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.entrypoints=https
97
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls=true
98
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.tls.certresolver=le
99
+
100
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.middlewares=https-redirect,${STACK_NAME?Variable not set}-www-redirect
101
+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
150
102
celeryworker:
151
103
image: '${DOCKER_IMAGE_CELERYWORKER?Variable not set}:${TAG-latest}'
152
104
depends_on:
@@ -166,18 +118,47 @@ services:
166
118
167
119
frontend:
168
120
image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
121
+
networks:
122
+
- traefik-public
123
+
- default
169
124
build:
170
125
context: ./frontend
171
-
labels:
172
-
- traefik.enable=true
173
-
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
174
-
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=PathPrefix(`/`)
175
-
- traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80
126
+
args:
127
+
- VITE_API_URL=https://${DOMAIN?Variable not set}
128
+
- NODE_ENV=production
129
+
labels:
130
+
- traefik.enable=true
131
+
- traefik.docker.network=traefik-public
132
+
- traefik.constraint-label=traefik-public
133
+
134
+
- traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80
135
+
136
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`)
137
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.entrypoints=http
138
+
139
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.rule=Host(`${DOMAIN?Variable not set}`, `www.${DOMAIN?Variable not set}`)
140
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.entrypoints=https
141
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls=true
142
+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-https.tls.certresolver=le
176
143
144
+
# Handle domain with and without "www" to redirect to only one
145
+
# To disable www redirection remove the next line
146
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.regex=^http(s)?://www.(${DOMAIN?Variable not set})/(.*)
147
+
# Redirect a domain with www to non-www
148
+
# To disable it remove the next line
149
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.replacement=http$${1}://${DOMAIN?Variable not set}/$${3}
150
+
# Redirect a domain without www to www
151
+
# To enable it remove the previous line and uncomment the next
0 commit comments