1

I'm trying to set up geoserver and traefik with docker, but having an issue with the paths.

Geoserver's main entrypoint is at /geoserver, but I want to make it accessible at the root path of my domain, let's say example.com. Here's the docker-compose file I put together:

version: "3"

services:
  traefik:
    image: traefik:2.4
    restart: unless-stopped
    networks:
      - web
    ports:
      - 80:80
      - 443:443
    command:
      - --log.level=DEBUG
      - --providers=docker
      - --providers.docker.network=geoserver_web
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=websecure
      # - --api.dashboard=true
      - --certificatesresolvers.lets-encrypt.acme.email=admin@example.com
      - --certificatesresolvers.lets-encrypt.acme.storage=acme.json
      - --certificatesresolvers.lets-encrypt.acme.tlschallenge=true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
  
  geoserver:
    image: oscarfonts/geoserver:latest
    restart: unless-stopped
    networks:
      - web
    labels:
      - traefik.port=8080
      - traefik.http.routers.geoserver.rule=Host(`example.com`)
      - traefik.http.routers.geoserver.entrypoints=websecure
      - traefik.http.routers.geoserver.tls=true
      - traefik.http.routers.geoserver.tls.certresolver=lets-encrypt
      - traefik.http.middlewares.geoserver.replacepathregex.regex=(.*)
      - traefik.http.middlewares.geoserver.replacepathregex.replacement=/geoserver/$$1

networks:
  web:

After going through the traefik docs, I thought using replacepathregex on geoserver service should prepend /geoserver to the paths for all the requests passed to geoserver and should make the service available at example.com, instead of example.com/geoserver, but it didn't work.

I also tried addPrefix, but that didn't work either.

Is my configuration incorrect? Or my understanding of what those middlewares do? Is there a way to configure my service to be accessible at example.com, instead of example.com/geoserver?

kaveh
  • 2,046
  • 1
  • 21
  • 33

2 Answers2

1

Turned out the issue was my traefik config! I needed to add the middleware to the geoserver router. Here's the updated docker-compose.yml (I went with addprefix instead of replacepathregex because the latter was an overkill):

version: "3"

services:
  traefik:
    image: traefik:2.4
    restart: unless-stopped
    networks:
      - web
    ports:
      - 80:80
      - 443:443
    command:
      - --log.level=DEBUG
      - --providers=docker
      - --providers.docker.network=geoserver_web
      - --entrypoints.websecure.address=:443
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=websecure
      # - --api.dashboard=true
      - --certificatesresolvers.lets-encrypt.acme.email=admin@example.com
      - --certificatesresolvers.lets-encrypt.acme.storage=acme.json
      - --certificatesresolvers.lets-encrypt.acme.tlschallenge=true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
  
  geoserver:
    image: oscarfonts/geoserver:latest
    restart: unless-stopped
    networks:
      - web
    labels:
      - traefik.http.middlewares.add-geoserver-prefix.addprefix.prefix=/geoserver
      - traefik.port=8080
      - traefik.http.routers.geoserver.rule=Host(`example.com`)
      - traefik.http.routers.geoserver.entrypoints=websecure
      - traefik.http.routers.geoserver.tls=true
      - traefik.http.routers.geoserver.tls.certresolver=lets-encrypt
      - traefik.http.routers.geoserver.middlewares=add-geoserver-prefix@docker

networks:
  web:
kaveh
  • 2,046
  • 1
  • 21
  • 33
0

Regarding to the ReplacePathRegex: Configuration Examples, the Docker tab, it mentions as the following example: -

# Replace path with regex
labels:
  - "traefik.http.middlewares.test-replacepathregex.replacepathregex.regex=^/foo/(.*)"
  - "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$$1"

Together with the following quoting

Regular expressions and replacements can be tested using online tools such as Go Playground or Regex101.

I use the Regex101 to test and ensure the sample configuration above and extend so that we achieve our requirement as the following scenarios.

Test case 1

  • Regular Expression: /foo/(.*) (Note: there is no leading caret ^ here)
  • Test String: https://my.domain.com/foo/api
  • Substitution: /bar/$1 (Note: there is a single dollar sing $ here, explain later)
  • The result: https://my.domain.com/bar/api

Test case 2

  • Regular Expression: /foo/(.*)
  • Test String: https://my.domain.com/foo/api
  • Substitution: /$1
  • The result: https://my.domain.com/api

Test case 3: The geoserver round 1

  • Regular Expression: (.*)/(.*)
  • Test String: https://my.domain.com/api
  • Substitution: $1/geoserver/$2
  • The result: https://my.domain.com/geoserver/api

Test case 4: The geoserver round 2

  • Regular Expression: (.*)/(.*)
  • Test String: https://my.domain.com/api
  • Substitution: /geoserver/$2
  • The result: /geoserver/api
Sidebar 1: Why do we need double dollar sing ($$) ?

Because the docker-compose provides the variable substitution, in a form of $VARIABLE and ${VARIABLE}, then the dollar sign is a key word / reserved word which we have to escape it and cause us to use dollar sing ($$) within the docker-compose.yml. Please refer to the StackOverflow Question and Answer for further information.

Sidebar 2: The leading caret (^)

After trial-and-error for a while, I realize that there is a bit different as the Traefik require the leading caret while the Regex101 does not. Up until now, I still have no idea why it is and remember that way :D

Summarize

To achieve our requirement by following the test case 4, the docker-compose label , should be as the following example

labels:
  - traefik.http.middlewares.geoserver.replacepathregex.regex=^(.*)/(.*) # <-- the leading caret
  - traefik.http.middlewares.geoserver.replacepathregex.replacement=/geoserver/$$2

Edit 1

Test case 5: The geoserver round 3

  • Regular Expression: ^(.*:)//([A-Za-z0-9\-\.]+)(:[0-9]+)?/(.*)$

  • Test String: https://my.domain.com/path

    • Substitution: /geoserver/$4
    • The result: /geoserver/path
  • Test String: https://my.domain.com/path/to

    • Substitution: /geoserver/$4
    • The result: /geoserver/path/to
  • Test String: https://my.domain.com/path/to/api

    • Substitution: /geoserver/$4
    • The result: /geoserver/path/to/api
  • Test String: https://my.domain.com/path/to/api?key=value

    • Substitution: /geoserver/$4
    • The result: /geoserver/path/to/api?key=value
  • Test String: https://my.domain.com/path/to/api?key=value&anotherkey=anothervalue

    • Substitution: /geoserver/$4
    • The result: /geoserver/path/to/api?key=value&anotherkey=anothervalue

Summarize

To achieve our requirement by following the test case 5, the docker-compose label , should be as the following example

labels:
  - traefik.http.middlewares.geoserver.replacepathregex.regex=^(.*:)//([A-Za-z0-9\-\.]+)(:[0-9]+)?/(.*)$$ # <-- the leading caret and double dollar sign at the end
  - traefik.http.middlewares.geoserver.replacepathregex.replacement=/geoserver/$$4
Charlee Chitsuk
  • 8,847
  • 2
  • 56
  • 71
  • Thanks, @charlee-chitsuk, but your answer doesn't work. The final suggested pattern, i.e. `(.*)(.*)`, catches everything before the last slash, and then in the replacement pattern you're dropping everything before it (the first capture group) and replacing it with `/geoserver`, but that's not the objective (also it didn't work as described in the answer). The goal is to prepend `/geoserver` to whatever request we pass to `geoserver` service. – kaveh Aug 23 '21 at 14:30
  • Please look at my edit 1, the test case 5. – Charlee Chitsuk Aug 23 '21 at 16:03
  • I spent more time on this, and turned out the issue wasn't the regex or the syntax of `replacepathregex` or `addprefix` middlewares, but attaching them to the geoserver router. See my own answer for the updated `docker-compose.yml`. – kaveh Aug 23 '21 at 18:06