Multi-user Docker Environment

Hi there,

We’ve been evaluating n8n for our team (internal use, no monetary gain) and think it’s going to be a fantastic fit for us. We’ve developed a node to leverage z/OSMF APIs (IBM Mainframe) to automate manual work. Since only a small subset of our team is familiar with the technology required to get n8n running, we were hoping to simplify the “barriers of entry” to get n8n available for each member our team.

For us, the ideal environment would be the following:

  • One Server running Docker
  • One Docker Container running Nginx
  • Many Docker Containers running n8n (one per user)

The Nginx configuration would have multiple proxy_pass statements for each user:

location /user1 {
	proxy_pass <user1 container>
}
location /user2 {
	proxy_pass <user2 container>
}
...

User1 would go to example.com/user1 and be connected to their instance, User2 would go to example.com/user2 and be connected to their instance, and so on.

I’m definitely oversimplifying the configuration/structure for discussion purposes but unfortunately we cannot get n8n working in this kind of environment. No matter what combination of Nginx configuration/n8n environment variables we try, we cannot get n8n to work properly.

Has anyone successfully set up a multi-user environment like this or possibly provide some advice on the proper configuration details to get this working?

Appreciate any and all advice/feedback. Thank you so much!

1 Like

Great to hear that you think n8n could be helpful for your team.

We are running multiple n8n instances in a more or less identical setup as described here:

We run it however not with docker-compose but in docker-swarm instead.

The main things you would have to change for each user is:

  • the name of the service (instead of “n8n” for example “n8n-jan”)
  • subdomain
  • folder to save the data to
  • a different user/password for authentication

If you want to run n8n in a subfolder you can check out this posts where community members describe how they did it.

It is on our roadmap to add proper user-management which will then also make that simpler in the future.

I hope that helps!

1 Like

Thank you @jan! Following the n8n server setup URL above helped with setting up multiple instances, each with their own URL. For now, this will do. We might revisit to see what needs to be done if we want the same URL but a different URI (example.com/user1, example.com/user2, etc.) but that’s a stretch goal at this point. I’ll mark this complete. Thanks again!

@Ian_Taggart Can you share how to install on sub folder like you’ve done? I’ve install on subdomain n8n.example.com successfully, now I want to install on multi subfolder like this: n8n.example.com/user1, n8n.example.com/user2… but not successful, when install, it shows error like this

root@n8n:~/n8n/0680# sudo docker-compose up -d
Creating network "0680_default" with the default driver
Creating 0680_n8n_1 ...
Creating 0680_n8n_1     ... error
WARNING: Host is already in use by another container

ERROR: for 0680_n8n_1  Cannot start service n8n: driver failed programming external connectivity on endpoint 0680_n8n_1 (0b6bddaa755ea252aaff35efea33b5e56654df87fc83b74e3e343c2a1d231e49): Bind for 127.0.0.1:5678 failed: port is already allocated
Creating 0680_traefik_1 ... error

ERROR: for 0680_traefik_1  Cannot start service traefik: driver failed programming external connectivity on endpoint 0680_traefik_1 (2947261f7ac88b9c2d3b3fd217d03ad3f8ba5a75765bb9823c775d6a3e52e5cb): Bind for 0.0.0.0:443 failed: port is already allocated

ERROR: for n8n  Cannot start service n8n: driver failed programming external connectivity on endpoint 0680_n8n_1 (0b6bddaa755ea252aaff35efea33b5e56654df87fc83b74e3e343c2a1d231e49): Bind for 127.0.0.1:5678 failed: port is already allocated

ERROR: for traefik  Cannot start service traefik: driver failed programming external connectivity on endpoint 0680_traefik_1 (2947261f7ac88b9c2d3b3fd217d03ad3f8ba5a75765bb9823c775d6a3e52e5cb): Bind for 0.0.0.0:443 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.
root@n8n:~/n8n/0680# sudo docker-compose up -d
Starting 0680_traefik_1 ...
Starting 0680_traefik_1 ... error
WARNING: Host is already in use by another container

ERROR: for 0680_traefik_1  Cannot start service traefik: driver failed programming external connectivity on endpoint 0680_traefik_1 (2dcf303d7bca44e5cf84bf1606182b8d022e78d645dcc180f6bada4e8c331d0c): Bind for 0.0.0.0:443 failed: port is already allocated
Recreating 0680_n8n_1   ... error

ERROR: for 0680_n8n_1  Cannot start service n8n: driver failed programming external connectivity on endpoint 0680_n8n_1 (d114ca17ffb45285b3ac93a8ee8e4f6765fc5b337af2fadbbfea440b7975e47d): Bind for 127.0.0.1:5678 failed: port is already allocated

ERROR: for traefik  Cannot start service traefik: driver failed programming external connectivity on endpoint 0680_traefik_1 (2dcf303d7bca44e5cf84bf1606182b8d022e78d645dcc180f6bada4e8c331d0c): Bind for 0.0.0.0:443 failed: port is already allocated

ERROR: for n8n  Cannot start service n8n: driver failed programming external connectivity on endpoint 0680_n8n_1 (d114ca17ffb45285b3ac93a8ee8e4f6765fc5b337af2fadbbfea440b7975e47d): Bind for 127.0.0.1:5678 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.

Please show me how to fix, thank you!

Hi @huuich, sorry for the confusion here! I was not actually able to figure out how to host multiple n8n instances from one URL with “subfolders” as you described above. It seems as though n8n is trying to use relative paths when loading the various html files so they never try and look for it in the right location. We had to spin up individual n8n instances in individual ec2 servers, each with their own URL in order for it to work correctly. Multiple n8n instances under one URL is definitely something that we want as well but cannot figure it out so we did this as a workaround until we do.

It is now properly possible to run n8n in a subfolder with [email protected]

Here an example:

1 Like

Hi @jan

I tried the subfolderwithSSL using docker-compose up -d and it shows

Starting subfolderwithssl_n8n_1     ... done
Starting subfolderwithssl_traefik_1 ... done

but when I visit IP:443 it shows 404 Page Not Found.
Also tried visiting Port 80, 5678 but dont know where the n8n is running.

Also checked with docker image ls

ubuntu@ubuntu:~/n8n/docker/compose/subfolderWithSSL$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
n8nio/n8n           latest              d4b87c6f9d89        4 days ago          359MB
traefik             latest              c6e6fde07226        11 days ago         78.4MB

I just checked. For some reason did WEBHOOK_TUNNEL_URL and VUE_APP_URL_BASE_API use http instead of https. Fixed that now. Apart from that did it look OK on the first sight.

One thing you wrote was: but when I visit IP:443 it shows 404 Page Not Found.

You have to make sure to not visit “IP:443” you have to visit your configured domain with subfolder. So for example: https://example.com/n8n

Hi @jan

Thanks, currently the n8n is working on the given subfolder, for the first time. but how do we create multiple instances ? I tried creating another subfolder in it but didnt work. Could you let me know what path should the subfolders should be created and what should it contain.

So to recreate the flow,

  1. I cloned the latest Repo
  2. cd to n8n/docker/compose/subfolderWithSSL
  3. Changed .env File
  4. Ran docker-compose up -d

If you need different ones you would have to copy the “n8n” part of the docker-compose file multiple times. But then make sure that you rename it and that you then best hard-code all the variables like N8N_PATH/SUBFOLDER, everything authentication related, … (so everything which should not be the same between the deployments).

Hi @jan
I added this to the docker-compose.yml file and also hardcoded some of the variables.

  n8n2:
image: n8nio/n8n
ports:
  - "127.0.0.1:5676:5676"
labels:
  - traefik.enable=true
  - traefik.http.routers.n8n.rule=Host(`${DOMAIN_NAME}`)
  - traefik.http.routers.n8n.tls=true
  - traefik.http.routers.n8n.entrypoints=websecure
  - "traefik.http.routers.n8n.rule=PathPrefix(`/asit{regex:$$|/.*}`)"
  - "traefik.http.middlewares.n8n-stripprefix.stripprefix.prefixes=/asit"
  - "traefik.http.routers.n8n.middlewares=n8n-stripprefix"
  - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
  - traefik.http.middlewares.n8n.headers.SSLRedirect=true
  - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
  - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
  - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
  - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
  - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
  - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
  - traefik.http.middlewares.n8n.headers.STSPreload=true
environment:
  - N8N_BASIC_AUTH_ACTIVE=false
  - N8N_BASIC_AUTH_USER
  - N8N_BASIC_AUTH_PASSWORD
  - N8N_HOST=${DOMAIN_NAME}
  - N8N_PORT=5676
  - N8N_PROTOCOL=https
  - NODE_ENV=production
  - N8N_PATH
  - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}/asit/
  - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}/asit/
volumes:
  - /var/run/docker.sock:/var/run/docker.sock
  - ${DATA_FOLDER}/.n8n:/root/.n8n

When I did docker-compose up -d it ran without any error but when I open the path in browser it shows

404 Page not found.

Even the app1 subfolder page which was working earlier didnt work after adding this. I had changed the ports of n8n2 but when I ran docker-compose ps it shows this

ubuntu@ubuntu:~/n8n/docker/compose/subfolderWithSSL$ docker-compose ps
           Name                         Command               State                    Ports
--------------------------------------------------------------------------------------------------------------
subfolderwithssl_n8n2_1      tini -- /docker-entrypoint.sh    Up      127.0.0.1:5676->5676/tcp, 5678/tcp
subfolderwithssl_n8n_1       tini -- /docker-entrypoint.sh    Up      127.0.0.1:5678->5678/tcp
subfolderwithssl_traefik_1   /entrypoint.sh --api=true  ...   Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

In the n8n2 it still shows port 5678, is it because of that ?

Hi @jan
Do you know how we can fix this ? Just able to run 1 subfolder and not multiple.

Hi @Asit_Joshi, I think what’s happening here is that the labels between the n8n instances are conflicting. Try these labels on the n8n2 instance:

labels:
 - traefik.enable=true
 - traefik.http.routers.n8n2.rule=Host(`${DOMAIN_NAME}`)
 - traefik.http.routers.n8n2.tls=true
 - traefik.http.routers.n8n2.entrypoints=websecure
 - "traefik.http.routers.n8n2.rule=PathPrefix(`/asit{regex:$$|/.*}`)"
 - "traefik.http.middlewares.n8n2-stripprefix.stripprefix.prefixes=/asit"
 - "traefik.http.routers.n8n2.middlewares=n8n2-stripprefix"
 - traefik.http.routers.n8n2.tls.certresolver=mytlschallenge
 - traefik.http.middlewares.n8n2.headers.SSLRedirect=true
 - traefik.http.middlewares.n8n2.headers.STSSeconds=315360000
 - traefik.http.middlewares.n8n2.headers.browserXSSFilter=true
 - traefik.http.middlewares.n8n2.headers.contentTypeNosniff=true
 - traefik.http.middlewares.n8n2.headers.forceSTSHeader=true
 - traefik.http.middlewares.n8n2.headers.SSLHost=${DOMAIN_NAME}
 - traefik.http.middlewares.n8n2.headers.STSIncludeSubdomains=true
 - traefik.http.middlewares.n8n2.headers.STSPreload=true

Notice the references in these two lines, this tripped us up until we caught it:

  • “traefik.http.middlewares.n8n2-stripprefix.stripprefix.prefixes=/asit”
  • “traefik.http.routers.n8n2.middlewares=n8n2-stripprefix

Hi @Ian_Taggart, have you tried multiple instances with subfolder ?

Hi, sorry for the accidental tag - please see above for my edit and info.

So yes, we were able to get it working within a controlled environment but we don’t have the ability to reach out to LetsEncrypt so we had to remove all of the labels related to SSL. But we did get it to work! We experienced the same issues that you did when moving from one n8n instance to more than one (it worked, and now none of them work). We were only able to get it to work by making the traefik labels unique among the instances.

Try that and let us know how it goes. Also, it might be helpful if you put your entire docker-compose file in here for reference.

2 Likes

Hi @Ian_Taggart

Thanks I was able to host multiple instances with SSL but there is a problem that there is only one database which can be accessed from any user. so for example I have created a credential from user1, then it is user2 can also see those in his credentials.

Here is my whole docker-compose.yml file

version: "3"
services:
  traefik:
    image: "traefik"
    command:
      - "--api=true"
      - "--api.insecure=true"
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
    ports:
      - "443:443"
      - "80:80"
    volumes:
      - ${DATA_FOLDER}/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
  n8n:
    image: n8nio/n8n
    ports:
      - "127.0.0.1:5678:5678"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=websecure
      - "traefik.http.routers.n8n.rule=PathPrefix(`/${SUBFOLDER}{regex:$$|/.*}`)"
      - "traefik.http.middlewares.n8n-stripprefix.stripprefix.prefixes=/${SUBFOLDER}"
      - "traefik.http.routers.n8n.middlewares=n8n-stripprefix"
      - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER
      - N8N_BASIC_AUTH_PASSWORD
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - N8N_PATH
      - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}${N8N_PATH}
      - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}${N8N_PATH}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/root/.n8n

  n8n3:
    image: n8nio/n8n
    ports:
      - "127.0.0.1:5600:5600"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n3.rule=Host(`${DOMAIN_NAME}`)
      - traefik.http.routers.n8n3.tls=true
      - traefik.http.routers.n8n3.entrypoints=websecure
      - "traefik.http.routers.n8n3.rule=PathPrefix(`/test{regex:$$|/.*}`)"
      - "traefik.http.middlewares.n8n3-stripprefix.stripprefix.prefixes=/test"
      - "traefik.http.routers.n8n3.middlewares=n8n3-stripprefix"
      - traefik.http.routers.n8n3.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n3.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n3.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n3.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n3.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n3.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n3.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n3.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n3.headers.STSPreload=true
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER="admin1"
      - N8N_BASIC_AUTH_PASSWORD="pass1"
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PORT=5600
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - N8N_PATH=/test/
      - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}/test/
      - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}/test/
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/root/.n8n

  n8n5:
    image: n8nio/n8n
    ports:
      - "127.0.0.1:5601:5601"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n5.rule=Host(`${DOMAIN_NAME}`)
      - traefik.http.routers.n8n5.tls=true
      - traefik.http.routers.n8n5.entrypoints=websecure
      - "traefik.http.routers.n8n5.rule=PathPrefix(`/test2{regex:$$|/.*}`)"
      - "traefik.http.middlewares.n8n5-stripprefix.stripprefix.prefixes=/test2"
      - "traefik.http.routers.n8n5.middlewares=n8n5-stripprefix"
      - traefik.http.routers.n8n5.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n5.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n5.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n5.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n5.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n5.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n5.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n5.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n5.headers.STSPreload=true
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin2
      - N8N_BASIC_AUTH_PASSWORD=pass2
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PORT=5601
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - N8N_PATH=/test2/
      - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}/test2/
      - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}/test2/
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/root/.n8n

  n8n4:
    image: n8nio/n8n
    ports:
      - "127.0.0.1:5700:5700"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n4.rule=Host(`${DOMAIN_NAME}`)
      - traefik.http.routers.n8n4.tls=true
      - traefik.http.routers.n8n4.entrypoints=websecure
      - "traefik.http.routers.n8n4.rule=PathPrefix(`/asit{regex:$$|/.*}`)"
      - "traefik.http.middlewares.n8n4-stripprefix.stripprefix.prefixes=/asit"
      - "traefik.http.routers.n8n4.middlewares=n8n4-stripprefix"
      - traefik.http.routers.n8n4.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n4.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n4.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n4.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n4.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n4.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n4.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n4.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n4.headers.STSPreload=true
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER
      - N8N_BASIC_AUTH_PASSWORD
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PORT=5700
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - N8N_PATH=/asit/
      - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}/asit/
      - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}/asit/
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/root/.n8n

Should I change the DATA_FOLDER for each instance ?
Thanks

Hi @Asit_Joshi, while I haven’t tested it, I think having separate data folders would be the solution if the instances cannot share the database. I know that if n8n cannot find a database, it will create one upon startup.

Yes, you would need a different DATA_FOLDER for each. As that is where the database and encryption-key get stored.

Additionally also different N8N_BASIC_AUTH_USER and N8N_BASIC_AUTH_PASSWORD to make sure that you can define different user and password for basic-auth authentication.

Yes, tried with different DATA_FOLDERS and was able to see different databases.sqlite & config files but LetsEncrypt seems to only work for the first one. Which Labels should be commented or set to false to make the instances work and disable the SSL as it gives Bad Gateway error on visiting.