mirror of
https://github.com/frappe/frappe_docker.git
synced 2026-06-17 13:55:08 +00:00
Merge pull request #1796 from Rocket-Quack/chore/Update-Traefik-to-Version-3.6
chore: Update Traefik to version 3.6 and add migration doc
This commit is contained in:
commit
e3ce6c6081
14 changed files with 129 additions and 62 deletions
|
|
@ -45,24 +45,23 @@ Then edit `.env` and set variables according to your needs.
|
|||
|
||||
## HTTPS & SSL Configuration
|
||||
|
||||
| Variable | Purpose | Default | When to Set |
|
||||
| ------------------- | ------------------------------------------------ | ------- | ---------------------------------------- |
|
||||
| `LETSENCRYPT_EMAIL` | Email for Let's Encrypt certificate registration | — | Required if using HTTPS override |
|
||||
| `SITES` | List of domains for SSL certificates | — | Required if using reverse proxy override |
|
||||
| Variable | Purpose | Default | When to Set |
|
||||
| ------------------- | ------------------------------------------------------------- | ------- | ---------------------------------------- |
|
||||
| `LETSENCRYPT_EMAIL` | Email for Let's Encrypt certificate registration | — | Required if using HTTPS override |
|
||||
| `SITES_RULE` | List of domains for SSL (Traefik rule for TLS domain routing) | — | Required if using reverse proxy override |
|
||||
|
||||
**Format for `SITES`:**
|
||||
**Format for `SITES_RULE`:**
|
||||
|
||||
```bash
|
||||
# Single site
|
||||
SITES=`mysite.example.com`
|
||||
SITES_RULE=Host(`mysite.example.com`)
|
||||
|
||||
# Wildcard (any subdomain)
|
||||
SITES=`{any:.+}`
|
||||
# Multiple sites
|
||||
SITES_RULE=Host(`a.example.com`) || Host(`b.example.com`)
|
||||
```
|
||||
|
||||
> Note: `SITES` currently supplies the host list that goes into the `Host(...)` rules. Once the Traefik v3 transition is completed, the plan is to switch to `SITES_RULE` (full rule expression) and deprecate `SITES` to map the Traefik Rule Syntax.
|
||||
|
||||
> Currently the used syntax is pinned to v2 via `--core.defaultRuleSyntax=v2`).
|
||||
> Note: The Traefik v3 migration is complete. Use `SITES_RULE` as a full v3 rule expression; `SITES` is deprecated.
|
||||
> Rule syntax now defaults to v3, so no `core.defaultRuleSyntax` or per-router `ruleSyntax` settings are required.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -4,26 +4,24 @@ Overrides extend the base compose.yaml with additional services or modify existi
|
|||
docker compose -f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/compose.redis.yaml config > compose.custom.yaml
|
||||
```
|
||||
|
||||
Note: The Traefik-based overrides uses Traefik v3.6 and `--core.defaultRuleSyntax=v2` for compatibility with existing traefik v2.11. This flag is temporary and will be removed once the transition to v3.6 is completed.
|
||||
|
||||
| Overrider | Purpose | Additional Info |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| **Database** | | |
|
||||
| compose.mariadb.yaml | Adds MariaDB database service | set `DB_PASSWORD` or default Password will be used |
|
||||
| compose.mariadb-secrets.yaml | Adds MariaDB with password from a secret file instead of environment variable | Set `DB_PASSWORD_SECRETS_FILE` to the path of your secret file |
|
||||
| compose.mariadb-shared.yaml | Makes MariaDB available on a shared network (mariadb-network) for other services | set `DB_PASSWORD` |
|
||||
| compose.postgres.yaml | Uses PostgreSQL instead of MariaDB as the database | set `DB_PASSWORD` |
|
||||
| **Proxy** | | |
|
||||
| compose.noproxy.yaml | Exposes the application directly on port `:8080` without a reverse proxy | |
|
||||
| compose.proxy.yaml | Uses Traefik as HTTP reverse proxy on port `:80` | You can change the published port by setting `HTTP_PUBLISH_PORT` |
|
||||
| compose.https.yaml | Uses Traefik as HTTPS reverse proxy on Port `:443` with automatic HTTP-to-HTTPS redirect | `SITES` and `LETSENCRYPT_EMAIL` must be set. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
|
||||
| **Redis** | | |
|
||||
| Overrider | Purpose | Additional Info |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| **Database** | | |
|
||||
| compose.mariadb.yaml | Adds MariaDB database service | set `DB_PASSWORD` or default Password will be used |
|
||||
| compose.mariadb-secrets.yaml | Adds MariaDB with password from a secret file instead of environment variable | Set `DB_PASSWORD_SECRETS_FILE` to the path of your secret file |
|
||||
| compose.mariadb-shared.yaml | Makes MariaDB available on a shared network (mariadb-network) for other services | set `DB_PASSWORD` |
|
||||
| compose.postgres.yaml | Uses PostgreSQL instead of MariaDB as the database | set `DB_PASSWORD` |
|
||||
| **Proxy** | | |
|
||||
| compose.noproxy.yaml | Exposes the application directly on port `:8080` without a reverse proxy | |
|
||||
| compose.proxy.yaml | Uses Traefik as HTTP reverse proxy on port `:80` | You can change the published port by setting `HTTP_PUBLISH_PORT` |
|
||||
| compose.https.yaml | Uses Traefik as HTTPS reverse proxy on Port `:443` with automatic HTTP-to-HTTPS redirect | `SITES_RULE` and `LETSENCRYPT_EMAIL` must be set. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
|
||||
| **Redis** | | |
|
||||
| compose.redis.yaml | Adds Redis service for caching and background job queuing |
|
||||
| **TBD** | **The following overrides are available but lack documentation. If you use them and understand their purpose, please consider contributing to this documentation.** |
|
||||
| compose.backup-cron.yaml | | |
|
||||
| compose.custom-domain-ssl.yaml | | |
|
||||
| compose.custom-domain.yaml | | |
|
||||
| compose.multi-bench-ssl.yaml | | |
|
||||
| compose.multi-bench.yaml | | |
|
||||
| compose.traefik-ssl.yaml | | |
|
||||
| compose.traefik.yaml | | |
|
||||
| compose.backup-cron.yaml | | |
|
||||
| compose.custom-domain-ssl.yaml | | |
|
||||
| compose.custom-domain.yaml | | |
|
||||
| compose.multi-bench-ssl.yaml | | |
|
||||
| compose.multi-bench.yaml | | |
|
||||
| compose.traefik-ssl.yaml | | |
|
||||
| compose.traefik.yaml | | |
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ Setup Frappe/ERPNext using containerized MariaDB and Redis with Let's Encrypt SS
|
|||
|
||||
**Requirements:**
|
||||
|
||||
- Set `LETSENCRYPT_EMAIL` and `SITES` environment variables
|
||||
- Set `LETSENCRYPT_EMAIL` and `SITES_RULE` environment variables
|
||||
- DNS must point to your server IP
|
||||
|
||||
```sh
|
||||
|
|
@ -93,7 +93,7 @@ docker compose -f compose.yaml \
|
|||
docker compose --project-name <project-name> -f ~/gitops/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
> **Note:** Ensure your `SITES` variable is properly formatted. See [environment variables](04-env-variables.md) for the correct format.
|
||||
> **Note:** Ensure your `SITES_RULE` variable is properly formatted. See [environment variables](04-env-variables.md) for the correct format.
|
||||
|
||||
## Create First Site
|
||||
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ cp example.env ~/gitops/erpnext-one.env
|
|||
sed -i 's/DB_PASSWORD=123/DB_PASSWORD=changeit/g' ~/gitops/erpnext-one.env
|
||||
sed -i 's/DB_HOST=/DB_HOST=mariadb-database/g' ~/gitops/erpnext-one.env
|
||||
sed -i 's/DB_PORT=/DB_PORT=3306/g' ~/gitops/erpnext-one.env
|
||||
sed -i 's/SITES=`erp.example.com`/SITES=\`one.example.com\`,\`two.example.com\`/g' ~/gitops/erpnext-one.env
|
||||
sed -i 's/SITES_RULE=Host(`erp.example.com`)/SITES_RULE=Host(`one.example.com`) || Host(`two.example.com`)/g' ~/gitops/erpnext-one.env
|
||||
echo 'ROUTER=erpnext-one' >> ~/gitops/erpnext-one.env
|
||||
echo "BENCH_NETWORK=erpnext-one" >> ~/gitops/erpnext-one.env
|
||||
```
|
||||
|
|
@ -204,7 +204,7 @@ sed -i 's/DB_PASSWORD=123/DB_PASSWORD=changeit/g' ~/gitops/erpnext-two.env
|
|||
sed -i 's/DB_HOST=/DB_HOST=mariadb-database/g' ~/gitops/erpnext-two.env
|
||||
sed -i 's/DB_PORT=/DB_PORT=3306/g' ~/gitops/erpnext-two.env
|
||||
echo "ROUTER=erpnext-two" >> ~/gitops/erpnext-two.env
|
||||
echo "SITES=\`three.example.com\`,\`four.example.com\`" >> ~/gitops/erpnext-two.env
|
||||
echo 'SITES_RULE=Host(`three.example.com`) || Host(`four.example.com`)' >> ~/gitops/erpnext-two.env
|
||||
echo "BENCH_NETWORK=erpnext-two" >> ~/gitops/erpnext-two.env
|
||||
```
|
||||
|
||||
|
|
@ -253,7 +253,7 @@ Create environment file
|
|||
|
||||
```shell
|
||||
echo "ROUTER=custom-one-example" > ~/gitops/custom-one-example.env
|
||||
echo "SITES=\`custom-one.example.com\`" >> ~/gitops/custom-one-example.env
|
||||
echo 'SITES_RULE=Host(`custom-one.example.com`)' >> ~/gitops/custom-one-example.env
|
||||
echo "BASE_SITE=one.example.com" >> ~/gitops/custom-one-example.env
|
||||
echo "BENCH_NETWORK=erpnext-one" >> ~/gitops/custom-one-example.env
|
||||
```
|
||||
|
|
@ -262,7 +262,7 @@ Note:
|
|||
|
||||
- Change the file name from `custom-one-example.env` to a logical one.
|
||||
- Change `ROUTER` variable from `custom-one.example.com` to the one being added.
|
||||
- Change `SITES` variable from `custom-one.example.com` to the one being added. You can add multiple sites quoted in backtick (`) and separated by commas.
|
||||
- Change `SITES_RULE` variable to the one being added. You can add multiple sites with `Host(...) || Host(...)`.
|
||||
- Change `BASE_SITE` variable from `one.example.com` to the one which is being pointed to.
|
||||
- Change `BENCH_NETWORK` variable from `erpnext-one` to the one which was created with the bench.
|
||||
|
||||
|
|
|
|||
79
docs/06-migration/02-traefik-v3-migration.md
Normal file
79
docs/06-migration/02-traefik-v3-migration.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Migrate an existing Traefik v2 instance to v3
|
||||
|
||||
Use this guide if you already run Traefik v2 with `frappe_docker` and want to upgrade to v3. It focuses on the image upgrade and the v3 routing rule changes that affect existing setups.
|
||||
|
||||
> Note: The Traefik v2 -> v3 migration is complete. The provided overrides no longer set `core.defaultRuleSyntax` or per-router `ruleSyntax` labels, because v3 is the default rule syntax.
|
||||
> Note: If you have a system that must continue to run on v2 despite EOL, you can pin v2 rule syntax with `--core.defaultRuleSyntax=v2` in your Traefik service.
|
||||
|
||||
### Before you start
|
||||
|
||||
Before migrating anything, it is always recommended to create a backup. Better safe than sorry. In particular, compose and .env should be backed up.
|
||||
|
||||
### Quick upgrade summary
|
||||
|
||||
1. Pull the updated repo
|
||||
2. Update env variables especially the updated `SITES` to `SITES_RULE`
|
||||
3. Regenerate the compose config and restart the stack
|
||||
|
||||
#### Multiple hostnames
|
||||
|
||||
v2 allowed comma-separated host lists inside `Host(...)`. In v3 Traefik uses logical OR.
|
||||
|
||||
**Before (v2):**
|
||||
|
||||
```
|
||||
Host(`a.example.com`,`b.example.com`)
|
||||
```
|
||||
|
||||
**After (v3):**
|
||||
|
||||
```
|
||||
Host(`a.example.com`) || Host(`b.example.com`)
|
||||
```
|
||||
|
||||
### Step 1: Replace `SITES` with `SITES_RULE`
|
||||
|
||||
All Traefik routing for HTTPS and multi-bench setups now uses `SITES_RULE`, which is a full v3 rule expression.
|
||||
|
||||
**Single site:**
|
||||
|
||||
```
|
||||
SITES_RULE=Host(`erp.example.com`)
|
||||
```
|
||||
|
||||
**Multiple sites:**
|
||||
|
||||
```
|
||||
SITES_RULE=Host(`a.example.com`) || Host(`b.example.com`)
|
||||
```
|
||||
|
||||
### Step 2: Regenerate and start your compose config
|
||||
|
||||
Example for HTTPS:
|
||||
|
||||
```sh
|
||||
docker compose --env-file .env \
|
||||
-f compose.yaml \
|
||||
-f overrides/compose.mariadb.yaml \
|
||||
-f overrides/compose.redis.yaml \
|
||||
-f overrides/compose.https.yaml \
|
||||
config > ~/gitops/docker-compose.yml
|
||||
```
|
||||
|
||||
```sh
|
||||
docker compose --project-name <project-name> -f ~/gitops/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
See [Single Server Example](../02-setup/07-single-server-example.md)
|
||||
|
||||
### Step 3: Verify Traefik
|
||||
|
||||
After restarting, Traefik will be used in the new supported version 3.6 and the same URLs will be used for the instances when making adjustments. After that, the pages should be accessible as before via the proxy and, if using HTTPS, via HTTPS.
|
||||
|
||||
### Rollback
|
||||
|
||||
If you need to rollback:
|
||||
|
||||
1. Revert Traefik image to `v2.11`
|
||||
2. Restore the old `SITES` variable format and v2 rules
|
||||
3. Regenerate the compose config and restart
|
||||
|
|
@ -49,7 +49,8 @@ PROXY_READ_TIMEOUT=
|
|||
# Necessary if the upload limit in the frappe application is increased
|
||||
CLIENT_MAX_BODY_SIZE=
|
||||
|
||||
# List of sites for letsencrypt certificates quoted with backtick (`) and separated by comma (,)
|
||||
# Single site: SITES_RULE=Host(`erp.example.com`)
|
||||
# Multiple sites: SITES_RULE=Host(`a.example.com`) || Host(`b.example.com`)
|
||||
# More https://doc.traefik.io/traefik/routing/routers/#rule
|
||||
# About acme https://doc.traefik.io/traefik/https/acme/#domain-definition
|
||||
SITES=`erp.example.com`
|
||||
SITES_RULE=Host(`erp.example.com`)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ services:
|
|||
- traefik.http.services.${ROUTER?ROUTER not set}.loadbalancer.server.port=2016
|
||||
- traefik.http.routers.${ROUTER}.service=${ROUTER}
|
||||
- traefik.http.routers.${ROUTER}.entrypoints=http
|
||||
- traefik.http.routers.${ROUTER}.rule=Host(${SITES?SITES not set})
|
||||
- traefik.http.routers.${ROUTER}.rule=${SITES_RULE?SITES_RULE not set}
|
||||
- traefik.http.middlewares.${ROUTER}.headers.customrequestheaders.Host=${BASE_SITE?BASE_SITE not set}
|
||||
- traefik.http.routers.${ROUTER}.middlewares=${ROUTER}
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ services:
|
|||
- traefik.http.services.frontend.loadbalancer.server.port=8080
|
||||
- traefik.http.routers.frontend-http.entrypoints=websecure
|
||||
- traefik.http.routers.frontend-http.tls.certresolver=main-resolver
|
||||
- traefik.http.routers.frontend-http.rule=Host(${SITES:?List of sites not set})
|
||||
- traefik.http.routers.frontend-http.rule=${SITES_RULE:?SITES_RULE not set}
|
||||
|
||||
proxy:
|
||||
image: traefik:v3.6
|
||||
|
|
@ -13,9 +13,6 @@ services:
|
|||
command:
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
# Keep v2 rule syntax for now
|
||||
# Ensure compatibility with existing labels (will be removed if v3 transition is complete)
|
||||
- --core.defaultRuleSyntax=v2
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ services:
|
|||
# ${ROUTER}-http to use the middleware to redirect to https
|
||||
- traefik.http.routers.${ROUTER}-http.middlewares=https-redirect
|
||||
# ${ROUTER}-https the actual router using HTTPS
|
||||
# Uses the environment variable SITES
|
||||
- traefik.http.routers.${ROUTER}-https.rule=Host(${SITES?SITES not set})
|
||||
# Uses the environment variable SITES_RULE
|
||||
- traefik.http.routers.${ROUTER}-https.rule=${SITES_RULE?SITES_RULE not set}
|
||||
- traefik.http.routers.${ROUTER}-https.entrypoints=https
|
||||
- traefik.http.routers.${ROUTER}-https.tls=true
|
||||
# Use the service ${ROUTER} with the frontend
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ services:
|
|||
- traefik.http.services.${ROUTER?ROUTER not set}.loadbalancer.server.port=8080
|
||||
- traefik.http.routers.${ROUTER}-http.service=${ROUTER}
|
||||
- traefik.http.routers.${ROUTER}-http.entrypoints=http
|
||||
- traefik.http.routers.${ROUTER}-http.rule=Host(${SITES?SITES not set})
|
||||
- traefik.http.routers.${ROUTER}-http.rule=${SITES_RULE?SITES_RULE not set}
|
||||
configurator:
|
||||
networks:
|
||||
- bench-network
|
||||
|
|
|
|||
|
|
@ -4,16 +4,13 @@ services:
|
|||
- traefik.enable=true
|
||||
- traefik.http.services.frontend.loadbalancer.server.port=8080
|
||||
- traefik.http.routers.frontend-http.entrypoints=web
|
||||
- traefik.http.routers.frontend-http.rule=HostRegexp(`{any:.+}`)
|
||||
- traefik.http.routers.frontend-http.rule=HostRegexp(`^.+$`)
|
||||
|
||||
proxy:
|
||||
image: traefik:v3.6
|
||||
command:
|
||||
- --providers.docker
|
||||
- --providers.docker.exposedbydefault=false
|
||||
# Keep v2 rule syntax for now
|
||||
# Ensure compatibility with existing labels (will be removed if v3 transition is complete)
|
||||
- --core.defaultRuleSyntax=v2
|
||||
- --entrypoints.web.address=:80
|
||||
ports:
|
||||
- ${HTTP_PUBLISH_PORT:-80}:80
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ services:
|
|||
- --providers.docker=true
|
||||
# Do not expose all Docker services, only the ones explicitly exposed
|
||||
- --providers.docker.exposedbydefault=false
|
||||
# Keep v2 rule syntax for now
|
||||
# Ensure compatibility with existing labels (will be removed if v3 transition is complete)
|
||||
- --core.defaultRuleSyntax=v2
|
||||
# Create an entrypoint http listening on port 80
|
||||
- --entrypoints.http.address=:80
|
||||
# Create an entrypoint https listening on port 443
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ services:
|
|||
- --providers.docker=true
|
||||
# Do not expose all Docker services, only the ones explicitly exposed
|
||||
- --providers.docker.exposedbydefault=false
|
||||
# Keep v2 rule syntax for now
|
||||
# Ensure compatibility with existing labels (will be removed if v3 transition is complete)
|
||||
- --core.defaultRuleSyntax=v2
|
||||
# Create an entrypoint http listening on port 80
|
||||
- --entrypoints.http.address=:80
|
||||
# Enable the access log, with HTTP requests
|
||||
|
|
|
|||
|
|
@ -26,11 +26,13 @@ def _add_version_var(name: str, env_path: Path):
|
|||
def _add_sites_var(env_path: Path):
|
||||
with open(env_path, "r+") as f:
|
||||
content = f.read()
|
||||
content = re.sub(
|
||||
rf"SITES=.*",
|
||||
f"SITES=`tests.localhost`,`test-erpnext-site.localhost`,`test-pg-site.localhost`",
|
||||
content,
|
||||
sites = (
|
||||
"tests.localhost",
|
||||
"test-erpnext-site.localhost",
|
||||
"test-pg-site.localhost",
|
||||
)
|
||||
sites_rule = " || ".join(f"Host(`{site}`)" for site in sites)
|
||||
content = re.sub(rf"SITES_RULE=.*", f"SITES_RULE={sites_rule}", content)
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
f.write(content)
|
||||
|
|
|
|||
Loading…
Reference in a new issue