feat: improve UX for external configuration (#6861)

* docs: simplify traefik external tls

* remove pass host header

* docs: simplify and fix nginx external tls

* fix: readiness with enabled tls

* improve proxy docs

* improve proxy docs

* fix(ready): don't verify server cert

* complete nginx docs

* cleanup

* complete traefik docs

* add caddy docs

* simplify traefik

* standardize

* fix caddy

* add httpd docs

* improve external config docs

* guiding error message

* docs(defaults.yaml): remove misleading comments

* guiding error message cs and ru

* improve proxy testability

* fix compose up command

* improve commands

* fix nginx tls disabled

* fix nginx tls enabled

* fix: serve gateway when tls is enabled

* fmt caddy files

* fix caddy enabled tls

* remove not-working commands

* review

* fix checks

* fix link

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Elio Bischof 2023-11-09 11:30:15 +01:00 committed by GitHub
parent 22e2d55999
commit e0a5f8661d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 938 additions and 537 deletions

View File

@ -39,16 +39,15 @@ Telemetry:
# Port ZITADEL will listen on
Port: 8080 # ZITADEL_PORT
# Port ZITADEL is exposed on, it can differ from port e.g. if you proxy the traffic
# !!! Changing this after the initial setup breaks your system !!!
# ExternalPort is the port on which end users access ZITADEL.
# It can differ from Port e.g. if a reverse proxy forwards the traffic to ZITADEL
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
ExternalPort: 8080 # ZITADEL_EXTERNALPORT
# Domain/hostname ZITADEL is exposed externally
# !!! Changing this after the initial setup breaks your system !!!
# ExternalPort is the domain on which end users access ZITADEL.
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
ExternalDomain: localhost # ZITADEL_EXTERNALDOMAIN
# specifies if ZITADEL is exposed externally through TLS
# this must be set to true even if TLS is not enabled on ZITADEL itself
# but TLS traffic is terminated on a reverse proxy
# !!! Changing this after the initial setup breaks your system !!!
# ExternalSecure specifies if ZITADEL is exposed externally using HTTPS or HTTP.
# Read more about external access: https://zitadel.com/docs/self-hosting/manage/custom-domain
ExternalSecure: true # ZITADEL_EXTERNALSECURE
TLS:
# If enabled, ZITADEL will serve all traffic over TLS (HTTPS and gRPC)

View File

@ -9,12 +9,14 @@ import (
internal_authz "github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/config/hook"
"github.com/zitadel/zitadel/internal/config/network"
"github.com/zitadel/zitadel/internal/domain"
)
type Config struct {
Log *logging.Config
Port uint16
TLS network.TLS
}
func MustNewConfig(v *viper.Viper) *Config {

View File

@ -1,6 +1,7 @@
package ready
import (
"crypto/tls"
"net"
"net/http"
"os"
@ -26,7 +27,13 @@ func New() *cobra.Command {
}
func ready(config *Config) bool {
res, err := http.Get("http://" + net.JoinHostPort("localhost", strconv.Itoa(int(config.Port))) + "/debug/ready")
scheme := "https"
if !config.TLS.Enabled {
scheme = "http"
}
// Checking the TLS cert is not in the scope of the readiness check
httpClient := http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
res, err := httpClient.Get(scheme + "://" + net.JoinHostPort("localhost", strconv.Itoa(int(config.Port))) + "/debug/ready")
if err != nil {
logging.WithError(err).Warn("ready check failed")
return false

View File

@ -367,16 +367,16 @@ func startAPIs(
return fmt.Errorf("error starting admin repo: %w", err)
}
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain)); err != nil {
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain), tlsConfig); err != nil {
return err
}
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, config.ExternalSecure, keys.User, config.AuditLogRetention)); err != nil {
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, config.ExternalSecure, keys.User, config.AuditLogRetention), tlsConfig); err != nil {
return err
}
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure)); err != nil {
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil {
return err
}
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure)); err != nil {
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil {
return err
}
if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure), idp.SAMLRootURL(config.ExternalSecure))); err != nil {

View File

@ -1,31 +1,65 @@
---
title: Run ZITADEL on a Custom Domain
sidebar: Custom Domain
title: External ZITADEL Access
sidebar_label: Instance Not Found
---
# Run ZITADEL on a (Sub)domain of Your Choice
## Why do I get an "Instance not found" error?
Also, ZITADEL has the [concept of virtual instances](/concepts/structure/instance#multiple-virtual-instances).
It uses a requests Host header to determine which virtual instance to use.
This is useful for multi-tenancy and resource sharing, for example in SaaS scenarios.
For most cases however, ZITADEL should run on exactly one domain.
This guide assumes you are already familiar with [configuring ZITADEL](./configure).
You most probably need to configure these fields for making ZITADEL work on your custom domain.
## Standard Config
For security reasons, ZITADEL only serves requests sent to the expected protocol, host and port.
If not using localhost as ExternalDomain, ExternalSecure must be true and you need to serve the ZITADEL console over HTTPS.
ZITADEL only serves requests sent to the expected protocol, host and port.
For local testing purposes, you can use following configuration:
```yaml
ExternalSecure: true
ExternalDomain: 'zitadel.my.domain'
ExternalPort: 443
ExternalDomain: localhost
ExternalPort: 8080
ExternalSecure: false
```
## Database Initialization Steps Config
For productive setups however, we recommend using HTTPS and a custom domain:
ZITADEL creates random subdomains for each instance created.
However, for the first instance, this is most probably not the desired behavior.
In this case the `ExternalDomain`-field of the configuration is used.
```yaml
ExternalDomain: 'zitadel.my.domain'
ExternalPort: 443
ExternalSecure: true
```
## Example
## Changing ExternalDomain, ExternalPort or ExternalSecure
You can change the ExternalDomain, ExternalPort and ExternalSecure configuration options at any time.
However, for ZITADEL to be able to pick up the changes, [you need to rerun ZITADELs setup phase](/self-hosting/manage/updating_scaling#the-setup-phase).
## Running ZITADEL behind a Reverse Proxy
If you run ZITADEL behind a reverse proxy, you need to ensure that it sends the correct request headers to ZITADEL.
The proxy must either ensure that
- the original *Host* header value is assigned to the *Forwarded* headers host directive.
- the original requests *Host* header value is unchanged by the proxy.
Check out the [reverse proxy configuration examples](/self-hosting/manage/reverseproxy/reverse_proxy) for more information.
## Organization Domains
Note that by default, you cannot access ZITADEL at an organizations domain.
Organization level domains [are intended for routing users by their login methods to their correct organization](http://localhost:3000/docs/guides/solution-scenarios/domain-discovery).
However, if you want to access ZITADEL at an organization domain, [you can add additional domains using the System API](/apis/resources/system/system-service-add-domain#adds-a-domain-to-an-instance).
Be aware that you won't automatically have the organizations context when you access ZITADEL like this.
## Generated Subdomains
ZITADEL creates random subdomains for [each new virtual instance](/concepts/structure/instance#multiple-virtual-instances).
You can immediately access the ZITADEL Console an APIs using these subdomains without further actions.
## More Information
- [Check out the production-near loadbalancing example with Traefik](/self-hosting/deploy/loadbalancing-example)
- [Explore some concrete proxy configuration examples for ZITADEL using the domain 127.0.0.1.sslip.io](/self-hosting/manage/reverseproxy/reverse_proxy)
Go to the [loadbalancing example with Traefik](/docs/self-hosting/deploy/loadbalancing-example) for seeing a working example configuration.

View File

@ -1,3 +0,0 @@
:::caution
[The Cloudflare tunnel client currently has an issue which allows it not to force HTTP/2 usage towards the origin.](https://github.com/cloudflare/cloudflared/issues/682)

View File

@ -1,166 +0,0 @@
## TLS mode external
```
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
ServerRoot "/usr/local/apache2"
LogLevel warn
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
ServerName my.domain
Listen 80
Listen 443
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
<VirtualHost *:80>
ServerName my.domain
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
ServerName my.domain
ProxyPreserveHost On
SSLCertificateFile /certs/server.crt
SSLCertificateKeyFile /certs/server.key
ProxyPass / h2c://localhost:8080/
ProxyPassReverse / h2c://localhost:8080/
</VirtualHost>
```
## TLS mode enabled
```
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule http2_module modules/mod_http2.so
ServerRoot "/usr/local/apache2"
LogLevel debug
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
ServerName my.domain
Listen 80
Listen 443
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
<VirtualHost *:80>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
ProxyPreserveHost On
SSLEngine on
SSLProxyEngine on
SSLCertificateFile /certs/server.crt
SSLCertificateKeyFile /certs/server.key
ProxyPass / h2://localhost:8080/
</VirtualHost>
```
## TLS mode disabled
```
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
ServerRoot "/usr/local/apache2"
LogLevel warn
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
ServerName my.domain
Listen 80
<VirtualHost *:80>
ServerName my.domain
ProxyPreserveHost On
ProxyPass / h2c://localhost:8080/
ProxyPassReverse / h2c://localhost:8080/
</VirtualHost>
```

View File

@ -1,4 +0,0 @@
## More information
- [You can read here about the TLS Modes](/self-hosting/manage/tls_modes)
- [And here about how ZITADEL makes use of HTTP/2](/self-hosting/manage/http2)

View File

@ -1,95 +0,0 @@
## TLS mode external
```
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 443;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
location / {
grpc_pass grpc://localhost:8080;
grpc_set_header Host $host;
}
}
}
```
:::info
If another port than the default HTTPS port 443 is used replace
` grpc_set_header Host $host;`
with
` grpc_set_header Host $host:$server_port;`
:::
## TLS mode enabled
```
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 443;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
location / {
grpc_pass grpcs://localhost:8080;
grpc_set_header Host $host;
}
}
}
```
:::info
If another port than the default HTTPS port 443 is used replace
` grpc_set_header Host $host;`
with
` grpc_set_header Host $host:$server_port;`
:::
## TLS mode disabled
```
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
grpc_pass grpc://localhost:8080;
grpc_set_header Host $host;
}
}
}
```
:::info
If another port than the default HTTP port 80 is used replace
` grpc_set_header Host $host;`
with
` grpc_set_header Host $host:$server_port;`
:::

View File

@ -0,0 +1,2 @@
- [Read more about ZITADELs TLS Modes](/self-hosting/manage/tls_modes)
- [Read more about how ZITADEL uses HTTP/2](/self-hosting/manage/http2)

View File

@ -0,0 +1,16 @@
import CodeBlock from '@theme/CodeBlock';
import ComposeYaml from "!!raw-loader!./docker-compose.yaml";
<>With these examples, you create and run a minimal {props.link} configuration for ZITADEL with <a href="https://docs.docker.com/compose">Docker Compose</a>.
Whereas the guide focuses on the configuration for {props.link}, you can inspect the configurations for ZITADEL and the database in the base Docker Compose file.</>
<details>
<summary>base docker-compose.yaml</summary>
<CodeBlock language="yaml">{ComposeYaml}</CodeBlock>
</details>
<>For running {props.link}, you will extend the base Docker Compose file with the {props.link} specific Docker Compose file.</>
<details>
<summary>specific docker-compose.yaml</summary>
<CodeBlock language="yaml">{props.compose}</CodeBlock>
</details>

View File

@ -0,0 +1,90 @@
import CodeBlock from '@theme/CodeBlock';
export const Description = ({mode, link}) => {
let desc
switch (mode) {
case "disabled":
desc = <>Neither {link} nor ZITADEL terminates TLS.
Nevertheless, {link} forwards unencrypted HTTP/2 traffic, aka h2c, to ZITADEL.</>;
break;
case "external":
desc = <>{link} terminates TLS and forwards the requests to ZITADEL via unencrypted h2c.
This example uses an unsafe self-signed certificate for {link}</>;
break;
case "enabled":
desc = <>{link} terminates TLS and forwards the requests to ZITADEL via encrypted HTTP/2.
This example uses an unsafe self-signed certificate for {link} and the same for ZITADEL.</>;
break;
}
return (
<>
{desc}
<>By executing the commands below, you will download the files necessary to run ZITADEL behind {link} with the following config:</>
</>)
}
export const Commands = ({mode, name, lower, configfilename}) => {
let genCert = '# Generate a self signed certificate and key.\nopenssl req -x509 -batch -subj "/CN=127.0.0.1.sslip.io/O=ZITADEL Demo" -nodes -newkey rsa:2048 -keyout ./selfsigned.key -out ./selfsigned.crt\n\n';
let connPort = "443"
let connInsecureFlag = "--insecure "
let connScheme = "https"
let grpcPlainTextFlag = ""
if (mode === "disabled") {
genCert = ''
connPort = "80"
grpcPlainTextFlag = "--plaintext "
connScheme = "http"
// We only need that flag for TLS connections with the self-signed cert
connInsecureFlag = ""
}
return (
<div>
<CodeBlock language="bash">
{'# Download the configuration files.'}{'\n'}
{'export ZITADEL_CONFIG_FILES=https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy\n'}
{`wget $\{ZITADEL_CONFIG_FILES\}/docker-compose.yaml -O docker-compose-base.yaml`}{'\n'}
{'wget $\{ZITADEL_CONFIG_FILES\}/'}{lower}{'/docker-compose.yaml -O docker-compose-'}{lower}{'.yaml'}{'\n'}
{'wget $\{ZITADEL_CONFIG_FILES\}/'}{lower}{'/'}{configfilename}{' -O '}{configfilename}{'\n'}
{'\n'}
{genCert}
{'# Run the database, ZITADEL and '}{name}{'.'}{'\n'}
{'docker compose --file docker-compose-base.yaml --file docker-compose-'}{lower}{'.yaml up --detach proxy-'}{mode}{'-tls'}{'\n'}
{'\n'}
{'# Test that gRPC and HTTP APIs work. Empty brackets like {} means success.\n'}
{'sleep 3\n'}
{'grpcurl '}{connInsecureFlag}{grpcPlainTextFlag}{'127.0.0.1.sslip.io:'}{connPort}{' zitadel.admin.v1.AdminService/Healthz\n'}
{'curl '}{connInsecureFlag}{connScheme}{'://127.0.0.1.sslip.io:'}{connPort}{'/admin/v1/healthz\n'}
</CodeBlock>
</div>
)
}
export const LoginURL = ({mode}) => {
let scheme = "https";
if (mode === "disabled") {
scheme = "http"
}
const url = scheme + "://127.0.0.1.sslip.io/ui/console";
return <a href={url}>{url}</a>
}
<Description mode={props.mode} name={props.providername} link={props.link}/>
<details open>
<summary>{props.configfilename}</summary>
<CodeBlock>{props.configfilecontent}</CodeBlock>
</details>
<Commands mode={props.mode} name={props.providername} lower={props.lower} configfilename={props.configfilename}/>
<>When the docker compose command exits successfully, go to <LoginURL mode={props.mode}/> and log in:</>
- **username**: *zitadel-admin@<span></span>zitadel.127.0.0.1.sslip.io*
- **password**: *Password1!*
If the console loads normally, you know that the HTTP and gRPC-Web and gRPC APIs are working correctly.
<CodeBlock language="bash">
{'# You can now stop the database, ZITADEL and '}{props.providername}{'.'}{'\n'}
{'docker compose --file docker-compose-base.yaml --file docker-compose-'}{props.lower}{'.yaml down'}{'\n'}
</CodeBlock>

View File

@ -1,150 +0,0 @@
## TLS mode external
```yaml
entrypoints:
web:
address: ":80"
websecure:
address: ":443"
tls:
stores:
default:
defaultCertificate:
providers:
file:
filename: /etc/traefik/traefik.yaml
http:
middlewares:
zitadel:
headers:
isDevelopment: false
allowedHosts:
- 'localhost'
customRequestHeaders:
:authority: 'localhost'
redirect-to-https:
redirectScheme:
scheme: https
port: 443
permanent: true
routers:
router0:
entryPoints:
- web
middlewares:
- redirect-to-https
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
service: zitadel
router1:
entryPoints:
- websecure
service: zitadel
middlewares:
- zitadel
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
tls:
domains:
- main: "localhost"
sans:
- "*.localhost"
- "localhost"
services:
zitadel:
loadBalancer:
servers:
- url: h2c://localhost:8080
passHostHeader: true
```
## TLS mode enabled
```yaml
entrypoints:
web:
address: ":80"
websecure:
address: ":443"
tls:
stores:
default:
defaultCertificate:
providers:
file:
filename: /etc/traefik/traefik.yaml
http:
middlewares:
zitadel:
headers:
isDevelopment: false
allowedHosts:
- 'localhost'
customRequestHeaders:
:authority: 'localhost'
redirect-to-https:
redirectScheme:
scheme: https
port: 443
permanent: true
routers:
router0:
entryPoints:
- web
middlewares:
- redirect-to-https
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
service: zitadel
# The actual ZITADEL router
router1:
entryPoints:
- websecure
service: zitadel
middlewares:
- zitadel
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
tls:
domains:
- main: "localhost"
sans:
- "*.localhost"
- "localhost"
services:
zitadel:
loadBalancer:
servers:
- url: https://localhost:8080
passHostHeader: true
```
## TLS mode disabled
```yaml
entrypoints:
web:
address: ":80"
providers:
file:
filename: /etc/traefik/traefik.yaml
http:
middlewares:
zitadel:
headers:
isDevelopment: false
allowedHosts:
- 'localhost'
customRequestHeaders:
:authority: 'localhost'
routers:
router0:
entryPoints:
- web
middlewares:
- redirect-to-https
rule: 'HostRegexp(`localhost`, `{subdomain:[a-z]+}.localhost`)'
service: zitadel
services:
zitadel:
loadBalancer:
servers:
- url: h2c://localhost:8080
passHostHeader: true
```

View File

@ -0,0 +1,38 @@
---
title: Configure ZITADEL with Caddy
sidebar_label: Caddy
---
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
import ProxyGuideMore from '../_proxy_guide_more.mdx';
import Compose from "!!raw-loader!./docker-compose.yaml";
import ConfigDisabled from "!!raw-loader!./disabled-tls.Caddyfile";
import ConfigExternal from "!!raw-loader!./external-tls.Caddyfile";
import ConfigEnabled from "!!raw-loader!./enabled-tls.Caddyfile";
export const providername = 'Caddy';
export const lower = "caddy";
export const link = <a href="https://caddyserver.com/">{providername}</a>
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
You can either setup your environment for <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
<!-- grpc NOT WORKING
## TLS mode disabled
<ProxyGuideTLSMode mode="disabled" configfilename="disabled-tls.Caddyfile" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
-->
## TLS mode external
<ProxyGuideTLSMode mode="external" configfilename="external-tls.Caddyfile" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode enabled
<ProxyGuideTLSMode mode="enabled" configfilename="enabled-tls.Caddyfile" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## More Information
<ProxyGuideMore></ProxyGuideMore>

View File

@ -0,0 +1,3 @@
http://127.0.0.1.sslip.io {
reverse_proxy h2c://zitadel-disabled-tls:8080
}

View File

@ -0,0 +1,37 @@
version: '3.8'
services:
proxy-disabled-tls:
image: "caddy:2.7.5-alpine"
volumes:
- "./disabled-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
ports:
- "80:80"
depends_on:
zitadel-disabled-tls:
condition: 'service_healthy'
proxy-external-tls:
image: "caddy:2.7.5-alpine"
volumes:
- "./external-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-external-tls:
condition: 'service_healthy'
proxy-enabled-tls:
image: "caddy:2.7.5-alpine"
volumes:
- "./enabled-tls.Caddyfile:/etc/caddy/Caddyfile:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-enabled-tls:
condition: 'service_healthy'

View File

@ -0,0 +1,8 @@
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy https://zitadel-enabled-tls:8080 {
transport http {
tls_insecure_skip_verify
}
}
}

View File

@ -0,0 +1,4 @@
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy h2c://zitadel-external-tls:8080
}

View File

@ -1,3 +1,8 @@
---
title: Configure ZITADEL with Cloudflare
sidebar_label: Cloudflare
---
## Settings
- [Make sure HTTP/2 is enabled](https://support.cloudflare.com/hc/en-us/articles/200168076-Understanding-Cloudflare-HTTP-2-and-HTTP-3-Support)

View File

@ -0,0 +1,8 @@
---
title: Configure ZITADEL with Cloudflare Tunnel
sidebar_label: Cloudflare Tunnel
---
:::caution
[The Cloudflare tunnel client currently has an issue which disallows it to force HTTP/2 usage towards the origin.](https://github.com/cloudflare/cloudflared/issues/682)

View File

@ -0,0 +1,90 @@
version: '3.8'
services:
zitadel-disabled-tls:
extends:
service: zitadel-init
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
environment:
- ZITADEL_EXTERNALPORT=80
- ZITADEL_EXTERNALSECURE=false
- ZITADEL_TLS_ENABLED=false
depends_on:
zitadel-init:
condition: 'service_completed_successfully'
db:
condition: 'service_healthy'
zitadel-external-tls:
extends:
service: zitadel-init
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
environment:
- ZITADEL_EXTERNALPORT=443
- ZITADEL_EXTERNALSECURE=true
- ZITADEL_TLS_ENABLED=false
depends_on:
zitadel-init:
condition: 'service_completed_successfully'
db:
condition: 'service_healthy'
zitadel-enabled-tls:
extends:
service: zitadel-init
command: 'start-from-setup --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
environment:
- ZITADEL_EXTERNALPORT=443
- ZITADEL_EXTERNALSECURE=true
- ZITADEL_TLS_ENABLED=true
- ZITADEL_TLS_CERTPATH=/etc/certs/selfsigned.crt
- ZITADEL_TLS_KEYPATH=/etc/certs/selfsigned.key
volumes:
- ./selfsigned.crt:/etc/certs/selfsigned.crt
- ./selfsigned.key:/etc/certs/selfsigned.key
depends_on:
zitadel-init:
condition: 'service_completed_successfully'
db:
condition: 'service_healthy'
zitadel-init:
user: '$UID'
image: '${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}'
command: 'init --config /zitadel.yaml'
depends_on:
db:
condition: 'service_healthy'
environment:
# Using an external domain other than localhost proofs, that the proxy configuration works.
# If ZITADEL can't resolve a requests original host to this domain,
# it will return a 404 Instance not found error.
- ZITADEL_EXTERNALDOMAIN=127.0.0.1.sslip.io
# ZITADEL accesses the database via the docker network.
- ZITADEL_DATABASE_COCKROACH_HOST=db
# In case something doesn't work as expected,
# it can be handy to be able to read the access logs.
- ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED=true
# For convenience, ZITADEL should not ask to change the initial admin users password.
- ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED=false
healthcheck:
test: ["CMD", "/app/zitadel", "ready"]
interval: '10s'
timeout: '5s'
retries: 5
start_period: '10s'
db:
restart: 'always'
image: 'cockroachdb/cockroach:latest'
command: 'start-single-node --insecure --http-addr :9090'
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9090/health?ready=1']
interval: '10s'
timeout: '30s'
retries: 5
start_period: '20s'
ports:
- "26257:26257"
- "9090:9090"

View File

@ -0,0 +1,37 @@
version: '3.8'
services:
proxy-disabled-tls:
image: "httpd:2.4.58-alpine"
volumes:
- "./httpd-disabled-tls.conf:/usr/local/apache2/conf/httpd.conf"
ports:
- "80:80"
depends_on:
zitadel-disabled-tls:
condition: 'service_healthy'
proxy-external-tls:
image: "httpd:2.4.58-alpine"
volumes:
- "./httpd-external-tls.conf:/usr/local/apache2/conf/httpd.conf"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-external-tls:
condition: 'service_healthy'
proxy-enabled-tls:
image: "httpd:2.4.58-alpine"
volumes:
- "./httpd-enabled-tls.conf:/usr/local/apache2/conf/httpd.conf"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-enabled-tls:
condition: 'service_healthy'

View File

@ -0,0 +1,39 @@
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
ServerRoot "/usr/local/apache2"
LogLevel debug
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
Listen 80
<VirtualHost *:80>
ProxyPass / h2c://zitadel-disabled-tls:8080/
ProxyPreserveHost on
</VirtualHost>

View File

@ -0,0 +1,47 @@
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule http2_module modules/mod_http2.so
ServerRoot "/usr/local/apache2"
LogLevel debug
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
Listen 443
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
<VirtualHost *:443>
ProxyPass / h2://zitadel-enabled-tls:8080/
ProxyPreserveHost on
SSLEngine on
SSLProxyEngine on
SSLCertificateFile /etc/certs/selfsigned.crt
SSLCertificateKeyFile /etc/certs/selfsigned.key
</VirtualHost>

View File

@ -0,0 +1,43 @@
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_http2_module modules/mod_proxy_http2.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule http2_module modules/mod_http2.so
LogLevel debug
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
Listen 443
<VirtualHost *:443>
ProxyPass / h2c://zitadel-external-tls:8080/
ProxyPassReverse / h2c://zitadel-external-tls:8080/
ProxyPreserveHost on
SSLEngine on
SSLCertificateFile /etc/certs/selfsigned.crt
SSLCertificateKeyFile /etc/certs/selfsigned.key
</VirtualHost>

View File

@ -0,0 +1,38 @@
---
title: Configure ZITADEL with Apache httpd
sidebar_label: Apache httpd
---
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
import Compose from "!!raw-loader!./docker-compose.yaml";
import ConfigDisabled from "!!raw-loader!./httpd-disabled-tls.conf";
import ConfigExternal from "!!raw-loader!./httpd-external-tls.conf";
import ConfigEnabled from "!!raw-loader!./httpd-enabled-tls.conf";
export const providername = "Apache httpd";
export const lower = "httpd";
export const link = <a href="https://httpd.apache.org//">{providername}</a>
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
## TLS mode disabled
<!-- grpc NOT WORKING -->
<ProxyGuideTLSMode mode="disabled" configfilename="httpd-disabled-tls.conf" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode external
<!-- grpc NOT WORKING -->
<ProxyGuideTLSMode mode="external" configfilename="httpd-external-tls.conf" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode enabled
<!-- grpc NOT WORKING -->
<ProxyGuideTLSMode mode="enabled" configfilename="httpd-enabled-tls.conf" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## More Information
<ProxyGuideMore></ProxyGuideMore>

View File

@ -0,0 +1,37 @@
version: '3.8'
services:
proxy-disabled-tls:
image: "nginx:1.25.3-alpine"
volumes:
- "./nginx-disabled-tls.conf:/etc/nginx/nginx.conf:ro"
ports:
- "80:80"
depends_on:
zitadel-disabled-tls:
condition: 'service_healthy'
proxy-external-tls:
image: "nginx:1.25.3-alpine"
volumes:
- "./nginx-external-tls.conf:/etc/nginx/nginx.conf:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-external-tls:
condition: 'service_healthy'
proxy-enabled-tls:
image: "nginx:1.25.3-alpine"
volumes:
- "./nginx-enabled-tls.conf:/etc/nginx/nginx.conf:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-enabled-tls:
condition: 'service_healthy'

View File

@ -0,0 +1,13 @@
events {
worker_connections 1024;
}
http {
server {
listen 80;
http2 on;
location / {
grpc_pass grpc://zitadel-disabled-tls:8080;
grpc_set_header Host $host:$server_port;
}
}
}

View File

@ -0,0 +1,15 @@
events {
worker_connections 1024;
}
http {
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/certs/selfsigned.crt;
ssl_certificate_key /etc/certs/selfsigned.key;
location / {
grpc_pass grpcs://zitadel-enabled-tls:8080;
grpc_set_header Host $host:$server_port;
}
}
}

View File

@ -0,0 +1,15 @@
events {
worker_connections 1024;
}
http {
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/certs/selfsigned.crt;
ssl_certificate_key /etc/certs/selfsigned.key;
location / {
grpc_pass grpc://zitadel-external-tls:8080;
grpc_set_header Host $host:$server_port;
}
}
}

View File

@ -0,0 +1,35 @@
---
title: Configure ZITADEL with NGINX
sidebar_label: NGINX
---
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
import Compose from "!!raw-loader!./docker-compose.yaml";
import ConfigDisabled from "!!raw-loader!./nginx-disabled-tls.conf";
import ConfigExternal from "!!raw-loader!./nginx-external-tls.conf";
import ConfigEnabled from "!!raw-loader!./nginx-enabled-tls.conf";
export const providername = 'NGINX';
export const lower = "nginx";
export const link = <a href="https://nginx.com/">{providername}</a>;
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
## TLS mode disabled
<ProxyGuideTLSMode mode="disabled" configfilename="nginx-disabled-tls.conf" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode external
<ProxyGuideTLSMode mode="external" configfilename="nginx-external-tls.conf" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode enabled
<ProxyGuideTLSMode mode="enabled" configfilename="nginx-enabled-tls.conf" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## More Information
<ProxyGuideMore></ProxyGuideMore>

View File

@ -2,58 +2,13 @@
title: Reverse Proxy Configuration
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import Zcloud from "./_zitadel_cloud.mdx";
import Nginx from "./_nginx.mdx";
import Traefik from "./_traefik.mdx";
import Caddy from "./_caddy.mdx";
import Httpd from "./_httpd.mdx";
import Cftunnel from "./_cloudflare_tunnel.mdx";
import Cloudflare from "./_cloudflare.mdx";
import More from "./_more.mdx";
Check out one of the following guides to configure your favorite reverse proxy:
# Proxy Configuration
- [Traefik](/self-hosting/manage/reverseproxy/traefik)
- [NGINX](/self-hosting/manage/reverseproxy/nginx)
- [Caddy](/self-hosting/manage/reverseproxy/caddy)
<!-- grpc NOT WORKING - [Apache httpd](/self-hosting/manage/reverseproxy/httpd) -->
- [Cloudflare](/self-hosting/manage/reverseproxy/cloudflare)
- [Cloudflare Tunnel](/self-hosting/manage/reverseproxy/cloudflare_tunnel)
- [Fronting ZITADEL Cloud](/self-hosting/manage/reverseproxy/zitadel_cloud)
<Tabs
groupId="proxy-vendor"
default="zcloud"
values={[
{ label: "ZITADEL Cloud", value: "zcloud" },
{ label: "NGINX", value: "nginx" },
{ label: "Traefik", value: "traefik" },
{ label: "Caddy", value: "caddy" },
{ label: "Apache httpd", value: "httpd" },
{ label: "Cloudflare Tunnel", value: "cftunnel" },
{ label: "Cloudflare", value: "cf" },
]}
>
<TabItem value="zcloud">
<Zcloud />
<More />
</TabItem>
<TabItem value="nginx">
<Nginx />
<More />
</TabItem>
<TabItem value="traefik">
<Traefik />
<More />
</TabItem>
<TabItem value="caddy">
<Caddy />
<More />
</TabItem>
<TabItem value="httpd">
<Httpd />
<More />
</TabItem>
<TabItem value="cftunnel">
<Cftunnel />
<More />
</TabItem>
<TabItem value="cf">
<Cloudflare />
<More />
</TabItem>
</Tabs>

View File

@ -0,0 +1,37 @@
version: '3.8'
services:
proxy-disabled-tls:
image: "traefik:v2.10.5"
volumes:
- "./traefik-disabled-tls.yaml:/etc/traefik/traefik.yaml:ro"
ports:
- "80:80"
depends_on:
zitadel-disabled-tls:
condition: 'service_healthy'
proxy-external-tls:
image: "traefik:v2.10.5"
volumes:
- "./traefik-external-tls.yaml:/etc/traefik/traefik.yaml:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-external-tls:
condition: 'service_healthy'
proxy-enabled-tls:
image: "traefik:v2.10.5"
volumes:
- "./traefik-enabled-tls.yaml:/etc/traefik/traefik.yaml:ro"
- "./selfsigned.crt:/etc/certs/selfsigned.crt:ro"
- "./selfsigned.key:/etc/certs/selfsigned.key:ro"
ports:
- "443:443"
depends_on:
zitadel-enabled-tls:
condition: 'service_healthy'

View File

@ -0,0 +1,20 @@
log:
level: "DEBUG"
providers:
file:
filename: "/etc/traefik/traefik.yaml"
entrypoints:
web:
address: ":80"
http:
routers:
router:
entryPoints:
- "web"
service: "zitadel"
rule: 'PathPrefix(`/`)'
services:
zitadel:
loadBalancer:
servers:
- url: "h2c://zitadel-disabled-tls:8080"

View File

@ -0,0 +1,31 @@
log:
level: "DEBUG"
providers:
file:
filename: "/etc/traefik/traefik.yaml"
entrypoints:
web:
address: ":443"
http:
routers:
router:
entryPoints:
- "web"
service: "zitadel"
rule: 'PathPrefix(`/`)'
tls: {}
services:
zitadel:
loadBalancer:
serversTransport: "zitadel"
servers:
- url: "https://zitadel-enabled-tls:8080"
serversTransports:
zitadel:
insecureSkipVerify: true
tls:
stores:
default:
defaultCertificate:
certFile: /etc/certs/selfsigned.crt
keyFile: /etc/certs/selfsigned.key

View File

@ -0,0 +1,27 @@
log:
level: "DEBUG"
providers:
file:
filename: "/etc/traefik/traefik.yaml"
entrypoints:
web:
address: ":443"
http:
routers:
router:
entryPoints:
- "web"
service: "zitadel"
rule: 'PathPrefix(`/`)'
tls: {}
services:
zitadel:
loadBalancer:
servers:
- url: "h2c://zitadel-external-tls:8080"
tls:
stores:
default:
defaultCertificate:
certFile: /etc/certs/selfsigned.crt
keyFile: /etc/certs/selfsigned.key

View File

@ -0,0 +1,35 @@
---
title: Configure ZITADEL with Traefik
sidebar_label: Traefik
---
import ProxyGuideOverview from '../_proxy_guide_overview.mdx';
import ProxyGuideTLSMode from '../_proxy_guide_tls_mode.mdx';
import Compose from "!!raw-loader!./docker-compose.yaml";
import ConfigDisabled from "!!raw-loader!./traefik-disabled-tls.yaml";
import ConfigExternal from "!!raw-loader!./traefik-external-tls.yaml";
import ConfigEnabled from "!!raw-loader!./traefik-enabled-tls.yaml";
export const providername = 'Traefik';
export const lower = "traefik";
export const link = <a href="https://doc.traefik.io/traefik/">{providername}</a>;
<ProxyGuideOverview link={link} compose={Compose}></ProxyGuideOverview>
You can either setup your environment for <a href={'#tls-mode-disabled'}>TLS mode disabled</a>, <a href={'#tls-mode-external'}>TLS mode external</a> or <a href={'#tls-mode-enabled'}>TLS mode enabled</a>.
## TLS mode disabled
<ProxyGuideTLSMode mode="disabled" configfilename="traefik-disabled-tls.yaml" configfilecontent={ConfigDisabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode external
<ProxyGuideTLSMode mode="external" configfilename="traefik-external-tls.yaml" configfilecontent={ConfigExternal} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## TLS mode enabled
<ProxyGuideTLSMode mode="enabled" configfilename="traefik-enabled-tls.yaml" configfilecontent={ConfigEnabled} providername={providername} link={link} lower={lower}></ProxyGuideTLSMode>
## More Information
<ProxyGuideMore></ProxyGuideMore>

View File

@ -1,3 +1,8 @@
---
title: Front ZITADEL Cloud with a CDN, WAF or Reverse Proxy
sidebar_label: Fronting ZITADEL Cloud
---
## Fronting ZITADEL Cloud
You can use your reverseproxy, content delivery network (CDN) or web application firewall (WAF) to front ZITADEL Cloud.

View File

@ -2,8 +2,8 @@
title: TLS Modes
---
To allow ZITADEL to be run on any kind of infrastructure it allows to configure on how tho handle TLS connections.
There are three mode of operation: `external`, `enabled`, `disabled`.
To run ZITADEL on any kind of infrastructure, you can configure on how to handle TLS connections.
There are three modes of operation: `disabled`, `external`, `enabled`.
Generally this command is set as argument while starting ZITADEL. For example like this:
@ -11,6 +11,16 @@ Generally this command is set as argument while starting ZITADEL. For example li
zitadel start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled
```
## Disabled
With the mode `disabled`, you instruct ZITADEL to await all connections with plain http without TLS.
:::caution
Be aware this is not a secure setup and should only be used for test systems!
:::
## External
The mode `external` allows you to configure ZITADEL in such a way that it will instruct its clients to use https.
@ -19,8 +29,8 @@ However ZITADEL delegates the management of TLS connections to a reverseproxy, w
## Enabled
When using the mode `enabled` ZITADEL is setup to await incoming connections in an encrypted fashion.
Wether it is from a client directly, a reverseproxy or web application firewall.
This allows http connections to be secured at the transport level the whole way.
Whether it is from a client directly, a reverse proxy or web application firewall.
This allows HTTP connections to be secured at the transport level the whole way.
If you use the mode `enabled` you need to configure ZITADEL with the necessary TLS settings.
@ -42,17 +52,10 @@ TLS:
Cert: #<bas64 encoded content of a pem file>
```
## Disabled
## More Information
With the mode `disabled` ZITADEL is instructed to await all connections with plain http without TLS.
Beware that ZITADEL uses HTTP/2 for all its connections.
If you are using the mode `external` or `disabled` make sure to verify h2c compatibility.
:::caution
Be aware this is not a secure setup and should only be used for test systems!
:::
## HTTP/2
To allow ZITADEL to function properly please make sure that HTTP/2 is enabled. If you are using the mode `external` or `disabled` make sure to verify h2c compatibilty.
You can read more about how ZITADEL utilizes in our [HTTP/2 docs](/self-hosting/manage/http2).
- [Read more abouth how ZITADEL utilizes HTTP/2](/self-hosting/manage/http2).
- [Explore some concrete proxy configuration examples for ZITADEL](/self-hosting/manage/reverseproxy/reverse_proxy).

View File

@ -61,6 +61,8 @@ ZITADEL uses the privileged and preexisting database user configured in `Databas
- If not already done, it grants the necessary permissions ZITADEL needs to the non privileged user.
- If they dont exist already, it creates all schemas and some basic tables.
The init phase is idempotent if executed with the same binary version.
### The Setup Phase
During `zitadel setup`, ZITADEL creates projection tables and migrates existing data.
@ -70,7 +72,10 @@ When deploying a new ZITADEL version,
make sure the setup phase runs before you roll out the new `zitadel start` processes.
The setup phase is executed in subsequent steps
whereas a new version's execution takes over where the last execution stopped.
Therefore, configuration changes relevant for the setup phase wont take effect in regard to the setup execution.
Some configuration changes are only applied during the setup phase, like ExternalDomain, ExternalPort and ExternalSecure.
The setup phase is idempotent if executed with the same binary version.
### The Runtime Phase

View File

@ -658,7 +658,24 @@ module.exports = {
"self-hosting/manage/production",
"self-hosting/manage/productionchecklist",
"self-hosting/manage/configure/configure",
"self-hosting/manage/reverseproxy/reverse_proxy",
{
type: "category",
collapsed: false,
label: "Reverse Proxy",
link: {
type: "doc",
id: "self-hosting/manage/reverseproxy/reverse_proxy",
},
items: [
"self-hosting/manage/reverseproxy/traefik/traefik",
"self-hosting/manage/reverseproxy/nginx/nginx",
"self-hosting/manage/reverseproxy/caddy/caddy",
// "self-hosting/manage/reverseproxy/httpd/httpd", grpc NOT WORKING
"self-hosting/manage/reverseproxy/cloudflare/cloudflare",
"self-hosting/manage/reverseproxy/cloudflare_tunnel/cloudflare_tunnel",
"self-hosting/manage/reverseproxy/zitadel_cloud/zitadel_cloud",
],
},
"self-hosting/manage/custom-domain",
"self-hosting/manage/http2",
"self-hosting/manage/tls_modes",

View File

@ -22,7 +22,7 @@ services:
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "/app/zitadel", "ready"]
test: ["CMD", "/app/zitadel", "ready", "--config", "/zitadel.yaml" ]
interval: '10s'
timeout: '5s'
retries: 5

View File

@ -63,7 +63,7 @@ func New(
}
api.grpcServer = server.CreateServer(api.verifier, authZ, queries, http2HostName, tlsConfig, accessInterceptor.AccessService())
api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, accessInterceptor)
api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, accessInterceptor, tlsConfig)
if err != nil {
return nil, err
}
@ -80,7 +80,7 @@ func New(
// creates a new grpc gateway and registers it as a separate http handler
//
// used for v1 api (system, admin, mgmt, auth)
func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayPrefix) error {
func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayPrefix, tlsConfig *tls.Config) error {
grpcServer.RegisterServer(a.grpcServer)
handler, prefix, err := server.CreateGatewayWithPrefix(
ctx,
@ -89,6 +89,7 @@ func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayP
a.http1HostName,
a.accessInterceptor,
a.queries,
tlsConfig,
)
if err != nil {
return err

View File

@ -2,6 +2,7 @@ package server
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"strings"
@ -9,6 +10,7 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/zitadel/logging"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/protobuf/encoding/protojson"
@ -89,10 +91,11 @@ func CreateGatewayWithPrefix(
http1HostName string,
accessInterceptor *http_mw.AccessInterceptor,
queries *query.Queries,
tlsConfig *tls.Config,
) (http.Handler, string, error) {
runtimeMux := runtime.NewServeMux(serveMuxOptions...)
opts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithTransportCredentials(grpcCredentials(tlsConfig)),
grpc.WithUnaryInterceptor(client_middleware.DefaultTracingClient()),
}
connection, err := dial(ctx, port, opts)
@ -106,11 +109,17 @@ func CreateGatewayWithPrefix(
return addInterceptors(runtimeMux, http1HostName, accessInterceptor, queries), g.GatewayPathPrefix(), nil
}
func CreateGateway(ctx context.Context, port uint16, http1HostName string, accessInterceptor *http_mw.AccessInterceptor) (*Gateway, error) {
func CreateGateway(
ctx context.Context,
port uint16,
http1HostName string,
accessInterceptor *http_mw.AccessInterceptor,
tlsConfig *tls.Config,
) (*Gateway, error) {
connection, err := dial(ctx,
port,
[]grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithTransportCredentials(grpcCredentials(tlsConfig)),
grpc.WithUnaryInterceptor(client_middleware.DefaultTracingClient()),
})
if err != nil {
@ -217,3 +226,15 @@ func (r *cookieResponseWriter) WriteHeader(status int) {
}
r.ResponseWriter.WriteHeader(status)
}
func grpcCredentials(tlsConfig *tls.Config) credentials.TransportCredentials {
creds := insecure.NewCredentials()
if tlsConfig != nil {
tlsConfigClone := tlsConfig.Clone()
// We don't want to verify the certificate of the internal grpc server
// That's up to the client who called the gRPC gateway
tlsConfigClone.InsecureSkipVerify = true
creds = credentials.NewTLS(tlsConfigClone)
}
return creds
}

View File

@ -319,7 +319,7 @@ Errors:
NotActive: Грантът по проекта не е активен
NotInactive: Грантът по проекта не е неактивен
IAM:
NotFound: Екземплярът не е намерен
NotFound: Екземплярът не е намерен. Вижте https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Ролите не са сменени
MemberInvalid: Членът е невалиден

View File

@ -317,7 +317,7 @@ Errors:
NotActive: Grant projektu není aktivní
NotInactive: Grant projektu není neaktivní
IAM:
NotFound: Instance nenalezena
NotFound: Instance nenalezena. Podívejte se na https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Role nebyly změněny
MemberInvalid: Člen je neplatný

View File

@ -317,7 +317,7 @@ Errors:
NotActive: Projekt Grant ist nicht aktiv
NotInactive: Projekt Grant ist nicht inaktiv
IAM:
NotFound: Instanz nicht gefunden
NotFound: Instanz nicht gefunden. Schau dir https://zitadel.com/docs/self-hosting/manage/custom-domain an
Member:
RolesNotChanged: Rollen wurden nicht verändert
MemberInvalid: Member ist ungültig

View File

@ -317,7 +317,7 @@ Errors:
NotActive: Project grant is not active
NotInactive: Project grant is not inactive
IAM:
NotFound: Instance not found
NotFound: Instance not found. Check out https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Roles have not been changed
MemberInvalid: Member is invalid

View File

@ -317,7 +317,7 @@ Errors:
NotActive: La concesión del proyecto no está activa
NotInactive: La concesión del proyecto no está inactiva
IAM:
NotFound: Instancia no encontrada
NotFound: Instancia no encontrada. Consulta https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Los roles no han cambiado
MemberInvalid: El miembro no es válido

View File

@ -317,7 +317,7 @@ Errors:
NotActive: La subvention de projet n'est pas active
NotInactive: La subvention du projet n'est pas inactive
IAM:
NotFound: Instance non trouvée
NotFound: Instance non trouvée. Consultez https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Les rôles n'ont pas été modifiés
MemberInvalid: Le membre n'est pas valide

View File

@ -318,7 +318,7 @@ Errors:
NotActive: Grant del progetto non è attivo
NotInactive: Grant del progetto non è inattivo
IAM:
NotFound: Istanza non trovata
NotFound: Istanza non trovata. Controlla https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: I ruoli non sono stati cambiati
MemberInvalid: Il membro non è valido

View File

@ -306,7 +306,7 @@ Errors:
NotActive: プロジェクトグラントはアクティブではありません
NotInactive: プロジェクトグラントは非アクティブではありません
IAM:
NotFound: インスタンスが見つかりません
NotFound: インスタンスが見つかりません https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: ロールは変更されていません
MemberInvalid: 無効なメンバーです

View File

@ -317,7 +317,7 @@ Errors:
NotActive: Овластувањето за проектот не е активно
NotInactive: Овластувањето за проектот не е неактивно
IAM:
NotFound: Инстанцата не е пронајдена
NotFound: Инстанцата не е пронајдена. Проверете https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Улогите не се променети
MemberInvalid: Членот е невалиден

View File

@ -317,7 +317,7 @@ Errors:
NotActive: Grant projektu jest nieaktywny
NotInactive: Grant projektu nie jest nieaktywny
IAM:
NotFound: Instancja nie znaleziona
NotFound: Instancja nie znaleziona. Sprawdź https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Role nie zmienione
MemberInvalid: Członek jest nieprawidłowy

View File

@ -315,7 +315,7 @@ Errors:
NotActive: A concessão do projeto não está ativa
NotInactive: A concessão do projeto não está inativa
IAM:
NotFound: Instância não encontrada
NotFound: Instância não encontrada. Confira https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: As funções não foram alteradas
MemberInvalid: O membro é inválido

View File

@ -308,7 +308,7 @@ Errors:
NotActive: Грант проекта не активен
NotInactive: Грант проекта не неактивен
IAM:
NotFound: Экземпляр не найден
NotFound: Экземпляр не найден. Проверьте https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: Роли не изменились
MemberInvalid: Участник недействителен

View File

@ -317,7 +317,7 @@ Errors:
NotActive: 项目授权不是启用状态
NotInactive: 项目授权不是停用状态
IAM:
NotFound: 实例未找到
NotFound: 实例未找到。查看 https://zitadel.com/docs/self-hosting/manage/custom-domain
Member:
RolesNotChanged: 角色没有改变
MemberInvalid: 成员无效