georchestra / docker

Quick start geOrchestra with docker
18 stars 21 forks source link

Switch to caddy webserver #268

Open edevosc2c opened 7 months ago

edevosc2c commented 7 months ago

Introduction

Traefik has been the source of multiple problems, #214 in particular, and is not a friendly web server to work with.

This pull request propose to switch from Traefik to Caddy webserver: https://caddyserver.com/

Caddy by itself is mature and has existed since 2015, the same year when Traefik launched.

Also, Caddy is so much simpler to work with, take a look at the documentation: https://caddyserver.com/docs/quick-starts/caddyfile

Benefits of this pull request

Overall: Way simpler docker-compose.yml and fewer services to run!

What this pull request does not change

(potential) downsides of this pull request

TODO (missing)

f-necas commented 7 months ago

Could it be possible to use http and not https with it ? Is it configurable ?

jeanpommier commented 7 months ago

It will be nice to have a solution to the SSL certificate issue, nice proposal. I'll try it ASAP (can't today).

I'm wondering if this one would justify a communication on the mailing list. A priori, this shouldn't matter a great deal to change the reverse-proxy technology. But maybe some people have the docker compo in production and would have some unforeseen impact.

fvanderbiest commented 7 months ago

Thanks for the proposal Emilien. Had not expected this and didn't know Caddy at all ;-)

"Caddy shines in its simplicity, automatic HTTPS, and intuitive configuration syntax, making it great for beginners and small to medium-sized projects. On the other hand, Traefik excels in its dynamic configuration capabilities, extensive plugin ecosystem, and strong community support, making it more suitable for larger and complex containerized environments." from https://stackshare.io/stackups/caddy-vs-traefik

Also saw a YT video showing Traefik outperformed Caddy in a test.

Apart from that, I'm a bit sad to see traefik go away. Loved it !

jeanpommier commented 7 months ago

Also saw a YT video showing Traefik outperformed Caddy in a test.

I'm not sure we care about performance, for the docker-compose. It's not the advised production setup anyway

Apart from that, I'm a bit sad to see traefik go away. Loved it !

Will you really be missing the configuration ? I quite like Traefik, once configured, but hate the config part. More seriously, I had gotten used to it and I'm rather bothered by having to learn yet another similar tool. But if it can help solve the SSL certificate issue for local deployments, I'm in.

jeanpommier commented 7 months ago

But... I'm thinking, if the aim is to generate self-signed certificate on startup, it should be fairly easy to replace the traefik-me-certificate-downloader service by a service that would auto-generate the certificates. And keep traefik. What do you think ?

I also believe it should be possible to simplify our configuration for traefik. It should be possible to get something simpler for the routing at least, I don't like the way we list all possible services, it doesn't match with Traefik phylosophy)

edevosc2c commented 7 months ago

I want to remind everyone that I'm using a project built on top of caddy called https://github.com/lucaslorentz/caddy-docker-proxy. This project has existed for almost 6 years now and is here to stay: lucaslorentz/caddy-docker-proxy/releases?page=4.

But this is because I have wanted to keep the same ability to configure the web server from docker labels.

It may not be what we really want, maybe a simple file would be much better. We would just use the containers names for configuring where to send the requests to, that would work too.

I'm wondering about that because docker labels are not necessary the ideal way to configure a web server and can make the configuration more difficult to work with.


But... I'm thinking, if the aim is to generate self-signed certificate on startup, it should be fairly easy to replace the traefik-me-certificate-downloader service by a service that would auto-generate the certificates. And keep traefik. What do you think ?

Sure, but "one off" containers in docker has always been the source of confusion or problems, it's not supported by Docker.

You need to hack a logic to check that everything went well, otherwise the container will keep repeating the same actions once the full docker composition is restarted. Sometimes this hack doesn't work well, so the container keep doing the same actions over and over anyway.

I also believe it should be possible to simplify our configuration for traefik. It should be possible to get something simpler for the routing at least, I don't like the way we list all possible services, it doesn't match with Traefik phylosophy)

You can't really change how traefik was made, in my opinion the configuration is awful to work with.

jeanpommier commented 7 months ago

But this is because I have wanted to keep the same ability to configure the web server from docker labels.

It may not be what we really want, maybe a simple file would be much better. We would just use the containers names for configuring where to send the requests to, that would work too.

I'm wondering about that because docker labels are not necessary the ideal way to configure a web server and can make the configuration more difficult to work with.

Indeed. In the end, how many services are configured behind the proxy ? Only security-proxy and static ? (What is the purpose of the static container BTW ? It looks like it has added a lot of extra complexity in the reverse-proxy config)

We are not really using the dynamic service discovery thing, actually, are we ? Static config could probably do the job

edevosc2c commented 2 months ago

I had some time to tackle this PR again! I have taken into account the feedback.

What's new?

Additional finding about Caddy

Summary

Please give me some feedback about these new changes. I'm confident that it's these were the remaining changes to greatly improve the docker composition of geOrchestra.

I was wondering if I should write a migration guide? A basic one for people that already have the docker composition for geOrchestra 23 with Traefik. Or if we don't care because we consider that this docker composition is for development only.

fvanderbiest commented 2 months ago

Thanks for this great contribution Emilien. It is indeed a clear improvement over the previous option.

edevosc2c commented 2 months ago

CAn you please also remove the 2 traefik*.yml files in resources/ ?

Resources removed.

edevosc2c commented 2 months ago

It seems like caddy trust does not work in Chrome. I have to check what's going on.

Or propose an alternative solution like how to trust the certificate generated by caddy. Or have a small script for that.

f-necas commented 2 months ago

First test : Firefox + Security proxy seems to work fine. As you said, it isn't working out of the box with Chrome when using ./caddy trust so for me it's a no go.

As it's planned to be with geOrchestra 24, I think we can get rid of the old header. By default it's redirecting to it and t's a little bit confusing.

I'll do more tests with Gateway

f-necas commented 2 months ago

Second test :

FF + Gateway : Some config needs to be updated, still can't login by now

Git diff Sorry for whitespaces ```diff Subject: [PATCH] feat: add data api to docker --- Index: config/console/console.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>ISO-8859-1 =================================================================== diff --git a/config/console/console.properties b/config/console/console.properties --- a/config/console/console.properties (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/console/console.properties (date 1717771250977) @@ -311,7 +311,7 @@ #saslEnabled=false # Activates extractor data -# if set to true, enable layer extraction in analytics part +# if set to true, enable layer extraction in analytics part # default: false # extractorappEnabled=false @@ -330,4 +330,4 @@ # Activates area of competence # if set to true, enable competence area in the account form and in organization page # default: false -# competenceAreaEnabled=false \ No newline at end of file +# competenceAreaEnabled=false Index: config/gateway/application.yaml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/config/gateway/application.yaml b/config/gateway/application.yaml --- a/config/gateway/application.yaml (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/gateway/application.yaml (date 1717773358202) @@ -24,4 +24,4 @@ - PreserveHostHeader filter: secure-headers: - referrer-policy: strict-origin \ No newline at end of file + referrer-policy: strict-origin Index: config/gateway/gateway.yaml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/config/gateway/gateway.yaml b/config/gateway/gateway.yaml --- a/config/gateway/gateway.yaml (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/gateway/gateway.yaml (date 1717773212110) @@ -7,7 +7,7 @@ georchestra: gateway: # Redirection URL after a successful logout : Defaults to /?logout - # logoutUrl : "/?logout" + # logoutUrl : "/?logout" default-headers: # Default security headers to append to proxied requests proxy: true @@ -24,11 +24,6 @@ - "/proxy/?url=*" anonymous: true services: - header: - target: ${georchestra.gateway.services.header.target} - access-rules: - - intercept-url: /header/** - anonymous: true datafeeder: target: ${georchestra.gateway.services.datafeeder.target} headers: @@ -37,13 +32,13 @@ access-rules: - intercept-url: /datafeeder/** anonymous: false - allowed-roles: SUPERUSER,DATAFEEDER + allowed-roles: SUPERUSER,IMPORT import: target: ${georchestra.gateway.services.import.target} access-rules: - intercept-url: /import/** anonymous: false - allowed-roles: SUPERUSER,DATAFEEDER + allowed-roles: SUPERUSER,IMPORT console: target: ${georchestra.gateway.services.console.target} access-rules: Index: config/gateway/routes.yaml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/config/gateway/routes.yaml b/config/gateway/routes.yaml --- a/config/gateway/routes.yaml (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/gateway/routes.yaml (date 1717771625812) @@ -10,7 +10,7 @@ predicates: - Path=/ filters: - - RedirectTo=308, /header + - RedirectTo=308, /datahub - id: header uri: ${georchestra.gateway.services.header.target} predicates: Index: config/gateway/security.yaml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/config/gateway/security.yaml b/config/gateway/security.yaml --- a/config/gateway/security.yaml (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/gateway/security.yaml (date 1717773059943) @@ -24,6 +24,12 @@ orgs: rdn: ${ldapOrgsRdn:ou=orgs} protectedRoles: ADMINISTRATOR, GN_.*, ORGADMIN, REFERENT, USER, SUPERUSER + +spring: + webflux: + static-path-pattern: /login/** + + # uncomment for oauth 2.0 #spring: # security: Index: resources/caddy/etc/Caddyfile IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/resources/caddy/etc/Caddyfile b/resources/caddy/etc/Caddyfile --- a/resources/caddy/etc/Caddyfile (revision f11be9ea2edd1cf06c6d2760e912b0035cd5c96a) +++ b/resources/caddy/etc/Caddyfile (date 1717770377133) @@ -43,7 +43,7 @@ } handle { - reverse_proxy proxy:8080 + reverse_proxy gateway:8080 header { Access-Control-Allow-Origin * Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" Index: config/datahub/conf/default.toml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/config/datahub/conf/default.toml b/config/datahub/conf/default.toml --- a/config/datahub/conf/default.toml (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/datahub/conf/default.toml (date 1717771250989) @@ -69,7 +69,7 @@ # Optional; specify a GeoJSON object to be used as filter: all records contained inside the geometry will be boosted on top, # all records which do not intersect with the geometry will be shown with lower priority; can be specified as URL or inline # Note: if the GeoJSON object contains multiple features, only the geometry of the first one will be kept! -filter_geometry_url = "/console/account/areaofcompetence" +# filter_geometry_url = "/console/account/areaofcompetence" # filter_geometry_data = '{ "coordinates": [...], "type": "Polygon" }' # The advanced search filters available to the user can be customized with this setting. Index: docker-compose.yml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/docker-compose.yml b/docker-compose.yml --- a/docker-compose.yml (revision f11be9ea2edd1cf06c6d2760e912b0035cd5c96a) +++ b/docker-compose.yml (date 1717770101546) @@ -14,6 +14,7 @@ datafeeder_postgis_data: esdata: georchestra_datadir: + rabbitmq_data: secrets: slapd_password: @@ -79,30 +80,19 @@ - ldap_config:/etc/ldap restart: always - proxy: - image: georchestra/security-proxy:latest - healthcheck: - test: ["CMD-SHELL", "curl -s -f http://localhost:8080/_static/bootstrap_3.0.0/css/bootstrap-theme.min.css >/dev/null || exit 1"] - interval: 30s - timeout: 10s - retries: 10 + gateway: + image: georchestra/gateway:latest depends_on: - ldap: - condition: service_healthy - database: - condition: service_healthy + - database volumes: - georchestra_datadir:/etc/georchestra environment: - - JAVA_OPTIONS=-Dorg.eclipse.jetty.annotations.AnnotationParser.LEVEL=OFF - - XMS=256M - - XMX=1G + - JAVA_TOOL_OPTIONS=-Dgeorchestra.datadir=/etc/georchestra env_file: - .envs-common - .envs-ldap - .envs-hosts - .envs-database-georchestra - restart: always cas: image: georchestra/cas:latest @@ -186,6 +176,8 @@ condition: service_healthy database: condition: service_healthy + rabbitmq: + condition: service_healthy volumes: - georchestra_datadir:/etc/georchestra environment: @@ -195,6 +187,7 @@ env_file: - .envs-common - .envs-ldap + - .envs-rabbitmq - .envs-database-georchestra - .envs-hosts restart: always @@ -401,5 +394,20 @@ volumes: - georchestra_datadir:/etc/georchestra restart: always + + rabbitmq: + image: docker.io/bitnami/rabbitmq:3.12 + healthcheck: + test: rabbitmq-diagnostics -q ping && rabbitmq-diagnostics -q check_local_alarms + interval: 60s + timeout: 30s + retries: 3 + env_file: + - .envs-rabbitmq + environment: + - RABBITMQ_LOGS=- + volumes: + - 'rabbitmq_data:/bitnami/rabbitmq/mnesia' + restart: always - + Index: config/cas/config/cas.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>ISO-8859-1 =================================================================== diff --git a/config/cas/config/cas.properties b/config/cas/config/cas.properties --- a/config/cas/config/cas.properties (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/cas/config/cas.properties (date 1717769175467) @@ -6,7 +6,7 @@ cas.theme.param-name=georchestra cas.theme.default-theme-name=georchestra -cas.service-registry.initFromJson=false +cas.service-registry.core.init-from-json=false cas.service-registry.json.location=file:/etc/georchestra/cas/services #uncomment if getting 302 redirects on cas.{css,js} behind nginx/apache #server.forward-headers-strategy=FRAMEWORK @@ -47,7 +47,7 @@ cas.authn.ldap[0].type=DIRECT cas.authn.ldap[0].dn-format=uid=%s,ou=users,dc=georchestra,dc=org -cas.authn.oidc.jwks.jwks-file=file:///tmp/keystore.jwksdown +cas.authn.oidc.jwks.file-system.jwks-file=file:///tmp/keystore.jwksdown cas.authn.saml-idp.core.entity-id=https://${FQDN}/idp -cas.authn.saml-idp.metadata.location=file:///tmp/ +cas.authn.saml-idp.metadata.file-system.location=file:///tmp/ Index: config/default.properties IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>ISO-8859-1 =================================================================== diff --git a/config/default.properties b/config/default.properties --- a/config/default.properties (revision 05119872450ec875ccfc6f58fcd8da65c1d3e37d) +++ b/config/default.properties (date 1717770607745) @@ -83,13 +83,13 @@ # rabbitmq server domain name rabbitmqHost=${RABBITMQ_HOST} -# rabbitmq user +# rabbitmq user rabbitmqUser=${RABBITMQ_USERNAME} -# rabbitmq password +# rabbitmq password rabbitmqPassword=${RABBITMQ_PASSWORD} -# rabbitmq port +# rabbitmq port rabbitmqPort=${RABBITMQ_PORT} ### LDAP properties @@ -144,10 +144,10 @@ # Listening port of the SMTP server smtpPort=${SMTPPORT} -# Activates analytics +# Activates analytics # WARNING : When using the geOrchestra gateway, analytics should be disabled -# if set to true, the analytics app will be enabled (https://github.com/georchestra/georchestra/tree/master/analytics) +# if set to true, the analytics app will be enabled (https://github.com/georchestra/georchestra/tree/master/analytics) # console will add all links to analytics and also execute XHR requests # header will diplay analytics app # default: true -# analyticsEnabled=true +analyticsEnabled=false ```
Login response from gateway ```log ✗ curl --request POST --url http://localhost:8080/login \ --data username=testadmin \ --data password=testadmin -v Note: Unnecessary use of -X or --request, POST is already inferred. * Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#0) > POST /login HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.81.0 > Accept: */* > Content-Length: 37 > Content-Type: application/x-www-form-urlencoded > * Mark bundle as not supporting multiuse < HTTP/1.1 302 Found < Location: / < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < X-Content-Type-Options: nosniff < X-Frame-Options: DENY < X-XSS-Protection: 1 ; mode=block < Referrer-Policy: no-referrer < Set-Cookie: SESSION=0bddcc89-5113-4bfc-ba8a-594b44315234; Path=/; HttpOnly; SameSite=Lax < content-length: 0 < * Connection #0 to host localhost left intact ```