Hi guys,
I created both stacks below, which I am able to access using domain n8n.example.com
. My manager idea is exposing different ports and host different instances with same domain to allow n8n.example.com:5679
, n8n.example.com:5680
and so on, instead of registering the subdomain on respective provider. On other file "n8n.yaml", by changing every referencen8n
to "n8n_n", as well as free port "5679 + n", we can host the instance 'n'. But I am not being able to access using protocol https, only http (http://n8n.example.com:$((5679 + n))
). Can you understand my use case? Is it reasonable?
docker stack deploy --prune --resolve-image always -c traefik.yaml traefik
docker stack deploy --prune --resolve-image always -c n8n.yaml n8n
traefik.yaml:
services:
traefik:
image: traefik:v3.2.3
command:
- "--api.dashboard=true"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik_network"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.transport.respondingTimeouts.idleTimeout=3600"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/letsencrypt/acme.json"
- "--certificatesresolvers.letsencryptresolver.acme.email=josezago@suasvendas.com.br"
- "--log.level=DEBUG"
- "--log.format=common"
- "--log.filePath=/var/log/traefik/traefik.log"
- "--accesslog=true"
- "--accesslog.filepath=/var/log/traefik/access-log"
volumes:
- "vol_certificates:/etc/traefik/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- traefik_network
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
volumes:
vol_certificates:
external: true
name: volume_certificates
networks:
traefik_network:
external: true
attachable: true
name: traefik_network
n8n.yaml:
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=postgres
- DB_POSTGRESDB_PASSWORD=mysecrepwd_shh
- N8N_SECURE_COOKIE=false
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=me@example.com
- N8N_BASIC_AUTH_PASSWORD=me@example.com
- N8N_PROTOCOL=https
- N8N_PORT=5678
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(n8n.example.com)"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
- "traefik.http.routers.n8n.entrypoints=https"
- "traefik.http.routers.n8n.tls=true"
- "traefik.http.routers.n8n.tls.certresolver=default"
- "traefik.http.routers.n8n.middlewares=redirect-to-https"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
ports:
- "5679:5678"
networks:
- "traefik_network"
volumes:
- n8n-data-zaff:/home/node/.n8n
volumes:
n8n-data:
networks:
traefik_network:
external: true
name: "traefik_network"
You want to proxy via Traefik, so you need to publish the additional ports
on Traefik container, create additional Traefik entrypoints
in static config and assign them to the according router
in dynamic config (labels).
Could you please provide the new content of file traefik.yaml
with an additional port, for example, 5679
?
Example with 3 Traefik entrypoints
.
1 Like
Does it apply when the dockerized application port differs from exposed port? My questions are:
- On the example, let us say the application uses 9000, but exposes 9001. How should it be set up? Should we expose port 9001 at all like below?
ports:
- "9001:9000"
- Even not defining a target like below, should we still be able to direct the incoming traffic from
tcp.example.com:9001
to the application, and other targets defined tcp.example.com:9002
as well?
- I see, the example defines different subdomains to each service. How could we define uniquelu the domain, but differ by accessing the port?
Usually Traefik is using a Docker network to connect to target services. Within, publishing ports has no impact, you connect to the original port of the app.
If you want to use different ports, you need to publish them on the Traefik container and create additional entrypoints
in static config.
Ok, let me get that right: on example [1] you provided, we define a line - --entryPoints.tcp-plain.address=:$PORT
on property command
AND the port on property ports
. Right?
- target: $PORT
published: $PORT
protocol: tcp
mode: host
On my small use case, I want to access as url https://subdomain.domain.com:$PORT
multiple instances, since multiple subdomains would require multiple registrations on DNS provider (laziness detected). The internal port is the same, but the access port is different though. How will Swarm differ between the applications if the internal port is the same? It is similar to, example, having multiple Postgres with internal port as 5432 and exposing some other 54XX.
Am I clear?
[1] traefik-best-practice/docker-traefik-tcp/docker-compose.yml at main · bluepuma77/traefik-best-practice · GitHub
Yes, publish port and add entrypoint
.
If you have different entrypoints
, then you can setup different routers
listening to them (exclusively).
If you then simply proxy/forward them to a target service, they could look very alike, except for X-Forwarded-Port
header.
Great! I promess this is the last question, yes!? Since I prefer the all-in-one configuration file, how would a target be defined with header X-Forwarded-Port
? Despite well-documented, development requires too much experimentation for me to .
I understand we define a new entrypoint
, expose the port
on same file, define a router
on respective service compose file and forward to the respective port service
. Ok, so using a single entrypoint pointing to same port allows us to say to Traefik: "Look, we have an entrypoint for services with this port, but we will forward to correct port". The next question is: How?
Can you re-phrase your question?
A port is used by an entrypoint
. A router
can be assigned to one or more entrypoints
. A service
can be assigned to one or more routers
.
Maybe have a look at this post.
If you use different ports and entrypoints
with the same router
and same service:
https://sub.example.com/
https://sub.example.com:8443/
then the target service can only figure out by request header which one was used.
Of course you can setup different routers
, middlewares
and services
for each port/entrypoint
.
The images on documentation clarify much, but the syntax is somewhat confusing. Traefik works as a front entity, an API gateway. I am able to deploy the application with the desired ports like 3001, 3002, 3003, assign the desired port to respective new entrypoints and also each entrypoint to the service, for example. Can I assign entrypoint custom-port AND websecure? Is this the way how I just use traefik setup to access the 2 different services 3000 and 3001 only by url without modifying the header? I will keep studying the documentation.
You don’t need to modify headers, they will automatically be supplied.
You can assign multiple entrypoints
to the same router
.
Great !! In summary, to add new service with port accessed websecure url, we:
- Create new
entrypoint
on property command
, enable respective tls
and expose application port
on property ports
on traefik compose;
- Define router host, assign tls-secured custom entrypoint to router, add port to service load balancer, change the internal on app port to the exposed port on traefik;
- Re-deploy traefik and deploy service composes.
Anything else, like enabling tls or certificate resolvers, right?
Thanks for your patience.
@bluepuma77 Update: I performed the suggestions above, but still am unable to access the service through domain https://n8n.example.com:5681
. A (unwanted) workaround is exposing on service compose the port, making me able to access http://n8n.example.com:5681
, but neglecting traefik safety (tears). Would you reproduce an example with service whoami
allowing https instead?
Share your full Traefik static and dynamic config, and docker-compose.yml
if used.
Here it is. BUT I GOT IT CORRECTLY!!!! THANKS!!
traefik.yaml
:
services:
traefik:
image: traefik:v3.2.3
hostname: '{{.Node.Hostname}}'
command:
- "--api.dashboard=true"
- "--log.level=INFO"
- "--providers.swarm.exposedByDefault=false"
- "--providers.swarm.network=traefik_network"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.asDefault=true"
- "--entrypoints.n8n_5679.address=:5679"
- "--entrypoints.n8n_5679.http.tls=true"
- "--entrypoints.n8n_5680.address=:5680"
- "--entrypoints.n8n_5680.http.tls=true"
- "--entrypoints.n8n_5681.address=:5681"
- "--entrypoints.n8n_5681.http.tls=true"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true"
- "--certificatesresolvers.letsencryptresolver.acme.tlschallenge=true"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencryptresolver.acme.storage=/etc/traefik/letsencrypt/acme.json"
- "--certificatesresolvers.letsencryptresolver.acme.email=`mailme@mail.com"
- "--log.format=common"
- "--log.filePath=/var/log/traefik/traefik.log"
- "--accesslog=true"
- "--accesslog.filepath=/var/log/traefik/access-log"
restart: unless-stopped
security_opt:
- no-new-privileges:true
deploy:
mode: global
placement:
constraints:
- node.role==manager
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.app.com`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls.certresolver=letsencryptresolver"
- "traefik.http.services.dummy-svc.loadbalancer.server.port=9999"
- "traefik.http.routers.dashboard.middlewares=myauth"
- "traefik.http.middlewares.myauth.basicauth.users=test:hashed_password"
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "vol_certificates:/etc/traefik/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- traefik_network
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
- target: 5679
published: 5679
mode: host
- target: 5680
published: 5680
mode: host
- target: 5681
published: 5681
mode: host
volumes:
vol_certificates:
external: true
name: volume_certificates
networks:
traefik_network:
attachable: true
name: traefik_network
Custom n8n:
services:
n8n_5680:
image: n8nio/n8n:latest
environment:
## Database configuration
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n_5680
- DB_POSTGRESDB_USER=postgres
- DB_POSTGRESDB_PASSWORD=postgres
# Authentication for the editor UI
- N8N_SECURE_COOKIE=false
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=n8n@mail.com
- N8N_BASIC_AUTH_PASSWORD=secret_password_shh
- N8N_PROTOCOL=https
- N8N_HOST=localhost
- N8N_PORT=5680
- WEBHOOK_URL=https://customer.app.com:5680
# Execution settings
- EXECUTIONS_MODE=queue
## Redis settings
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_DB=2
- NODE_FUNCTION_ALLOW_EXTERNAL=moment,lodash,moment-with-locales
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=336
## Community Nodes
- N8N_REINSTALL_MISSING_PACKAGES=true
- N8N_COMMUNITY_PACKAGES_ENABLED=true
- N8N_NODE_PATH=/home/node/.n8n/nodes
## Timezone
- GENERIC_TIMEZONE=America/Sao_Paulo
- TZ=America/Sao_Paulo
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
resources:
limits:
cpus: "1"
memory: 1024M
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n_5680.rule=Host(`customer.app.com`)"
- "traefik.http.services.n8n_5680.loadbalancer.server.port=5680"
- "traefik.http.routers.n8n_5680.entrypoints=websecure,n8n_5680"
- "traefik.http.routers.n8n_5680.tls=true"
- "traefik.http.routers.n8n_5680.tls.certresolver=default"
networks:
- "traefik_network"
volumes:
- n8n-data-zaff:/home/node/.n8n
volumes:
n8n-data-zaff:
networks:
traefik_network:
external: true
name: "traefik_network"
Great when it works
I would assign the certResolver directly in entrypoints
. No need for tls=true
when you assign a certResolver.
And I would assume that only one method (httpChallenge
, tlsChallenge
) is used.
1 Like
I don't know how to assign the certResolver directly on entrypoint. I removed the tls flag, and also httpChallenge.
It's probably in most examples I provide
- --entryPoints.websecure.address=:443
- --entrypoints.websecure.http.tls.certresolver=myresolver
1 Like
I will be back with more questions in the future. Beware!