mirror of
https://github.com/traefik/traefik
synced 2026-02-03 11:10:33 +00:00
Split Expose User Guides & Add Multi-Layer Routing Section
This commit is contained in:
@@ -1,252 +1,29 @@
|
||||
# Exposing Services with Traefik on Docker
|
||||
# Exposing Services with Traefik on Docker - Advanced
|
||||
|
||||
This guide will help you expose your services securely through Traefik Proxy using Docker. We'll cover routing HTTP and HTTPS traffic, implementing TLS, adding middlewares, Let's Encrypt integration, and sticky sessions.
|
||||
This guide builds on the concepts and setup from the [Basic Guide](basic.md). Make sure you've completed the basic guide and have a working Traefik setup with Docker before proceeding.
|
||||
|
||||
In this advanced guide, you'll learn how to enhance your Traefik deployment with:
|
||||
|
||||
- **Middlewares** for security headers and access control
|
||||
- **Let's Encrypt** for automated certificate management
|
||||
- **Sticky sessions** for stateful applications
|
||||
- **Multi-layer routing** for hierarchical routing with a complex authentication based routing example
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Completed the [Basic Guide](basic.md)
|
||||
- Docker and Docker Compose installed
|
||||
- Basic understanding of Docker concepts
|
||||
- Traefik deployed using the Traefik Docker Setup guide
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://hub.docker.com/r/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:v3.4"
|
||||
container_name: "traefik"
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
- "--entryPoints.web.address=:80"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
|
||||
whoami:
|
||||
image: "traefik/whoami"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=web"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
```
|
||||
|
||||
Save this as `docker-compose.yml` and start the services:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.docker.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 172.18.0.3
|
||||
IP: fe80::215:5dff:fe00:c9e
|
||||
RemoteAddr: 172.18.0.2:55108
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.docker.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 172.18.0.1
|
||||
X-Forwarded-Host: whoami.docker.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: 5789f594e7d5
|
||||
X-Real-Ip: 172.18.0.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on [URL paths](../reference/routing-configuration/http/routing/rules-and-priority.md#path-pathprefix-and-pathregexp). This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
Update your `docker-compose.yml` to add another service:
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
|
||||
# New service
|
||||
whoami-api:
|
||||
image: "traefik/whoami"
|
||||
networks:
|
||||
- proxy
|
||||
container_name: "whoami-api"
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Path-based routing
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=web"
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly.
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate:
|
||||
|
||||
```bash
|
||||
mkdir -p certs
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout certs/local.key -out certs/local.crt \
|
||||
-subj "/CN=*.docker.localhost"
|
||||
```
|
||||
|
||||
Create a directory for dynamic configuration and add a TLS configuration file:
|
||||
|
||||
```bash
|
||||
mkdir -p dynamic
|
||||
cat > dynamic/tls.yml << EOF
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /certs/local.crt
|
||||
keyFile: /certs/local.key
|
||||
EOF
|
||||
```
|
||||
|
||||
Update your `docker-compose.yml` file with the following changes:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:v3.4"
|
||||
container_name: "traefik"
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
command:
|
||||
- "--api.insecure=false"
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
- "--entryPoints.web.address=:80"
|
||||
- "--entryPoints.websecure.address=:443"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
# Add the following volumes
|
||||
- "./certs:/certs:ro"
|
||||
- "./dynamic:/etc/traefik/dynamic:ro"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.localhost`)"
|
||||
- "traefik.http.routers.dashboard.entrypoints=websecure"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.dashboard.tls=true"
|
||||
|
||||
whoami:
|
||||
image: "traefik/whoami"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=websecure"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.whoami.tls=true"
|
||||
|
||||
whoami-api:
|
||||
image: "traefik/whoami"
|
||||
container_name: "whoami-api"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=websecure"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.whoami-api.tls=true"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Your browser can access https://whoami.docker.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate.
|
||||
- Working Traefik setup from the basic guide
|
||||
|
||||
## Add Middlewares
|
||||
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
|
||||
Add the following labels to your whoami service in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
|
||||
|
||||
# Secure Headers Middleware
|
||||
- "traefik.http.middlewares.secure-headers.headers.frameDeny=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.sslRedirect=true"
|
||||
@@ -255,10 +32,10 @@ labels:
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsPreload=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000"
|
||||
|
||||
|
||||
# IP Allowlist Middleware
|
||||
- "traefik.http.middlewares.ip-allowlist.ipallowlist.sourceRange=127.0.0.1/32,192.168.0.0/16,10.0.0.0/8"
|
||||
|
||||
|
||||
# Apply middlewares to whoami router
|
||||
- "traefik.http.routers.whoami.middlewares=secure-headers,ip-allowlist"
|
||||
```
|
||||
@@ -288,7 +65,7 @@ curl -k -I -H "Host: whoami.docker.localhost" https://localhost/
|
||||
|
||||
In the response headers, you should see security headers set by the middleware:
|
||||
|
||||
- `X-Frame-Options: DENY`
|
||||
- `X-Frame-Options: DENY`
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-XSS-Protection: 1; mode=block`
|
||||
- `Strict-Transport-Security` with the appropriate settings
|
||||
@@ -438,28 +215,191 @@ You should see different `Hostname` values in these responses, as each request i
|
||||
!!! important "Browser Testing"
|
||||
When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with `httpOnly` and `secure` flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript.
|
||||
|
||||
For more advanced configuration options, see the [reference documentation](../reference/routing-configuration/http/load-balancing/service.md).
|
||||
For more advanced configuration options, see the [reference documentation](../../reference/routing-configuration/http/load-balancing/service.md).
|
||||
|
||||
## Multi-Layer Routing
|
||||
|
||||
Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application.
|
||||
|
||||
!!! info "Provider Requirement"
|
||||
Multi-layer routing requires the File provider, as Docker labels do not support the `parentRefs` field. However, you can use **both Docker and File providers together** - Docker labels for service discovery and File configuration for multi-layer routing.
|
||||
|
||||
### Setup Multi-Layer Routing with Docker
|
||||
|
||||
To use multi-layer routing with Docker, you need to enable the File provider alongside the Docker provider.
|
||||
|
||||
Update your Traefik service in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:latest"
|
||||
container_name: "traefik"
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic" # Enable File provider
|
||||
- "--entryPoints.web.address=:80"
|
||||
- "--entryPoints.websecure.address=:443"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- "./dynamic:/etc/traefik/dynamic:ro" # Mount directory for dynamic config
|
||||
```
|
||||
|
||||
### Authentication-Based Routing Example
|
||||
|
||||
Let's create a multi-layer routing setup where a parent router authenticates requests, and child routers direct traffic based on user roles.
|
||||
|
||||
First, keep your Docker services defined with labels as usual:
|
||||
|
||||
```yaml
|
||||
# In docker-compose.yml
|
||||
services:
|
||||
# ... traefik service from above ...
|
||||
|
||||
# Mock authentication service that adds X-User-Role header
|
||||
auth-service:
|
||||
image: "traefik/whoami"
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=Auth Service
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.auth-service.loadbalancer.server.port=80"
|
||||
|
||||
# Admin backend service
|
||||
admin-backend:
|
||||
image: "traefik/whoami"
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=Admin Backend
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.admin-backend.loadbalancer.server.port=80"
|
||||
|
||||
# User backend service
|
||||
user-backend:
|
||||
image: "traefik/whoami"
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=User Backend
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.user-backend.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
Now create the multi-layer routing configuration in a file. Create `dynamic/mlr.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
routers:
|
||||
# Parent router with authentication middleware
|
||||
api-parent:
|
||||
rule: "Host(`api.docker.localhost`) && PathPrefix(`/api`)"
|
||||
middlewares:
|
||||
- auth-middleware
|
||||
entryPoints:
|
||||
- websecure
|
||||
# Note: No service and no TLS config - this is a parent router
|
||||
|
||||
# Child router for admin users
|
||||
api-admin:
|
||||
rule: "HeadersRegexp(`X-Auth-User`, `admin`)"
|
||||
service: admin-backend@docker # Reference Docker service
|
||||
parentRefs:
|
||||
- api-parent@file # Explicit reference to parent in file provider
|
||||
|
||||
# Child router for regular users
|
||||
api-user:
|
||||
rule: "HeadersRegexp(`X-Auth-User`, `user`)"
|
||||
service: user-backend@docker # Reference Docker service
|
||||
parentRefs:
|
||||
- api-parent@file # Explicit reference to parent in file provider
|
||||
|
||||
middlewares:
|
||||
auth-middleware:
|
||||
basicAuth:
|
||||
users:
|
||||
- "admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0"
|
||||
- "user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI."
|
||||
headerField: X-Auth-User
|
||||
```
|
||||
|
||||
!!! note "Generating Password Hashes"
|
||||
The password hashes above are generated using `htpasswd`. To create your own user credentials:
|
||||
|
||||
```bash
|
||||
# Using htpasswd (Apache utils)
|
||||
htpasswd -nb admin yourpassword
|
||||
```
|
||||
|
||||
!!! important "Cross-Provider References"
|
||||
Notice the `@docker` suffix on service names and the `@file` suffix in `parentRefs`. When using the File provider to orchestrate multi-layer routing with Docker services:
|
||||
|
||||
- Use `service-name@docker` to reference Docker services
|
||||
- Use `parent-name@file` in `parentRefs` to reference the parent router in the File provider
|
||||
|
||||
The `@provider` suffix tells Traefik which provider namespace to look in for the resource.
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Test Multi-Layer Routing
|
||||
|
||||
Test the routing behavior:
|
||||
|
||||
```bash
|
||||
# Request goes through parent router → auth middleware → admin child router
|
||||
curl -k -u admin:test -H "Host: api.docker.localhost" https://localhost/api
|
||||
```
|
||||
|
||||
You should see the response from the admin-backend service when authenticating as `admin`. Try with `user:test` credentials to reach the user-backend service instead.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Request arrives** at `api.docker.localhost/api`
|
||||
2. **Parent router** (`api-parent`) matches based on host and path
|
||||
3. **BasicAuth middleware** authenticates the user and sets the `X-Auth-User` header with the username
|
||||
4. **Child router** (`api-admin` or `api-user`) matches based on the header value
|
||||
5. **Request forwarded** to the appropriate Docker service
|
||||
|
||||
For more details about multi-layer routing, see the [Multi-Layer Routing documentation](../../reference/routing-configuration/http/routing/multi-layer-routing.md).
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this guide, you've learned how to:
|
||||
In this advanced guide, you've learned how to:
|
||||
|
||||
- Expose HTTP services through Traefik in Docker
|
||||
- Set up path-based routing to direct traffic to different backend services
|
||||
- Secure your services with TLS using self-signed certificates
|
||||
- Add security with middlewares like secure headers and IP allow listing
|
||||
- Automate certificate management with Let's Encrypt
|
||||
- Implement sticky sessions for stateful applications
|
||||
- Setup multi-layer routing for authentication-based routing
|
||||
|
||||
These fundamental capabilities provide a solid foundation for exposing any application through Traefik Proxy in Docker. Each of these can be further customized to meet your specific requirements.
|
||||
These advanced capabilities allow you to build production-ready Traefik deployments with Docker. Each of these can be further customized to meet your specific requirements.
|
||||
|
||||
### Next Steps
|
||||
|
||||
Now that you understand the basics of exposing services with Traefik Proxy, you might want to explore:
|
||||
Now that you've mastered both basic and advanced Traefik features with Docker, you might want to explore:
|
||||
|
||||
- [Advanced routing options](../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Docker provider documentation](../reference/install-configuration/providers/docker.md) for more details about the Docker integration
|
||||
- [Advanced routing options](../../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Docker provider documentation](../../reference/install-configuration/providers/docker.md) for more details about the Docker integration
|
||||
@@ -0,0 +1,250 @@
|
||||
# Exposing Services with Traefik on Docker - Basic
|
||||
|
||||
This guide will help you get started with exposing your services through Traefik Proxy using Docker. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- Basic understanding of Docker concepts
|
||||
- Traefik deployed using the [Traefik Docker Setup guide](../../setup/docker.md)
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://hub.docker.com/r/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:v3.4"
|
||||
container_name: "traefik"
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
- "--entryPoints.web.address=:80"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
|
||||
whoami:
|
||||
image: "traefik/whoami"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=web"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
```
|
||||
|
||||
Save this as `docker-compose.yml` and start the services:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.docker.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 172.18.0.3
|
||||
IP: fe80::215:5dff:fe00:c9e
|
||||
RemoteAddr: 172.18.0.2:55108
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.docker.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 172.18.0.1
|
||||
X-Forwarded-Host: whoami.docker.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: 5789f594e7d5
|
||||
X-Real-Ip: 172.18.0.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on [URL paths](../../reference/routing-configuration/http/routing/rules-and-priority.md#path-pathprefix-and-pathregexp). This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
Update your `docker-compose.yml` to add another service:
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
|
||||
# New service
|
||||
whoami-api:
|
||||
image: "traefik/whoami"
|
||||
networks:
|
||||
- proxy
|
||||
container_name: "whoami-api"
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Path-based routing
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=web"
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly.
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate:
|
||||
|
||||
```bash
|
||||
mkdir -p certs
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout certs/local.key -out certs/local.crt \
|
||||
-subj "/CN=*.docker.localhost"
|
||||
```
|
||||
|
||||
Create a directory for dynamic configuration and add a TLS configuration file:
|
||||
|
||||
```bash
|
||||
mkdir -p dynamic
|
||||
cat > dynamic/tls.yml << EOF
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /certs/local.crt
|
||||
keyFile: /certs/local.key
|
||||
EOF
|
||||
```
|
||||
|
||||
Update your `docker-compose.yml` file with the following changes:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: "traefik:v3.4"
|
||||
container_name: "traefik"
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
command:
|
||||
- "--api.insecure=false"
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=proxy"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
- "--entryPoints.web.address=:80"
|
||||
- "--entryPoints.websecure.address=:443"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
# Add the following volumes
|
||||
- "./certs:/certs:ro"
|
||||
- "./dynamic:/etc/traefik/dynamic:ro"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.localhost`)"
|
||||
- "traefik.http.routers.dashboard.entrypoints=websecure"
|
||||
- "traefik.http.routers.dashboard.service=api@internal"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.dashboard.tls=true"
|
||||
|
||||
whoami:
|
||||
image: "traefik/whoami"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=websecure"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.whoami.tls=true"
|
||||
|
||||
whoami-api:
|
||||
image: "traefik/whoami"
|
||||
container_name: "whoami-api"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.docker.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=websecure"
|
||||
# Add the following label
|
||||
- "traefik.http.routers.whoami-api.tls=true"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
name: proxy
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Your browser can access https://whoami.docker.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've mastered the basics of exposing services with Traefik on Docker, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing.
|
||||
|
||||
Continue to the [Advanced Guide](advanced.md) to learn about:
|
||||
|
||||
- Adding middlewares for security and access control
|
||||
- Generating certificates with Let's Encrypt
|
||||
- Configuring sticky sessions for stateful applications
|
||||
- Setting up multi-layer routing for authentication-based routing
|
||||
@@ -1,432 +1,25 @@
|
||||
# Exposing Services with Traefik on Kubernetes
|
||||
# Exposing Services with Traefik on Kubernetes - Advanced
|
||||
|
||||
This guide will help you expose your services securely through Traefik Proxy on Kubernetes. We'll cover routing HTTP and HTTPS traffic, implementing TLS, adding security middleware, and configuring sticky sessions. For routing, this guide gives you two options:
|
||||
This guide builds on the concepts and setup from the [Basic Guide](basic.md). Make sure you've completed the basic guide and have a working Traefik setup with Kubernetes before proceeding.
|
||||
|
||||
- [Gateway API](../reference/routing-configuration/kubernetes/gateway-api.md)
|
||||
- [IngressRoute](../reference/routing-configuration/kubernetes/crd/http/ingressroute.md)
|
||||
In this advanced guide, you'll learn how to enhance your Traefik deployment with:
|
||||
|
||||
Feel free to choose the one that fits your needs best.
|
||||
- **Middlewares** for security headers and access control
|
||||
- **Let's Encrypt** for automated certificate management (IngressRoute)
|
||||
- **cert-manager** for automated certificate management (Gateway API)
|
||||
- **Sticky sessions** for stateful applications
|
||||
- **Multi-layer routing** for hierarchical routing with complex authentication scenarios (IngressRoute only)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Completed the [Basic Guide](basic.md)
|
||||
- A Kubernetes cluster with Traefik Proxy installed
|
||||
- `kubectl` configured to interact with your cluster
|
||||
- Traefik deployed using the Traefik Kubernetes Setup guide
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://github.com/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, create the deployment and service:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami.yaml
|
||||
```
|
||||
|
||||
Now, let's create routes using either Gateway API or IngressRoute.
|
||||
|
||||
### Using Gateway API
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway # This Gateway is automatically created by Traefik
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### Using IngressRoute
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.docker.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
```
|
||||
|
||||
!!! info
|
||||
Make sure to remove the `ports.web.redirections` block from the `values.yaml` file if you followed the Kubernetes Setup Guide to install Traefik otherwise you will be redirected to the HTTPS entrypoint:
|
||||
|
||||
```yaml
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami-6d5d964cb-8pv4k
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.0.18
|
||||
IP: fe80::d4c0:3bff:fe20:b0a3
|
||||
RemoteAddr: 10.42.0.17:39872
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.docker.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.42.0.1
|
||||
X-Forwarded-Host: whoami.docker.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: traefik-76cbd5b89c-rx5xn
|
||||
X-Real-Ip: 10.42.0.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on URL paths. This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
First, deploy a second service to represent an API:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami-api
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami-api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami-api
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
env:
|
||||
- name: WHOAMI_NAME
|
||||
value: "API Service"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-api
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami-api
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-api.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-api.yaml
|
||||
```
|
||||
|
||||
Now set up path-based routing:
|
||||
|
||||
### Gateway API with Path Rules
|
||||
|
||||
Update your existing `HTTPRoute` to include path-based routing:
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api
|
||||
backendRefs:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Update the file `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### IngressRoute with Path Rules
|
||||
|
||||
Update your existing IngressRoute to include path-based routing:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly:
|
||||
|
||||
```bash
|
||||
{"hostname":"whoami-api-67d97b4868-dvvll","ip":["127.0.0.1","::1","10.42.0.9","fe80::10aa:37ff:fe74:31f2"],"headers":{"Accept":["*/*"],"Accept-Encoding":["gzip"],"User-Agent":["curl/8.7.1"],"X-Forwarded-For":["10.42.0.1"],"X-Forwarded-Host":["whoami.docker.localhost"],"X-Forwarded-Port":["80"],"X-Forwarded-Proto":["http"],"X-Forwarded-Server":["traefik-669c479df8-vkj22"],"X-Real-Ip":["10.42.0.1"]},"url":"/api","host":"whoami.docker.localhost","method":"GET","name":"API Service","remoteAddr":"10.42.0.13:36592"}
|
||||
```
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate:
|
||||
|
||||
```bash
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout tls.key -out tls.crt \
|
||||
-subj "/CN=whoami.docker.localhost"
|
||||
```
|
||||
|
||||
Create a TLS secret in Kubernetes:
|
||||
|
||||
```bash
|
||||
kubectl create secret tls whoami-tls --cert=tls.crt --key=tls.key
|
||||
```
|
||||
|
||||
!!! important "Prerequisite for Gateway API with TLS"
|
||||
Before using the Gateway API with TLS, you must define the `websecure` listener in your Traefik installation. This is typically done in your Helm values.
|
||||
|
||||
Example configuration in `values.yaml`:
|
||||
```yaml
|
||||
gateway:
|
||||
listeners:
|
||||
web:
|
||||
port: 80
|
||||
protocol: HTTP
|
||||
namespacePolicy:
|
||||
from: All
|
||||
websecure:
|
||||
port: 443
|
||||
protocol: HTTPS
|
||||
namespacePolicy:
|
||||
from: All
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- kind: Secret
|
||||
name: local-selfsigned-tls
|
||||
group: ""
|
||||
```
|
||||
|
||||
See the Traefik Kubernetes Setup Guide for complete installation details.
|
||||
|
||||
### Gateway API with TLS
|
||||
|
||||
Update your existing `HTTPRoute` to use the secured gateway listener:
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway
|
||||
sectionName: websecure # The HTTPS listener
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api
|
||||
backendRefs:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Update the file `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### IngressRoute with TLS
|
||||
|
||||
Update your existing IngressRoute to use TLS:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure # Changed from 'web' to 'websecure'
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
tls:
|
||||
secretName: whoami-tls # Added TLS configuration
|
||||
```
|
||||
|
||||
Update the file `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Verify HTTPS Access
|
||||
|
||||
Now you can access your service securely. Since we're using a self-signed certificate, you'll need to skip certificate verification:
|
||||
|
||||
```bash
|
||||
curl -k -H "Host: whoami.docker.localhost" https://localhost/
|
||||
```
|
||||
|
||||
Your browser can also access https://whoami.docker.localhost/ (you'll need to accept the security warning for the self-signed certificate).
|
||||
- Working Traefik setup from the basic guide
|
||||
|
||||
## Add Middlewares
|
||||
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
|
||||
### Create Middlewares
|
||||
|
||||
@@ -469,37 +62,6 @@ kubectl apply -f middlewares.yaml
|
||||
|
||||
In Gateway API, you can apply middlewares using the `ExtensionRef` filter type. This is the preferred and standard way to use Traefik middlewares with Gateway API, as it integrates directly with the HTTPRoute specification.
|
||||
|
||||
First, make sure you have the same middlewares defined:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: secure-headers
|
||||
namespace: default
|
||||
spec:
|
||||
headers:
|
||||
frameDeny: true
|
||||
sslRedirect: true
|
||||
browserXssFilter: true
|
||||
contentTypeNosniff: true
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
stsSeconds: 31536000
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: ip-allowlist
|
||||
namespace: default
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 10.0.0.0/8 # Typical cluster network range
|
||||
- 192.168.0.0/16 # Common local network range
|
||||
```
|
||||
|
||||
Now, update your `HTTPRoute` to reference these middlewares using the `ExtensionRef` filter:
|
||||
|
||||
```yaml
|
||||
@@ -525,7 +87,7 @@ spec:
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
name: secure-headers
|
||||
- type: ExtensionRef
|
||||
- type: ExtensionRef
|
||||
extensionRef: # IP AllowList Middleware Definition
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
@@ -543,7 +105,7 @@ spec:
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
name: secure-headers
|
||||
- type: ExtensionRef
|
||||
- type: ExtensionRef
|
||||
extensionRef: # IP AllowList Middleware Definition
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
@@ -854,7 +416,7 @@ spec:
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
name: secure-headers
|
||||
- type: ExtensionRef
|
||||
- type: ExtensionRef
|
||||
extensionRef: # IP AllowList Middleware Definition
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
@@ -876,7 +438,7 @@ spec:
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
name: secure-headers
|
||||
- type: ExtensionRef
|
||||
- type: ExtensionRef
|
||||
extensionRef: # IP AllowList Middleware Definition
|
||||
group: traefik.io
|
||||
kind: Middleware
|
||||
@@ -986,29 +548,283 @@ You should see different `Hostname` values in these responses, as each request i
|
||||
!!! important "Browser Testing"
|
||||
When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with `httpOnly` and `secure` flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript.
|
||||
|
||||
For more advanced configuration options, see the [reference documentation](../reference/routing-configuration/http/load-balancing/service.md).
|
||||
For more advanced configuration options, see the [reference documentation](../../reference/routing-configuration/http/load-balancing/service.md).
|
||||
|
||||
## Setup Multi-Layer Routing
|
||||
|
||||
Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application.
|
||||
|
||||
!!! info "IngressRoute Support"
|
||||
Multi-layer routing is **natively supported** by Kubernetes IngressRoute (CRD) using the `spec.parentRefs` field. This feature is not available when using standard Kubernetes Ingress or Gateway API resources.
|
||||
|
||||
### Authentication-Based Routing Example
|
||||
|
||||
Let's create a multi-layer routing setup where a parent IngressRoute authenticates requests, and child IngressRoutes direct traffic based on user roles.
|
||||
|
||||
!!! important "Parent Router Requirements"
|
||||
Parent routers in multi-layer routing must not have a service defined. The child routers will handle the service selection based on their matching rules. Make sure all child IngressRoutes reference the parent correctly using `parentRefs`.
|
||||
|
||||
First, deploy your backend services:
|
||||
|
||||
```yaml
|
||||
# whoami-backends.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: admin-backend
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: admin-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: admin-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
env:
|
||||
- name: WHOAMI_NAME
|
||||
value: "Admin Backend"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: admin-backend
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: admin-backend
|
||||
ports:
|
||||
- port: 80
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: user-backend
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: user-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: user-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
env:
|
||||
- name: WHOAMI_NAME
|
||||
value: "User Backend"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: user-backend
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: user-backend
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Apply the backend services:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-backends.yaml
|
||||
```
|
||||
|
||||
Now create the middleware and IngressRoutes for multi-layer routing:
|
||||
|
||||
```yaml
|
||||
# mlr-ingressroute.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: auth-secret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
users: |
|
||||
admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0
|
||||
user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI.
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: auth-middleware
|
||||
namespace: default
|
||||
spec:
|
||||
basicAuth:
|
||||
secret: auth-secret
|
||||
headerField: X-Auth-User
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api-parent
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`api.docker.localhost`) && PathPrefix(`/api`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: auth-middleware
|
||||
# Note: No services and no TLS config - this is a parent IngressRoute
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api-admin
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: api-parent
|
||||
namespace: default # Optional, defaults to same namespace
|
||||
routes:
|
||||
- match: HeadersRegexp(`X-Auth-User`, `admin`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: admin-backend
|
||||
port: 80
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api-user
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: api-parent
|
||||
namespace: default # Optional, defaults to same namespace
|
||||
routes:
|
||||
- match: HeadersRegexp(`X-Auth-User`, `user`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: user-backend
|
||||
port: 80
|
||||
```
|
||||
|
||||
!!! note "Generating Password Hashes"
|
||||
The password hashes above are generated using `htpasswd`. To create your own user credentials:
|
||||
|
||||
```bash
|
||||
# Using htpasswd (Apache utils)
|
||||
htpasswd -nb admin yourpassword
|
||||
```
|
||||
|
||||
Apply the multi-layer routing configuration:
|
||||
|
||||
```bash
|
||||
kubectl apply -f mlr-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Test Multi-Layer Routing
|
||||
|
||||
Test the routing behavior:
|
||||
|
||||
```bash
|
||||
# Request goes through parent router → auth middleware → admin child router
|
||||
curl -k -u admin:test -H "Host: api.docker.localhost" https://localhost/api
|
||||
```
|
||||
|
||||
You should see the response from the admin-backend service when authenticating as `admin`. Try with `user:test` credentials to reach the user-backend service instead.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Request arrives** at `api.docker.localhost/api`
|
||||
2. **Parent IngressRoute** (`api-parent`) matches based on host and path
|
||||
3. **BasicAuth middleware** authenticates the user and sets the `X-Auth-User` header with the username
|
||||
4. **Child IngressRoute** (`api-admin` or `api-user`) matches based on the header value
|
||||
5. **Request forwarded** to the appropriate Kubernetes service
|
||||
|
||||
### Cross-Namespace Parent References
|
||||
|
||||
You can reference parent IngressRoutes in different namespaces by specifying the `namespace` field:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api-child
|
||||
namespace: app-namespace
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: api-parent
|
||||
namespace: shared-namespace # Parent in different namespace
|
||||
routes:
|
||||
- match: Path(`/child`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: child-service
|
||||
port: 80
|
||||
```
|
||||
|
||||
!!! important "Cross-Namespace Requirement"
|
||||
To use cross-namespace parent references, you must enable the `allowCrossNamespace` option in your Traefik Helm values:
|
||||
|
||||
```yaml
|
||||
providers:
|
||||
kubernetesCRD:
|
||||
allowCrossNamespace: true
|
||||
```
|
||||
|
||||
### Multiple Parent References
|
||||
|
||||
Child IngressRoutes can reference multiple parent IngressRoutes:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api-child
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: parent-one
|
||||
- name: parent-two
|
||||
routes:
|
||||
- match: Path(`/api`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: child-service
|
||||
port: 80
|
||||
```
|
||||
|
||||
For more details about multi-layer routing, see the [Multi-Layer Routing documentation](../../reference/routing-configuration/http/routing/multi-layer-routing.md).
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this guide, you've learned how to:
|
||||
In this advanced guide, you've learned how to:
|
||||
|
||||
- Expose HTTP services through Traefik in Kubernetes using both Gateway API and IngressRoute
|
||||
- Set up path-based routing to direct traffic to different backend services
|
||||
- Secure your services with TLS using self-signed certificates
|
||||
- Add security with middlewares like secure headers and IP allow listing
|
||||
- Automate certificate management with Let's Encrypt
|
||||
- Automate certificate management with Let's Encrypt (IngressRoute) and cert-manager (Gateway API)
|
||||
- Implement sticky sessions for stateful applications
|
||||
- Setup multi-layer routing for authentication-based routing (IngressRoute only)
|
||||
|
||||
These fundamental capabilities provide a solid foundation for exposing any application through Traefik Proxy in Kubernetes. Each of these can be further customized to meet your specific requirements.
|
||||
These advanced capabilities allow you to build production-ready Traefik deployments with Kubernetes. Each of these can be further customized to meet your specific requirements.
|
||||
|
||||
### Next Steps
|
||||
|
||||
Now that you understand the basics of exposing services with Traefik Proxy, you might want to explore:
|
||||
Now that you've mastered both basic and advanced Traefik features with Kubernetes, you might want to explore:
|
||||
|
||||
- [Advanced routing options](../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Kubernetes Provider documentation](../reference/install-configuration/providers/kubernetes/kubernetes-crd.md) for more details about the Kubernetes integration.
|
||||
- [Gateway API provider documentation](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md) for more details about the Gateway API integration.
|
||||
- [Advanced routing options](../../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Kubernetes Provider documentation](../../reference/install-configuration/providers/kubernetes/kubernetes-crd.md) for more details about the Kubernetes integration
|
||||
- [Gateway API provider documentation](../../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md) for more details about the Gateway API integration
|
||||
@@ -0,0 +1,438 @@
|
||||
# Exposing Services with Traefik on Kubernetes - Basic
|
||||
|
||||
This guide will help you get started with exposing your services through Traefik Proxy on Kubernetes. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS.
|
||||
|
||||
For routing, this guide gives you two options:
|
||||
|
||||
- [Gateway API](../../reference/routing-configuration/kubernetes/gateway-api.md)
|
||||
- [IngressRoute](../../reference/routing-configuration/kubernetes/crd/http/ingressroute.md)
|
||||
|
||||
Feel free to choose the one that fits your needs best.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster with Traefik Proxy installed
|
||||
- `kubectl` configured to interact with your cluster
|
||||
- Traefik deployed using the [Traefik Kubernetes Setup guide](../../setup/kubernetes.md)
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://github.com/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, create the deployment and service:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami.yaml
|
||||
```
|
||||
|
||||
Now, let's create routes using either Gateway API or IngressRoute.
|
||||
|
||||
### Using Gateway API
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway # This Gateway is automatically created by Traefik
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### Using IngressRoute
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.docker.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
```
|
||||
|
||||
!!! info
|
||||
Make sure to remove the `ports.web.redirections` block from the `values.yaml` file if you followed the Kubernetes Setup Guide to install Traefik otherwise you will be redirected to the HTTPS entrypoint:
|
||||
|
||||
```yaml
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami-6d5d964cb-8pv4k
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.42.0.18
|
||||
IP: fe80::d4c0:3bff:fe20:b0a3
|
||||
RemoteAddr: 10.42.0.17:39872
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.docker.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.42.0.1
|
||||
X-Forwarded-Host: whoami.docker.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: traefik-76cbd5b89c-rx5xn
|
||||
X-Real-Ip: 10.42.0.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on URL paths. This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
First, deploy a second service to represent an API:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: whoami-api
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: whoami-api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: whoami-api
|
||||
spec:
|
||||
containers:
|
||||
- name: whoami
|
||||
image: traefik/whoami
|
||||
env:
|
||||
- name: WHOAMI_NAME
|
||||
value: "API Service"
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: whoami-api
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: whoami-api
|
||||
ports:
|
||||
- port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-api.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-api.yaml
|
||||
```
|
||||
|
||||
Now set up path-based routing:
|
||||
|
||||
### Gateway API with Path Rules
|
||||
|
||||
Update your existing `HTTPRoute` to include path-based routing:
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api
|
||||
backendRefs:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Update the file `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### IngressRoute with Path Rules
|
||||
|
||||
Update your existing IngressRoute to include path-based routing:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Save this as `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.docker.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly:
|
||||
|
||||
```bash
|
||||
{"hostname":"whoami-api-67d97b4868-dvvll","ip":["127.0.0.1","::1","10.42.0.9","fe80::10aa:37ff:fe74:31f2"],"headers":{"Accept":["*/*"],"Accept-Encoding":["gzip"],"User-Agent":["curl/8.7.1"],"X-Forwarded-For":["10.42.0.1"],"X-Forwarded-Host":["whoami.docker.localhost"],"X-Forwarded-Port":["80"],"X-Forwarded-Proto":["http"],"X-Forwarded-Server":["traefik-669c479df8-vkj22"],"X-Real-Ip":["10.42.0.1"]},"url":"/api","host":"whoami.docker.localhost","method":"GET","name":"API Service","remoteAddr":"10.42.0.13:36592"}
|
||||
```
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate:
|
||||
|
||||
```bash
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout tls.key -out tls.crt \
|
||||
-subj "/CN=whoami.docker.localhost"
|
||||
```
|
||||
|
||||
Create a TLS secret in Kubernetes:
|
||||
|
||||
```bash
|
||||
kubectl create secret tls whoami-tls --cert=tls.crt --key=tls.key
|
||||
```
|
||||
|
||||
!!! important "Prerequisite for Gateway API with TLS"
|
||||
Before using the Gateway API with TLS, you must define the `websecure` listener in your Traefik installation. This is typically done in your Helm values.
|
||||
|
||||
Example configuration in `values.yaml`:
|
||||
```yaml
|
||||
gateway:
|
||||
listeners:
|
||||
web:
|
||||
port: 80
|
||||
protocol: HTTP
|
||||
namespacePolicy:
|
||||
from: All
|
||||
websecure:
|
||||
port: 443
|
||||
protocol: HTTPS
|
||||
namespacePolicy:
|
||||
from: All
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- kind: Secret
|
||||
name: local-selfsigned-tls
|
||||
group: ""
|
||||
```
|
||||
|
||||
See the Traefik Kubernetes Setup Guide for complete installation details.
|
||||
|
||||
### Gateway API with TLS
|
||||
|
||||
Update your existing `HTTPRoute` to use the secured gateway listener:
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: traefik-gateway
|
||||
sectionName: websecure # The HTTPS listener
|
||||
hostnames:
|
||||
- "whoami.docker.localhost"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /api
|
||||
backendRefs:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
```
|
||||
|
||||
Update the file `whoami-route.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-route.yaml
|
||||
```
|
||||
|
||||
### IngressRoute with TLS
|
||||
|
||||
Update your existing IngressRoute to use TLS:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: whoami
|
||||
namespace: default
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure # Changed from 'web' to 'websecure'
|
||||
routes:
|
||||
- match: Host(`whoami.docker.localhost`) && Path(`/api`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami-api
|
||||
port: 80
|
||||
- match: Host(`whoami.docker.localhost`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
tls:
|
||||
secretName: whoami-tls # Added TLS configuration
|
||||
```
|
||||
|
||||
Update the file `whoami-ingressroute.yaml` and apply it:
|
||||
|
||||
```bash
|
||||
kubectl apply -f whoami-ingressroute.yaml
|
||||
```
|
||||
|
||||
### Verify HTTPS Access
|
||||
|
||||
Now you can access your service securely. Since we're using a self-signed certificate, you'll need to skip certificate verification:
|
||||
|
||||
```bash
|
||||
curl -k -H "Host: whoami.docker.localhost" https://localhost/
|
||||
```
|
||||
|
||||
Your browser can also access https://whoami.docker.localhost/ (you'll need to accept the security warning for the self-signed certificate).
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've mastered the basics of exposing services with Traefik on Kubernetes, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing.
|
||||
|
||||
Continue to the [Advanced Guide](advanced.md) to learn about:
|
||||
|
||||
- Adding middlewares for security and access control
|
||||
- Generating certificates with Let's Encrypt (IngressRoute) or cert-manager (Gateway API)
|
||||
- Configuring sticky sessions for stateful applications
|
||||
- Setting up multi-layer routing for authentication-based routing with IngressRoute
|
||||
@@ -17,6 +17,6 @@ Following these guides, you'll learn how to:
|
||||
|
||||
For detailed steps tailored to your environment, follow the guide for your platform:
|
||||
|
||||
- [Kubernetes](./kubernetes.md)
|
||||
- [Docker](./docker.md)
|
||||
- [Docker Swarm](./swarm.md)
|
||||
- [Kubernetes](./kubernetes/basic.md)
|
||||
- [Docker](./docker/basic.md)
|
||||
- [Docker Swarm](./swarm/basic.md)
|
||||
|
||||
@@ -1,186 +1,23 @@
|
||||
# Exposing Services with Traefik on Docker Swarm
|
||||
# Exposing Services with Traefik on Docker Swarm - Advanced
|
||||
|
||||
This guide will help you expose your services securely through Traefik Proxy using Docker Swarm. We'll cover routing HTTP and HTTPS traffic, implementing TLS, adding middlewares, Let's Encrypt integration, and sticky sessions.
|
||||
This guide builds on the concepts and setup from the [Basic Guide](basic.md). Make sure you've completed the basic guide and have a working Traefik setup with Docker Swarm before proceeding.
|
||||
|
||||
In this advanced guide, you'll learn how to enhance your Traefik deployment with:
|
||||
|
||||
- **Middlewares** for security headers and access control
|
||||
- **Let's Encrypt** for automated certificate management
|
||||
- **Sticky sessions** for stateful applications
|
||||
- **Multi-layer routing** for complex authentication scenarios
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Completed the [Basic Guide](basic.md)
|
||||
- Docker Swarm cluster initialized
|
||||
- Basic understanding of Docker Swarm concepts
|
||||
- Traefik deployed using the Traefik Docker Swarm Setup guide
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://hub.docker.com/r/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, update your existing `docker-compose.yml` file if you haven't already:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
deploy:
|
||||
replicas: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=web,websecure"
|
||||
```
|
||||
|
||||
Save this as `docker-compose.yml` and deploy the stack:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.swarm.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami.1.7c8f7tr56q3p949rscxrkp80e
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.0.1.8
|
||||
IP: fe80::215:5dff:fe00:c9e
|
||||
RemoteAddr: 10.0.1.2:45098
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.swarm.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.0.1.1
|
||||
X-Forwarded-Host: whoami.swarm.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: 5789f594e7d5
|
||||
X-Real-Ip: 10.0.1.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on [URL paths](../reference/routing-configuration/http/routing/rules-and-priority.md#path-pathprefix-and-pathregexp). This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
Update your `docker-compose.yml` to add another service:
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
|
||||
# New service
|
||||
whoami-api:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
deploy:
|
||||
replicas: 2
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Path-based routing
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.swarm.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=web,websecure"
|
||||
- "traefik.http.routers.whoami-api.service=whoami-api-svc"
|
||||
- "traefik.http.services.whoami-api-svc.loadbalancer.server.port=80"
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly.
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate and dynamic config file to tell Traefik where the cert lives:
|
||||
|
||||
```bash
|
||||
mkdir -p certs
|
||||
|
||||
# key + cert (valid for one year)
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout certs/local.key -out certs/local.crt \
|
||||
-subj "/CN=*.swarm.localhost"
|
||||
|
||||
# dynamic config that tells Traefik where the cert lives
|
||||
cat > certs/tls.yml <<'EOF'
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /certificates/local.crt
|
||||
keyFile: /certificates/local.key
|
||||
EOF
|
||||
```
|
||||
|
||||
Create a Docker config for the certificate files:
|
||||
|
||||
```bash
|
||||
docker config create swarm-cert.crt certs/local.crt
|
||||
docker config create swarm-cert.key certs/local.key
|
||||
docker config create swarm-tls.yml certs/tls.yml
|
||||
```
|
||||
|
||||
Update your `docker-compose.yml` file with the following changes:
|
||||
|
||||
```yaml
|
||||
# Add to the Traefik command section:
|
||||
command:
|
||||
# ... existing commands ...
|
||||
- "--entryPoints.websecure.address=:443"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Add to the root of your docker-compose.yml file:
|
||||
configs:
|
||||
swarm-cert.crt:
|
||||
file: ./certs/local.crt
|
||||
swarm-cert.key:
|
||||
file: ./certs/local.key
|
||||
swarm-tls.yml:
|
||||
file: ./certs/tls.yml
|
||||
```
|
||||
|
||||
Deploy the stack:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
Your browser can access https://whoami.swarm.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate.
|
||||
- Working Traefik setup from the basic guide
|
||||
|
||||
## Add Middlewares
|
||||
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
Middlewares allow you to modify requests or responses as they pass through Traefik. Let's add two useful middlewares: [Headers](../../reference/routing-configuration/http/middlewares/headers.md) for security and [IP allowlisting](../../reference/routing-configuration/http/middlewares/ipallowlist.md) for access control.
|
||||
|
||||
Add the following labels to your whoami service deployment section in `docker-compose.yml`:
|
||||
|
||||
@@ -189,7 +26,7 @@ deploy:
|
||||
# ... existing configuration ...
|
||||
labels:
|
||||
# ... existing labels ...
|
||||
|
||||
|
||||
# Secure Headers Middleware
|
||||
- "traefik.http.middlewares.secure-headers.headers.frameDeny=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.sslRedirect=true"
|
||||
@@ -198,10 +35,10 @@ deploy:
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsPreload=true"
|
||||
- "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000"
|
||||
|
||||
|
||||
# IP Allowlist Middleware
|
||||
- "traefik.http.middlewares.ip-allowlist.ipallowlist.sourceRange=127.0.0.1/32,192.168.0.0/16,10.0.0.0/8"
|
||||
|
||||
|
||||
# Apply the middlewares
|
||||
- "traefik.http.routers.whoami.middlewares=secure-headers,ip-allowlist"
|
||||
```
|
||||
@@ -332,7 +169,7 @@ deploy:
|
||||
# ... existing configuration ...
|
||||
labels:
|
||||
# ... existing labels ...
|
||||
|
||||
|
||||
# Sticky Sessions Configuration
|
||||
- "traefik.http.services.whoami.loadbalancer.sticky.cookie=true"
|
||||
- "traefik.http.services.whoami.loadbalancer.sticky.cookie.name=sticky_cookie"
|
||||
@@ -374,28 +211,195 @@ You should see different `Hostname` values in these responses, as each request i
|
||||
!!! important "Browser Testing"
|
||||
When testing in browsers, you need to use the same browser session to maintain the cookie. The cookie is set with `httpOnly` and `secure` flags for security, so it will only be sent over HTTPS connections and won't be accessible via JavaScript.
|
||||
|
||||
For more advanced configuration options, see the [reference documentation](../reference/routing-configuration/http/load-balancing/service.md).
|
||||
For more advanced configuration options, see the [reference documentation](../../reference/routing-configuration/http/load-balancing/service.md).
|
||||
|
||||
## Multi-Layer Routing
|
||||
|
||||
Multi-layer routing enables hierarchical relationships between routers, where parent routers can process requests through middleware before child routers make final routing decisions. This is particularly useful for authentication-based routing or staged middleware application.
|
||||
|
||||
!!! info "Provider Requirement"
|
||||
Multi-layer routing requires the File provider, as Docker Swarm labels do not support the `parentRefs` field. However, you can use **both Docker Swarm and File providers together** - Swarm labels for service discovery and File configuration for multi-layer routing.
|
||||
|
||||
### Setup Multi-Layer Routing with Docker Swarm
|
||||
|
||||
To use multi-layer routing with Docker Swarm, you need to enable the File provider alongside the Docker provider.
|
||||
|
||||
Update your Traefik service in `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v3.4
|
||||
command:
|
||||
- "--api.dashboard=true"
|
||||
- "--providers.docker.swarmMode=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--providers.docker.network=traefik_proxy"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic" # Enable File provider
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--entrypoints.websecure.http.tls=true"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
configs:
|
||||
- source: mlr-config
|
||||
target: /etc/traefik/dynamic/mlr.yml
|
||||
networks:
|
||||
- traefik_proxy
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
|
||||
configs:
|
||||
mlr-config:
|
||||
file: ./dynamic/mlr.yml
|
||||
|
||||
networks:
|
||||
traefik_proxy:
|
||||
external: true
|
||||
```
|
||||
|
||||
### Authentication-Based Routing Example
|
||||
|
||||
Let's create a multi-layer routing setup where a parent router authenticates requests, and child routers direct traffic based on user roles.
|
||||
|
||||
First, keep your Docker Swarm services defined with labels as usual:
|
||||
|
||||
```yaml
|
||||
# In docker-compose.yml
|
||||
services:
|
||||
# ... traefik service from above ...
|
||||
|
||||
# Admin backend service
|
||||
admin-backend:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=Admin Backend
|
||||
deploy:
|
||||
replicas: 2
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.admin-backend.loadbalancer.server.port=80"
|
||||
|
||||
# User backend service
|
||||
user-backend:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=User Backend
|
||||
deploy:
|
||||
replicas: 2
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.services.user-backend.loadbalancer.server.port=80"
|
||||
```
|
||||
|
||||
Now create the multi-layer routing configuration in a file. Create `dynamic/mlr.yml`:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
routers:
|
||||
# Parent router with authentication middleware
|
||||
api-parent:
|
||||
rule: "Host(`api.swarm.localhost`) && PathPrefix(`/api`)"
|
||||
middlewares:
|
||||
- auth-middleware
|
||||
entryPoints:
|
||||
- websecure
|
||||
# Note: No service and no TLS config - this is a parent router
|
||||
|
||||
# Child router for admin users
|
||||
api-admin:
|
||||
rule: "HeadersRegexp(`X-Auth-User`, `admin`)"
|
||||
service: admin-backend@swarm # Reference Swarm service
|
||||
parentRefs:
|
||||
- api-parent@file # Explicit reference to parent in file provider
|
||||
|
||||
# Child router for regular users
|
||||
api-user:
|
||||
rule: "HeadersRegexp(`X-Auth-User`, `user`)"
|
||||
service: user-backend@swarm # Reference Swarm service
|
||||
parentRefs:
|
||||
- api-parent@file # Explicit reference to parent in file provider
|
||||
|
||||
middlewares:
|
||||
auth-middleware:
|
||||
basicAuth:
|
||||
users:
|
||||
- "admin:$apr1$DmXR3Add$wfdbGw6RWIhFb0ffXMM4d0"
|
||||
- "user:$apr1$GJtcIY1o$mSLdsWYeXpPHVsxGDqadI."
|
||||
headerField: X-Auth-User
|
||||
```
|
||||
|
||||
!!! note "Generating Password Hashes"
|
||||
The password hashes above are generated using `htpasswd`. To create your own user credentials:
|
||||
|
||||
```bash
|
||||
# Using htpasswd (Apache utils)
|
||||
htpasswd -nb admin yourpassword
|
||||
```
|
||||
|
||||
!!! important "Cross-Provider References"
|
||||
Notice the `@swarm` suffix on service names and the `@file` suffix in `parentRefs`. When using the File provider to orchestrate multi-layer routing with Swarm services:
|
||||
|
||||
- Use `service-name@swarm` to reference Swarm services
|
||||
- Use `parent-name@file` in `parentRefs` to reference the parent router in the File provider
|
||||
|
||||
The `@provider` suffix tells Traefik which provider namespace to look in for the resource.
|
||||
|
||||
Deploy the stack:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
### Test Multi-Layer Routing
|
||||
|
||||
Test the routing behavior:
|
||||
|
||||
```bash
|
||||
# Request goes through parent router → auth middleware → admin child router
|
||||
curl -k -u admin:test -H "Host: api.swarm.localhost" https://localhost/api
|
||||
```
|
||||
|
||||
You should see the response from the admin-backend service when authenticating as `admin`. Try with `user:test` credentials to reach the user-backend service instead.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Request arrives** at `api.swarm.localhost/api`
|
||||
2. **Parent router** (`api-parent`) matches based on host and path
|
||||
3. **BasicAuth middleware** authenticates the user and sets the `X-Auth-User` header with the username
|
||||
4. **Child router** (`api-admin` or `api-user`) matches based on the header value
|
||||
5. **Request forwarded** to the appropriate Swarm service
|
||||
|
||||
For more details about multi-layer routing, see the [Multi-Layer Routing documentation](../../reference/routing-configuration/http/routing/multi-layer-routing.md).
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this guide, you've learned how to:
|
||||
In this advanced guide, you've learned how to:
|
||||
|
||||
- Expose HTTP services through Traefik in Docker Swarm
|
||||
- Set up path-based routing to direct traffic to different backend services
|
||||
- Secure your services with TLS using self-signed certificates
|
||||
- Add security with middlewares like secure headers and IP allow listing
|
||||
- Automate certificate management with Let's Encrypt
|
||||
- Implement sticky sessions for stateful applications
|
||||
- Setup multi-layer routing for authentication-based routing
|
||||
|
||||
These fundamental capabilities provide a solid foundation for exposing any application through Traefik Proxy in Docker Swarm. Each of these can be further customized to meet your specific requirements.
|
||||
These advanced capabilities allow you to build production-ready Traefik deployments with Docker Swarm. Each of these can be further customized to meet your specific requirements.
|
||||
|
||||
### Next Steps
|
||||
|
||||
Now that you understand the basics of exposing services with Traefik Proxy, you might want to explore:
|
||||
Now that you've mastered both basic and advanced Traefik features with Docker Swarm, you might want to explore:
|
||||
|
||||
- [Advanced routing options](../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Docker provider documentation](../reference/install-configuration/providers/docker.md) for more details about the Docker integration
|
||||
- [Advanced routing options](../../reference/routing-configuration/http/routing/rules-and-priority.md) like query parameter matching, header-based routing, and more
|
||||
- [Additional middlewares](../../reference/routing-configuration/http/middlewares/overview.md) for authentication, rate limiting, and request modifications
|
||||
- [Observability features](../../reference/install-configuration/observability/metrics.md) for monitoring and debugging your Traefik deployment
|
||||
- [TCP services](../../reference/routing-configuration/tcp/service.md) for exposing TCP services
|
||||
- [UDP services](../../reference/routing-configuration/udp/service.md) for exposing UDP services
|
||||
- [Docker provider documentation](../../reference/install-configuration/providers/docker.md) for more details about the Docker integration
|
||||
@@ -0,0 +1,191 @@
|
||||
# Exposing Services with Traefik on Docker Swarm - Basic
|
||||
|
||||
This guide will help you get started with exposing your services through Traefik Proxy using Docker Swarm. You'll learn the fundamentals of routing HTTP traffic, setting up path-based routing, and securing your services with TLS.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Swarm cluster initialized
|
||||
- Basic understanding of Docker Swarm concepts
|
||||
- Traefik deployed using the [Traefik Docker Swarm Setup guide](../../setup/swarm.md)
|
||||
|
||||
|
||||
## Expose Your First HTTP Service
|
||||
|
||||
Let's expose a simple HTTP service using the [whoami](https://hub.docker.com/r/traefik/whoami) application. This will demonstrate basic routing to a backend service.
|
||||
|
||||
First, update your existing `docker-compose.yml` file if you haven't already:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
whoami:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
deploy:
|
||||
replicas: 3
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.whoami.rule=Host(`whoami.swarm.localhost`)"
|
||||
- "traefik.http.routers.whoami.entrypoints=web,websecure"
|
||||
```
|
||||
|
||||
Save this as `docker-compose.yml` and deploy the stack:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
### Verify Your Service
|
||||
|
||||
Your service is now available at http://whoami.swarm.localhost/. Test that it works:
|
||||
|
||||
```bash
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/
|
||||
```
|
||||
|
||||
You should see output similar to:
|
||||
|
||||
```bash
|
||||
Hostname: whoami.1.7c8f7tr56q3p949rscxrkp80e
|
||||
IP: 127.0.0.1
|
||||
IP: ::1
|
||||
IP: 10.0.1.8
|
||||
IP: fe80::215:5dff:fe00:c9e
|
||||
RemoteAddr: 10.0.1.2:45098
|
||||
GET / HTTP/1.1
|
||||
Host: whoami.swarm.localhost
|
||||
User-Agent: curl/7.68.0
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip
|
||||
X-Forwarded-For: 10.0.1.1
|
||||
X-Forwarded-Host: whoami.swarm.localhost
|
||||
X-Forwarded-Port: 80
|
||||
X-Forwarded-Proto: http
|
||||
X-Forwarded-Server: 5789f594e7d5
|
||||
X-Real-Ip: 10.0.1.1
|
||||
```
|
||||
|
||||
This confirms that Traefik is successfully routing requests to your whoami application.
|
||||
|
||||
## Add Routing Rules
|
||||
|
||||
Now we'll enhance our routing by directing traffic to different services based on [URL paths](../../reference/routing-configuration/http/routing/rules-and-priority.md#path-pathprefix-and-pathregexp). This is useful for API versioning, frontend/backend separation, or organizing microservices.
|
||||
|
||||
Update your `docker-compose.yml` to add another service:
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
|
||||
# New service
|
||||
whoami-api:
|
||||
image: traefik/whoami
|
||||
networks:
|
||||
- traefik_proxy
|
||||
environment:
|
||||
- WHOAMI_NAME=API Service
|
||||
deploy:
|
||||
replicas: 2
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Path-based routing
|
||||
- "traefik.http.routers.whoami-api.rule=Host(`whoami.swarm.localhost`) && PathPrefix(`/api`)"
|
||||
- "traefik.http.routers.whoami-api.entrypoints=web,websecure"
|
||||
- "traefik.http.routers.whoami-api.service=whoami-api-svc"
|
||||
- "traefik.http.services.whoami-api-svc.loadbalancer.server.port=80"
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
Apply the changes:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
### Test the Path-Based Routing
|
||||
|
||||
Verify that different paths route to different services:
|
||||
|
||||
```bash
|
||||
# Root path should go to the main whoami service
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/
|
||||
|
||||
# /api path should go to the whoami-api service
|
||||
curl -H "Host: whoami.swarm.localhost" http://localhost/api
|
||||
```
|
||||
|
||||
For the `/api` requests, you should see the response showing "API Service" in the environment variables section, confirming that your path-based routing is working correctly.
|
||||
|
||||
## Enable TLS
|
||||
|
||||
Let's secure our service with HTTPS by adding TLS. We'll start with a self-signed certificate for local development.
|
||||
|
||||
### Create a Self-Signed Certificate
|
||||
|
||||
Generate a self-signed certificate and dynamic config file to tell Traefik where the cert lives:
|
||||
|
||||
```bash
|
||||
mkdir -p certs
|
||||
|
||||
# key + cert (valid for one year)
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout certs/local.key -out certs/local.crt \
|
||||
-subj "/CN=*.swarm.localhost"
|
||||
|
||||
# dynamic config that tells Traefik where the cert lives
|
||||
cat > certs/tls.yml <<'EOF'
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /certificates/local.crt
|
||||
keyFile: /certificates/local.key
|
||||
EOF
|
||||
```
|
||||
|
||||
Create a Docker config for the certificate files:
|
||||
|
||||
```bash
|
||||
docker config create swarm-cert.crt certs/local.crt
|
||||
docker config create swarm-cert.key certs/local.key
|
||||
docker config create swarm-tls.yml certs/tls.yml
|
||||
```
|
||||
|
||||
Update your `docker-compose.yml` file with the following changes:
|
||||
|
||||
```yaml
|
||||
# Add to the Traefik command section:
|
||||
command:
|
||||
# ... existing commands ...
|
||||
- "--entryPoints.websecure.address=:443"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
```
|
||||
|
||||
```yaml
|
||||
# Add to the root of your docker-compose.yml file:
|
||||
configs:
|
||||
swarm-cert.crt:
|
||||
file: ./certs/local.crt
|
||||
swarm-cert.key:
|
||||
file: ./certs/local.key
|
||||
swarm-tls.yml:
|
||||
file: ./certs/tls.yml
|
||||
```
|
||||
|
||||
Deploy the stack:
|
||||
|
||||
```bash
|
||||
docker stack deploy -c docker-compose.yml traefik
|
||||
```
|
||||
|
||||
Your browser can access https://whoami.swarm.localhost/ for the service. You'll need to accept the security warning for the self-signed certificate.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've mastered the basics of exposing services with Traefik on Docker Swarm, you're ready to explore more advanced features like middlewares, Let's Encrypt certificates, sticky sessions, and multi-layer routing.
|
||||
|
||||
Continue to the [Advanced Guide](advanced.md) to learn about:
|
||||
|
||||
- Adding middlewares for security and access control
|
||||
- Generating certificates with Let's Encrypt
|
||||
- Configuring sticky sessions for stateful applications
|
||||
- Setting up multi-layer routing for authentication-based routing
|
||||
+19
-9
@@ -136,12 +136,16 @@ plugins:
|
||||
'middlewares/tcp/ipwhitelist.md': 'reference/routing-configuration/tcp/middlewares/ipallowlist.md'
|
||||
'middlewares/tcp/ipallowlist.md': 'reference/routing-configuration/tcp/middlewares/ipallowlist.md'
|
||||
## User Guides
|
||||
'user-guides/crd-acme/index.md': 'expose/kubernetes.md'
|
||||
'user-guides/cert-manager.md': 'expose/kubernetes.md'
|
||||
'user-guides/docker-compose/basic-example/index.md': 'expose/docker.md'
|
||||
'user-guides/docker-compose/acme-tls/index.md': 'expose/docker.md'
|
||||
'user-guides/docker-compose/acme-http/index.md': 'expose/docker.md'
|
||||
'user-guides/docker-compose/acme-dns/index.md': 'expose/docker.md'
|
||||
'user-guides/crd-acme/index.md': 'expose/kubernetes/basic.md'
|
||||
'user-guides/cert-manager.md': 'expose/kubernetes/advanced.md'
|
||||
'user-guides/docker-compose/basic-example/index.md': 'expose/docker/basic.md'
|
||||
'user-guides/docker-compose/acme-tls/index.md': 'expose/docker/advanced.md'
|
||||
'user-guides/docker-compose/acme-http/index.md': 'expose/docker/advanced.md'
|
||||
'user-guides/docker-compose/acme-dns/index.md': 'expose/docker/advanced.md'
|
||||
## Expose pages (redirect old URLs to new structure)
|
||||
'expose/kubernetes.md': 'expose/kubernetes/basic.md'
|
||||
'expose/docker.md': 'expose/docker/basic.md'
|
||||
'expose/swarm.md': 'expose/swarm/basic.md'
|
||||
# References
|
||||
# Static Configuration
|
||||
'reference/static-configuration/overview.md': 'reference/install-configuration/configuration-options.md'
|
||||
@@ -201,9 +205,15 @@ nav:
|
||||
- 'Swarm': 'setup/swarm.md'
|
||||
- 'Expose':
|
||||
- 'Overview': 'expose/overview.md'
|
||||
- 'Kubernetes': 'expose/kubernetes.md'
|
||||
- 'Docker': 'expose/docker.md'
|
||||
- 'Swarm': 'expose/swarm.md'
|
||||
- 'Kubernetes':
|
||||
- 'Basic': 'expose/kubernetes/basic.md'
|
||||
- 'Advanced': 'expose/kubernetes/advanced.md'
|
||||
- 'Docker':
|
||||
- 'Basic': 'expose/docker/basic.md'
|
||||
- 'Advanced': 'expose/docker/advanced.md'
|
||||
- 'Swarm':
|
||||
- 'Basic': 'expose/swarm/basic.md'
|
||||
- 'Advanced': 'expose/swarm/advanced.md'
|
||||
- 'Secure':
|
||||
- '<span class="nav-link-with-icon">Secure Access with JWT <img src="https://doc.traefik.io/traefik-hub/img/ps-traefik-hub-logo-light.svg" class="menu-icon" alt="Traefik Hub API Gateway"></span>': 'secure/secure-api-access-with-jwt.md'
|
||||
- '<span class="nav-link-with-icon">Secure Access with OIDC <img src="https://doc.traefik.io/traefik-hub/img/ps-traefik-hub-logo-light.svg" class="menu-icon" alt="Traefik Hub API Gateway"></span>': 'secure/secure-api-access-with-oidc.md'
|
||||
|
||||
Reference in New Issue
Block a user