[GH-ISSUE #700] Bug: Listening to an address other than 127.0.0.1/32 or 0.0.0.0/32 breaks docker health checks #248

Closed
opened 2026-02-27 08:16:08 +03:00 by kerem · 16 comments
Owner

Originally created by @TheRealGramdalf on GitHub (Oct 6, 2023).
Original GitHub issue: https://github.com/lldap/lldap/issues/700

Forgive me if this isn't possible/within the scope of LLDAP. I tried to look through the code briefly to see whether I could figure it out on my own, but I'm not familiar enough with rust to find it easily.

The issue:

When binding the LDAP IP address to a specific IPv4 address (LLDAP_LDAP_HOST = "192.168.2.2", which is technically 192.168.2.2/32 - unless LLDAP does something weird), docker health checks fail.

Why it happens:

It's simple in nature: The docker health check attempts to reach the LDAP api on 127.0.0.1/32, but gets refused - LDAP is listening on 192.168.2.2/32. Thus, it's request is refused.

The solution:

Unless it is a case of user error, I see three ways to resolve this:

  • Allow listening on two different IPv4/6 addresses
    • I find this to be unlikely, because I'm not actually sure if the Linux kernel allows this
  • Always listen on 127.0.0.1/32 when dockerized
    • Not necessarily ideal, since it adds complexity to development - namely fragmentation
  • Use the configured LLDAP_LDAP_HOST address for docker healthchecks
    • This seems to be the sanest option imho, though I'm not sure if there are security/bandwidth/other concerns

Again, forgive me if I'm incorrect - I wasn't able to find any information in the issues, readme, or code regarding this.

Originally created by @TheRealGramdalf on GitHub (Oct 6, 2023). Original GitHub issue: https://github.com/lldap/lldap/issues/700 Forgive me if this isn't possible/within the scope of LLDAP. I tried to look through the code briefly to see whether I could figure it out on my own, but I'm not familiar enough with rust to find it easily. #### The issue: When binding the LDAP IP address to a specific IPv4 address (`LLDAP_LDAP_HOST = "192.168.2.2"`, which is technically `192.168.2.2/32` - unless LLDAP does something weird), docker health checks fail. #### Why it happens: It's simple in nature: The docker health check attempts to reach the LDAP api on `127.0.0.1/32`, but gets refused - LDAP is listening on `192.168.2.2/32`. Thus, it's request is refused. #### The solution: Unless it is a case of user error, I see three ways to resolve this: - Allow listening on two different IPv4/6 addresses - I find this to be unlikely, because I'm not actually sure if the Linux kernel allows this - Always listen on `127.0.0.1/32` when dockerized - Not necessarily ideal, since it adds complexity to development - namely fragmentation - Use the configured `LLDAP_LDAP_HOST` address for docker healthchecks - This seems to be the sanest option imho, though I'm not sure if there are security/bandwidth/other concerns Again, forgive me if I'm incorrect - I wasn't able to find any information in the issues, readme, or code regarding this.
kerem 2026-02-27 08:16:08 +03:00
Author
Owner

@TheRealGramdalf commented on GitHub (Oct 6, 2023):

For now I'm using 0.0.0.0 as my listen address, but I would prefer to listen to an address managed by my firewall if possible. I can provide more information about my setup if needed.

<!-- gh-comment-id:1749995301 --> @TheRealGramdalf commented on GitHub (Oct 6, 2023): For now I'm using `0.0.0.0` as my listen address, but I would prefer to listen to an address managed by my firewall if possible. I can provide more information about my setup if needed.
Author
Owner

@nitnelave commented on GitHub (Oct 6, 2023):

Out of curiosity, would something like https://github.com/lldap/lldap/issues/701 help?

Otherwise, I propose another solution: make the healthcheck target configurable. That way you can choose yourself between options 2 or 3.

<!-- gh-comment-id:1750508399 --> @nitnelave commented on GitHub (Oct 6, 2023): Out of curiosity, would something like https://github.com/lldap/lldap/issues/701 help? Otherwise, I propose another solution: make the healthcheck target configurable. That way you can choose yourself between options 2 or 3.
Author
Owner

@martadinata666 commented on GitHub (Oct 6, 2023):

Adding to this, manually trigger healthcheck, somehow it don't read LLDAP_LDAP_HOST parameter correctly or as the port read correctly. 🤔 Accidentally hardcoded to localhost?

bash-5.1# ./lldap healthcheck
Loading configuration from lldap_config.toml
Configuration: Configuration {
    ldap_host: "192.168.0.13",
    ldap_port: 50000,
    http_host: "0.0.0.0",
    http_port: 17170,
    jwt_secret: ***SECRET***,
    ldap_base_dn: "dc=example,dc=com",
    ldap_user_dn: UserId(
        "admin",
    ),
    ldap_user_email: "",
    ldap_user_pass: ***SECRET***,
    database_url: "sqlite://users.db?mode=rwc",
    ignored_user_attributes: [],
    ignored_group_attributes: [],
    verbose: true,
    key_file: "server_key",
    key_seed: None,
    smtp_options: MailOptions {
        enable_password_reset: false,
        from: None,
        reply_to: None,
        server: "localhost",
        port: 587,
        user: "",
        password: ***SECRET***,
        smtp_encryption: Tls,
        tls_required: None,
    },
    ldaps_options: LdapsOptions {
        enabled: false,
        port: 6360,
        cert_file: "cert.pem",
        key_file: "key.pem",
    },
    http_url: Url {
        scheme: "http",
        cannot_be_a_base: false,
        username: "",
        password: None,
        host: Some(
            Domain(
                "localhost",
            ),
        ),
        port: None,
        path: "/",
        query: None,
        fragment: None,
    },
    server_setup: None,
}
2023-10-06T12:18:38.810617579+00:00  INFO     i [info]: Starting healthchecks
2023-10-06T12:18:38.812262477+00:00  INFO     check_ldaps [ 87.4µs | 100.00% ] port: 6360
2023-10-06T12:18:38.812350828+00:00  INFO     ┕━ i [info]: LDAPS not enabled
2023-10-06T12:18:38.814807128+00:00  DEBUG    🐛 [debug]: resolving host="localhost"
2023-10-06T12:18:38.811396593+00:00  INFO     check_ldap [ 1.53ms | 100.00% ] port: 50000
2023-10-06T12:18:38.815577476+00:00  ERROR    ┕━ 🚨 [error]:  | error: Address not available (os error 99)
2023-10-06T12:18:38.816863987+00:00  DEBUG    🐛 [debug]: flushed 60 bytes
2023-10-06T12:18:38.817722667+00:00  DEBUG    🐛 [debug]: parsed 2 headers
2023-10-06T12:18:38.817765685+00:00  DEBUG    🐛 [debug]: incoming body is empty
2023-10-06T12:18:38.812522642+00:00  INFO     check_api [ 4.76ms | 100.00% ] port: 17170
2023-10-06T12:18:38.815878289+00:00  DEBUG    ┝━ 🐛 [debug]: connecting to 127.0.0.1:17170
2023-10-06T12:18:38.816431323+00:00  DEBUG    ┝━ 🐛 [debug]: connected to 127.0.0.1:17170
2023-10-06T12:18:38.817946962+00:00  DEBUG    ┝━ 🐛 [debug]: pooling idle connection for ("http", localhost:17170)
2023-10-06T12:18:38.819595008+00:00  INFO     ┕━ i [info]: Success
2023-10-06T12:18:38.819809525+00:00  ERROR    🚨 [error]: Healthcheck failed
bash-5.1# 
<!-- gh-comment-id:1750557400 --> @martadinata666 commented on GitHub (Oct 6, 2023): Adding to this, manually trigger healthcheck, somehow it don't read `LLDAP_LDAP_HOST` parameter correctly or as the port read correctly. 🤔 Accidentally hardcoded to `localhost`? ``` bash-5.1# ./lldap healthcheck Loading configuration from lldap_config.toml Configuration: Configuration { ldap_host: "192.168.0.13", ldap_port: 50000, http_host: "0.0.0.0", http_port: 17170, jwt_secret: ***SECRET***, ldap_base_dn: "dc=example,dc=com", ldap_user_dn: UserId( "admin", ), ldap_user_email: "", ldap_user_pass: ***SECRET***, database_url: "sqlite://users.db?mode=rwc", ignored_user_attributes: [], ignored_group_attributes: [], verbose: true, key_file: "server_key", key_seed: None, smtp_options: MailOptions { enable_password_reset: false, from: None, reply_to: None, server: "localhost", port: 587, user: "", password: ***SECRET***, smtp_encryption: Tls, tls_required: None, }, ldaps_options: LdapsOptions { enabled: false, port: 6360, cert_file: "cert.pem", key_file: "key.pem", }, http_url: Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some( Domain( "localhost", ), ), port: None, path: "/", query: None, fragment: None, }, server_setup: None, } 2023-10-06T12:18:38.810617579+00:00 INFO i [info]: Starting healthchecks 2023-10-06T12:18:38.812262477+00:00 INFO check_ldaps [ 87.4µs | 100.00% ] port: 6360 2023-10-06T12:18:38.812350828+00:00 INFO ┕━ i [info]: LDAPS not enabled 2023-10-06T12:18:38.814807128+00:00 DEBUG 🐛 [debug]: resolving host="localhost" 2023-10-06T12:18:38.811396593+00:00 INFO check_ldap [ 1.53ms | 100.00% ] port: 50000 2023-10-06T12:18:38.815577476+00:00 ERROR ┕━ 🚨 [error]: | error: Address not available (os error 99) 2023-10-06T12:18:38.816863987+00:00 DEBUG 🐛 [debug]: flushed 60 bytes 2023-10-06T12:18:38.817722667+00:00 DEBUG 🐛 [debug]: parsed 2 headers 2023-10-06T12:18:38.817765685+00:00 DEBUG 🐛 [debug]: incoming body is empty 2023-10-06T12:18:38.812522642+00:00 INFO check_api [ 4.76ms | 100.00% ] port: 17170 2023-10-06T12:18:38.815878289+00:00 DEBUG ┝━ 🐛 [debug]: connecting to 127.0.0.1:17170 2023-10-06T12:18:38.816431323+00:00 DEBUG ┝━ 🐛 [debug]: connected to 127.0.0.1:17170 2023-10-06T12:18:38.817946962+00:00 DEBUG ┝━ 🐛 [debug]: pooling idle connection for ("http", localhost:17170) 2023-10-06T12:18:38.819595008+00:00 INFO ┕━ i [info]: Success 2023-10-06T12:18:38.819809525+00:00 ERROR 🚨 [error]: Healthcheck failed bash-5.1# ```
Author
Owner

@nitnelave commented on GitHub (Oct 6, 2023):

ldap_host is somewhat misnamed, it's the listen address.
Healthcheck is hardcoded to listen to localhost.

<!-- gh-comment-id:1750874821 --> @nitnelave commented on GitHub (Oct 6, 2023): `ldap_host` is somewhat misnamed, it's the listen address. Healthcheck is hardcoded to listen to localhost.
Author
Owner

@TheRealGramdalf commented on GitHub (Oct 6, 2023):

My two cents on this and #701 :

  • In order to keep lldap simple, adding unix sockets as an option may be out of scope. Perhaps I'm being too harsh, but from the perspective of a new user who doesn't necessarily know about unix sockets, that could be a turn away. Especially in the case of docker, I could see that becoming an issue - say you need to access the socket outside of the lldap container. That could easily become complicated with file permissions inside and outside of the container (due to UID:GID mappings). For a semi-experienced sysadmin like myself, it probably wouldn't be that hard - but for someone who just wants to get something running, even having the choice available can be confusing.
  • In that case, I would actually consider it more "lightweight" to use the TCP/IP stack - a user who wants to deploy this will have to have at least some knowledge of how that works. Unix sockets are more of a black box situation.
  • Assuming you agree with my above comment, it would probably be best to implement the solution here:
  • Optional: Allow multiple addresses in ldap_host and ldaps_host. Each address is separated by a comma and whitespace is ignored for interpretation (e.g.: ldap_host = unix@/run/lldap.sock, 192.168.1.16:389, 192.168.2.16:3890, [::1]:389). While not part of this feature request, I do miss the ability to bind to multiple local addresses. Example use case: exposing LLDAP running outside of Docker to Docker containers who cannot refer to localhost as the machine itself.
  • This would allow "advanced" configuration while still keeping the concept simple to learn. It's not so much that unix sockets are complicated, it's that a user most likely already has a base knowledge of TCP/IP, and would have to learn unix sockets from scratch
    • One thing to note here: Allowing 0.0.0.0:port in the ldap_host configuration could be considered more complex, as it could lead to a situation in which a user isn't certain which port is actually being used - they may be unsure whether:
      • The config file takes priority over the environment variables
      • Specifying 0.0.0.0:port takes priority over ldap_port
      • Or any combination of the two.
    • It seems all too likely that you end up with users who didn't read the installation instructions all the way through, simply missed the warning about what takes priority, or otherwise - and then come open issues on github, which takes away from development time. Ideally this wouldn't be necessary, but for the target audience I think choosing one or the other (ldap_host/port vs 0.0.0.0:port) would be the best.
    • In that regard, it would be the most readable (imho) to use 0.0.0.0:port. Using only that value would require deprecation of ldap_port, which could be tricky.
  • As far as allowing multiple bind addresses: it came to mind while I was writing that you could run into issues where you aren't able to bind to the same port twice in linux, which could present some issues - I'm not familiar with the intricacies of bind well enough to know.
  • Given the above information, I think the best way forward is:

TL;DR

  • Deprecate ldap_port in favor of ldap_host = 0.0.0.0:port
  • Use a (hardcoded) unix socket for docker healthchecks*

Things of note:

  • Going with the TL;DR solution would make lldap less flexible - which could be a pro or a con
  • Deprecation may well be tricky and complicated
  • In order to prevent fragmentation and security leaks, I believe it would be necessary to implement a check - if lldap is running inside docker, create a socket for healthchecks - if not (i.e. running bare metal/lxc/vm etc), do not create the socket. The socket should be non-persistent - again, I'm not certain about the intricacies of unix sockets, so I'm not sure if they disappear from the filesystem once the service stops/crashes, or if a blank "file" (such as touch /var/run/lldap.sock) is left.
    • To check if lldap is running within docker, I would hardcode an environment variable to the dockerfile (that cannot be changed by the user in any way) such as LLDAP_IS_DOCKERIZED or something to that effect. If the variable is defined (At all! Even if a user defines their own value for whatever reason), lldap assumes it is running within docker, and creates the unix socket for docker healthchecks.

I'm sort of playing devils advocate here, but I also believe this would be the simplest to implement, maintain, and be transparent to the user. IMHO, users shouldn't have to configure docker health checks - they should just work. But by any means, I'm open to suggestions. It's not my project, after all :)

Edit: Sorry for the double notification, the issue didn't tag properly. Not sure why that is.

<!-- gh-comment-id:1751126795 --> @TheRealGramdalf commented on GitHub (Oct 6, 2023): My two cents on this and #701 : - In order to keep lldap simple, adding unix sockets as an option may be out of scope. Perhaps I'm being too harsh, but from the perspective of a new user who doesn't necessarily know about unix sockets, that could be a turn away. Especially in the case of docker, I could see that becoming an issue - say you need to access the socket outside of the lldap container. That could easily become complicated with file permissions inside and outside of the container (due to UID:GID mappings). For a semi-experienced sysadmin like myself, it probably wouldn't be that hard - but for someone who just wants to get something running, even having the choice available can be confusing. - In that case, I would actually consider it more "lightweight" to use the TCP/IP stack - a user who wants to deploy this will have to have at least some knowledge of how that works. Unix sockets are more of a black box situation. - Assuming you agree with my above comment, it would probably be best to implement the solution here: > * Optional: Allow multiple addresses in `ldap_host` and `ldaps_host`. Each address is separated by a comma and whitespace is ignored for interpretation (e.g.: `ldap_host = unix@/run/lldap.sock, 192.168.1.16:389, 192.168.2.16:3890, [::1]:389`). While not part of this feature request, I do miss the ability to bind to multiple local addresses. Example use case: exposing LLDAP running outside of Docker to Docker containers who cannot refer to localhost as the machine itself. - This would allow "advanced" configuration while still keeping the concept simple to learn. It's not so much that unix sockets are complicated, it's that a user most likely already has a base knowledge of TCP/IP, and would have to learn unix sockets from scratch - One thing to note here: Allowing `0.0.0.0:port` in the `ldap_host` configuration could be considered more complex, as it could lead to a situation in which a user isn't certain which port is actually being used - they may be unsure whether: - The config file takes priority over the environment variables - Specifying `0.0.0.0:port` takes priority over `ldap_port` - Or any combination of the two. - It seems all too likely that you end up with users who didn't read the installation instructions all the way through, simply missed the warning about what takes priority, or otherwise - and then come open issues on github, which takes away from development time. Ideally this wouldn't be necessary, but for the target audience I think choosing one or the other (`ldap_host/port` vs `0.0.0.0:port`) would be the best. - In that regard, it would be the most readable (imho) to use `0.0.0.0:port`. Using only that value would require deprecation of `ldap_port`, which could be tricky. - As far as allowing multiple bind addresses: it came to mind while I was writing that you could run into issues where you aren't able to bind to the same port twice in linux, which could present some issues - I'm not familiar with the intricacies of bind well enough to know. - Given the above information, I think the best way forward is: #### TL;DR - Deprecate `ldap_port` in favor of `ldap_host = 0.0.0.0:port` - Use a (hardcoded) unix socket for docker healthchecks* #### Things of note: - Going with the TL;DR solution would make lldap less flexible - which could be a pro or a con - Deprecation may well be tricky and complicated - In order to prevent fragmentation and security leaks, I believe it would be necessary to implement a check - if lldap is running inside docker, create a socket for healthchecks - if not (i.e. running bare metal/lxc/vm etc), do not create the socket. The socket should be non-persistent - again, I'm not certain about the intricacies of unix sockets, so I'm not sure if they disappear from the filesystem once the service stops/crashes, or if a blank "file" (such as `touch /var/run/lldap.sock`) is left. - To check if lldap is running within docker, I would hardcode an environment variable to the dockerfile (that cannot be changed by the user in any way) such as `LLDAP_IS_DOCKERIZED` or something to that effect. If the variable is defined (At all! Even if a user defines their own value for whatever reason), lldap assumes it is running within docker, and creates the unix socket for docker healthchecks. I'm sort of playing devils advocate here, but I also believe this would be the simplest to implement, maintain, and be transparent to the user. IMHO, users shouldn't have to configure docker health checks - they should just work. But by any means, I'm open to suggestions. It's not my project, after all :) *Edit: Sorry for the double notification, the issue didn't tag properly. Not sure why that is.*
Author
Owner

@Zepmann commented on GitHub (Oct 6, 2023):

@TheRealGramdalf

In order to keep lldap simple, adding unix sockets as an option may be out of scope.

Just because lldap would support unix sockets would not have to make usage harder. Using it is optional. If you are afraid of it confusing new users, leave examples out of the default configuration file and only note them in documentation (for advanced users/usage). Hell, you can even put it on a separate documentation page dedicated to unix sockets and slap a big warning on top of it that it is not necessary for normal operations.

If you wanted simple and not scare away users, you can also remove LDAPS support. TLS is not simple for the uninitiated. I would even wager it is more complex compared to unix sockets. Strictly speaking, it is not necessary for LDAP support, and LDAPS support can also be added through other means (e.g. a TLS wrapper such as stunnel or a reverse proxy such as HAProxy in TCP mode).

Especially in the case of docker, I could see that becoming an issue

Not everyone runs lldap in docker. Unix sockets are useful if docker is not used. With docker, TCP connections make more sense since they are easier to manage in, through and outside of docker.

<!-- gh-comment-id:1751144975 --> @Zepmann commented on GitHub (Oct 6, 2023): @TheRealGramdalf > In order to keep lldap simple, adding unix sockets as an option may be out of scope. Just because lldap would support unix sockets would not have to make usage harder. Using it is optional. If you are afraid of it confusing new users, leave examples out of the default configuration file and only note them in documentation (for advanced users/usage). Hell, you can even put it on a separate documentation page dedicated to unix sockets and slap a big warning on top of it that it is not necessary for normal operations. If you wanted simple and not scare away users, you can also remove LDAPS support. TLS is not simple for the uninitiated. I would even wager it is more complex compared to unix sockets. Strictly speaking, it is not necessary for LDAP support, and LDAPS support can also be added through other means (e.g. a TLS wrapper such as stunnel or a reverse proxy such as HAProxy in TCP mode). > Especially in the case of docker, I could see that becoming an issue Not everyone runs lldap in docker. Unix sockets are useful if docker is not used. With docker, TCP connections make more sense since they are easier to manage in, through and outside of docker.
Author
Owner

@nitnelave commented on GitHub (Oct 6, 2023):

Hey, thanks for your opinions on the matter! That gave me food for thought. Here's what I'm currently thinking:

  • I really, really don't want to break people's config, especially for cosmetic things like putting the port in the host. There are probably thousands of LLDAP instances deployed, doing their work in the background, being quietly forgotten, and that's how they're supposed to be! LLDAP is not meant to be an in-your-face care-about-it tool, but rather a quiet infrastructure pillar that you set and forget.
  • That said, I am aware that some people want to have better control of their listening address/socket/firewall and whatnot. I'm not against the idea of multiple listening hosts/ports, unix sockets and so on. Whatever floats your boat. LLDAP is structured so that the only file(s) that care about that are the LDAP and TCP server setup files, and they care only about that. Moreover, actix supports listening to several addresses trivially (though not mixing IPs and UDS, sadly, we'll have to connect to both separately). It would be a little bit more code, but the complexity would be contained and I'm not too worried about the implementation or the maintenance.
  • So, the questions that remain:
    • How do we keep backward compatibility?
    • How do we make it easy for the simple case?
    • How do we make it extensible for the complex case?
    • How do we make it clear?

What I'd like to propose is:

  • We keep ldap_host/ldap_port/ldaps_port/http_host/http_port, they are not deprecated. But in the config, they become optional (though the default template has values for them).
    • That takes care of backward compatibility and the simple case.
  • We add new keys ldap_bind_socket_addresses, ldaps_bind_socket_addresses, http_bind_socket_addresses. These keys are lists (TOML lists) so the parsing is clear. These are in the format IP:port with a mandatory port or unix@path
    • That takes care of the complex case.
  • How do we resolve the addresses in case of conflict? If you set a *_bind_socket_addresses variable and a *_host or *_port, that's an error and the server doesn't start. If you set nothing, use the defaults for host and port. In addition, if you set the ldap_bind_socket_addresses and you enable LDAPS, we'll require a ldaps_bind_socket_addresses.
    • That takes care of any possible ambiguity (I can think of), so the config should remain clear.

The new config values can be documented in the config template, but as advanced features. Since it's marked as an advanced and optional feature, we can mention the unix sockets and the fact that they are incompatible with *_host/*_port. No integration example will be recommending it, so if you got to them it's probably that you read the docs.

Along those lines, we can similarly add an advanced [healthcheck] section, with ldap_socket_address/ldaps_socket_address/http_socket_address for those who want to tune everything to their liking.

I don't think that we should try to detect docker or do anything specific in the container. That, for me, is more essential to keeping the project simple.

What do you think about this proposal? It's fairly broad, and thus covers both #700 and #701.

<!-- gh-comment-id:1751505715 --> @nitnelave commented on GitHub (Oct 6, 2023): Hey, thanks for your opinions on the matter! That gave me food for thought. Here's what I'm currently thinking: - I _really, really_ don't want to break people's config, especially for cosmetic things like putting the port in the host. There are probably thousands of LLDAP instances deployed, doing their work in the background, being quietly forgotten, and _that's how they're supposed to be_! LLDAP is not meant to be an in-your-face care-about-it tool, but rather a quiet infrastructure pillar that you set and forget. - That said, I am aware that some people want to have better control of their listening address/socket/firewall and whatnot. I'm not against the idea of multiple listening hosts/ports, unix sockets and so on. Whatever floats your boat. LLDAP is structured so that the only file(s) that care about that are the LDAP and TCP server setup files, and they care only about that. Moreover, actix supports listening to several addresses trivially (though not mixing IPs and UDS, sadly, we'll have to connect to both separately). It would be a little bit more code, but the complexity would be contained and I'm not too worried about the implementation or the maintenance. - So, the questions that remain: - How do we keep backward compatibility? - How do we make it easy for the simple case? - How do we make it extensible for the complex case? - How do we make it _clear_? What I'd like to propose is: - We keep `ldap_host`/`ldap_port`/`ldaps_port`/`http_host`/`http_port`, they are not deprecated. But in the config, they become optional (though the default template has values for them). - That takes care of backward compatibility and the simple case. - We add new keys `ldap_bind_socket_addresses`, `ldaps_bind_socket_addresses`, `http_bind_socket_addresses`. These keys are lists (TOML lists) so the parsing is clear. These are in the format `IP:port` with a mandatory port or `unix@path` - That takes care of the complex case. - How do we resolve the addresses in case of conflict? If you set a `*_bind_socket_addresses` variable _and_ a `*_host` or `*_port`, that's an error and the server doesn't start. If you set nothing, use the defaults for host and port. In addition, if you set the `ldap_bind_socket_addresses` and you enable LDAPS, we'll _require_ a `ldaps_bind_socket_addresses`. - That takes care of any possible ambiguity (I can think of), so the config should remain clear. The new config values can be documented in the config template, but as advanced features. Since it's marked as an advanced and optional feature, we can mention the unix sockets and the fact that they are incompatible with `*_host`/`*_port`. No integration example will be recommending it, so if you got to them it's probably that you read the docs. Along those lines, we can similarly add an advanced `[healthcheck]` section, with `ldap_socket_address`/`ldaps_socket_address`/`http_socket_address` for those who want to tune everything to their liking. I don't think that we should try to detect docker or do anything specific in the container. _That_, for me, is more essential to keeping the project simple. What do you think about this proposal? It's fairly broad, and thus covers both #700 and #701.
Author
Owner

@Zepmann commented on GitHub (Oct 7, 2023):

@nitnelave

That's a good proposal. I agree that unix sockets are an advanced topic, so they should not be mentioned in integration examples in the documentation.

Maybe over time you can also consider adding these socket file options for completeness sake? I would not make them part of this request since it is complex enough as it is, but it could be put on a roadmap.

An idea for implementation:

unix:mode=<mode>,user=<user>,uid=<uid>,group=<group>,gid=<gid>@<socketpath>

Every value is optional, but at least one value should be specified if unix: is used. Using unix: to indicate a unix socket address with options does not break backwards compatibility in configuration files if unix@ is implemented first.

<!-- gh-comment-id:1751610667 --> @Zepmann commented on GitHub (Oct 7, 2023): @nitnelave That's a good proposal. I agree that unix sockets are an advanced topic, so they should not be mentioned in integration examples in the documentation. Maybe over time you can also consider [adding these socket file options](https://www.haproxy.com/documentation/hapee/latest/onepage/#3.1-unix-bind) for completeness sake? I would not make them part of this request since it is complex enough as it is, but it could be put on a roadmap. An idea for implementation: ``` unix:mode=<mode>,user=<user>,uid=<uid>,group=<group>,gid=<gid>@<socketpath> ``` Every value is optional, but at least one value should be specified if `unix:` is used. Using `unix:` to indicate a unix socket address with options does not break backwards compatibility in configuration files if `unix@` is implemented first.
Author
Owner

@TheRealGramdalf commented on GitHub (Oct 7, 2023):

  • I really, really don't want to break people's config, especially for cosmetic things like putting the port in the host. There are probably thousands of LLDAP instances deployed, doing their work in the background, being quietly forgotten, and that's how they're supposed to be! LLDAP is not meant to be an in-your-face care-about-it tool, but rather a quiet infrastructure pillar that you set and forget.

I agree, that's partly why I was hesitant to push for deprecating an option. I think this is probably the best path forward

  • How do we resolve the addresses in case of conflict? If you set a *_bind_socket_addresses variable and a *_host or *_port, that's an error and the server doesn't start. If you set nothing, use the defaults for host and port. In addition, if you set the ldap_bind_socket_addresses and you enable LDAPS, we'll require a ldaps_bind_socket_addresses.

One thing to note here: I'm not sure if this is the case (I'm using Portainer, so logs are somewhat weird for me), but it would be good to make sure that these messages are displayed regardless of the debug level - I don't think a user should have to enable debug = true to see why their container doesn't start up.

<!-- gh-comment-id:1751768786 --> @TheRealGramdalf commented on GitHub (Oct 7, 2023): >- I _really, really_ don't want to break people's config, especially for cosmetic things like putting the port in the host. There are probably thousands of LLDAP instances deployed, doing their work in the background, being quietly forgotten, and _that's how they're supposed to be_! LLDAP is not meant to be an in-your-face care-about-it tool, but rather a quiet infrastructure pillar that you set and forget. I agree, that's partly why I was hesitant to push for deprecating an option. I think this is probably the best path forward >- How do we resolve the addresses in case of conflict? If you set a `*_bind_socket_addresses` variable _and_ a `*_host` or `*_port`, that's an error and the server doesn't start. If you set nothing, use the defaults for host and port. In addition, if you set the `ldap_bind_socket_addresses` and you enable LDAPS, we'll _require_ a `ldaps_bind_socket_addresses`. One thing to note here: I'm not sure if this is the case (I'm using Portainer, so logs are somewhat weird for me), but it would be good to make sure that these messages are displayed regardless of the debug level - I don't think a user should have to enable `debug = true` to see why their container doesn't start up.
Author
Owner

@nioc commented on GitHub (Apr 14, 2025):

Hello, as a new user, I'm encountering the same problem as the original subject: I'm exposing the 17170/UI port on a proxy network used by a HAProxy and the 3890/ldap port on another network ldap accessible only to Authelia (LLDAP_LDAP_HOST: 172.30.0.2 which is on this second network).

Would it be possible to tell the healthcheck what ldap_host value to use?
For now, I disabled the healthcheck...

Here is my docker-compose.yml:

  lldap:
    container_name: lldap
    image: lldap/lldap:stable
    volumes:
      - /data/lldap:/data
    networks:
      ldap: # exposed port 3890
        ipv4_address: 172.30.0.2
      proxy: # exposed port 17170
    healthcheck:
      disable: true  # <--- workaround for this issue
    environment:
      TZ: Europe/Paris
      UID: 1000
      GID: 1000
      LLDAP_JWT_SECRET: ***
      LLDAP_KEY_FILE:
      LLDAP_KEY_SEED: ***
      LLDAP_LDAP_HOST: 172.30.0.2
      LLDAP_LDAP_BASE_DN: $BASE_DN
      LLDAP_LDAP_USER_DN: $LDAP_ADMIN_USER
      LLDAP_LDAP_USER_PASS: $LDAP_ADMIN_PWD
<!-- gh-comment-id:2803102063 --> @nioc commented on GitHub (Apr 14, 2025): Hello, as a new user, I'm encountering the same problem as the original subject: I'm exposing the 17170/UI port on a `proxy` network used by a HAProxy and the 3890/ldap port on another network `ldap` accessible only to Authelia (LLDAP_LDAP_HOST: 172.30.0.2 which is on this second network). Would it be possible to tell the healthcheck what ldap_host value to use? For now, I disabled the healthcheck... Here is my docker-compose.yml: ``` yml lldap: container_name: lldap image: lldap/lldap:stable volumes: - /data/lldap:/data networks: ldap: # exposed port 3890 ipv4_address: 172.30.0.2 proxy: # exposed port 17170 healthcheck: disable: true # <--- workaround for this issue environment: TZ: Europe/Paris UID: 1000 GID: 1000 LLDAP_JWT_SECRET: *** LLDAP_KEY_FILE: LLDAP_KEY_SEED: *** LLDAP_LDAP_HOST: 172.30.0.2 LLDAP_LDAP_BASE_DN: $BASE_DN LLDAP_LDAP_USER_DN: $LDAP_ADMIN_USER LLDAP_LDAP_USER_PASS: $LDAP_ADMIN_PWD ```
Author
Owner

@nitnelave commented on GitHub (Apr 15, 2025):

The health check can take pretty much all the same options as lldap, so you can add cli flags or env variables to affect its behavior. You just need to copy the health check command from the docker file (something like lldap check_health) and add the flags you want

<!-- gh-comment-id:2803582451 --> @nitnelave commented on GitHub (Apr 15, 2025): The health check can take pretty much all the same options as lldap, so you can add cli flags or env variables to affect its behavior. You just need to copy the health check command from the docker file (something like `lldap check_health`) and add the flags you want
Author
Owner

@nioc commented on GitHub (Apr 15, 2025):

I tried some commands, but healthcheck never worked...

feabccca4adf:/app# /app/lldap healthcheck --config-file /data/lldap_config.toml -v --ldap-host 172.30.0.2 
Loading configuration from /data/lldap_config.toml
Configuration: Configuration {
    ldap_host: "172.30.0.2",
    ldap_port: 3890,
    http_host: "0.0.0.0",
    http_port: 17170,
    jwt_secret: ***SECRET***,
    ldap_base_dn: "dc=bidule,dc=machin",
    ldap_user_dn: "admin",
    ldap_user_email: "",
    ldap_user_pass: ***SECRET***,
    force_ldap_user_pass_reset: False,
    force_update_private_key: false,
    database_url: "sqlite:///data/users.db?mode=rwc",
    ignored_user_attributes: [],
    ignored_group_attributes: [],
    verbose: true,
    key_file: "",
    key_seed: Some(
        ***SECRET***,
    ),
    smtp_options: MailOptions {
        enable_password_reset: false,
        from: None,
        reply_to: None,
        server: "localhost",
        port: 587,
        user: "",
        password: ***SECRET***,
        smtp_encryption: Tls,
        ..
    },
    ldaps_options: LdapsOptions {
        enabled: false,
        port: 6360,
        cert_file: "cert.pem",
        key_file: "key.pem",
    },
    http_url: "http://localhost/",
    ..
}
Generating the private key from the key_seed
2025-04-15T21:41:49.700464618+00:00  INFO     i [info]: Starting healthchecks
2025-04-15T21:41:49.700679249+00:00  INFO     check_ldaps [ 16.9µs | 100.00% ] port: 6360
2025-04-15T21:41:49.700695872+00:00  INFO     ┕━ i [info]: LDAPS not enabled
2025-04-15T21:41:49.701592738+00:00  DEBUG    🐛 [debug]: resolving host="localhost"
2025-04-15T21:41:49.700534742+00:00  INFO     check_ldap [ 347µs | 100.00% ] port: 3890
2025-04-15T21:41:49.701978766+00:00  ERROR    ┕━ 🚨 [error]:  | error: Connection refused (os error 111)
2025-04-15T21:41:49.702442670+00:00  DEBUG    🐛 [debug]: flushed 60 bytes
2025-04-15T21:41:49.702571462+00:00  DEBUG    🐛 [debug]: parsed 2 headers
2025-04-15T21:41:49.702583475+00:00  DEBUG    🐛 [debug]: incoming body is empty
2025-04-15T21:41:49.700748255+00:00  INFO     check_api [ 1.63ms | 100.00% ] port: 17170
2025-04-15T21:41:49.701739690+00:00  DEBUG    ┝━ 🐛 [debug]: connecting to [::1]:17170
2025-04-15T21:41:49.702043791+00:00  DEBUG    ┝━ 🐛 [debug]: connecting to 127.0.0.1:17170
2025-04-15T21:41:49.702173980+00:00  DEBUG    ┝━ 🐛 [debug]: connected to 127.0.0.1:17170
2025-04-15T21:41:49.702658697+00:00  DEBUG    ┝━ 🐛 [debug]: pooling idle connection for ("http", localhost:17170)
2025-04-15T21:41:49.703050731+00:00  INFO     ┕━ i [info]: Success
Error: Healthcheck failed

I look at the code (disclaimer: I do not know Rust), and when I read this:

github.com/lldap/lldap@1f89059c84/server/src/main.rs (L254)

github.com/lldap/lldap@1f89059c84/server/src/healthcheck.rs (L73-L75)

It seems I can override whatever, healthcheck will still try to connect at localhost.

<!-- gh-comment-id:2807594192 --> @nioc commented on GitHub (Apr 15, 2025): I tried some commands, but healthcheck never worked... ``` sh feabccca4adf:/app# /app/lldap healthcheck --config-file /data/lldap_config.toml -v --ldap-host 172.30.0.2 Loading configuration from /data/lldap_config.toml Configuration: Configuration { ldap_host: "172.30.0.2", ldap_port: 3890, http_host: "0.0.0.0", http_port: 17170, jwt_secret: ***SECRET***, ldap_base_dn: "dc=bidule,dc=machin", ldap_user_dn: "admin", ldap_user_email: "", ldap_user_pass: ***SECRET***, force_ldap_user_pass_reset: False, force_update_private_key: false, database_url: "sqlite:///data/users.db?mode=rwc", ignored_user_attributes: [], ignored_group_attributes: [], verbose: true, key_file: "", key_seed: Some( ***SECRET***, ), smtp_options: MailOptions { enable_password_reset: false, from: None, reply_to: None, server: "localhost", port: 587, user: "", password: ***SECRET***, smtp_encryption: Tls, .. }, ldaps_options: LdapsOptions { enabled: false, port: 6360, cert_file: "cert.pem", key_file: "key.pem", }, http_url: "http://localhost/", .. } Generating the private key from the key_seed 2025-04-15T21:41:49.700464618+00:00 INFO i [info]: Starting healthchecks 2025-04-15T21:41:49.700679249+00:00 INFO check_ldaps [ 16.9µs | 100.00% ] port: 6360 2025-04-15T21:41:49.700695872+00:00 INFO ┕━ i [info]: LDAPS not enabled 2025-04-15T21:41:49.701592738+00:00 DEBUG 🐛 [debug]: resolving host="localhost" 2025-04-15T21:41:49.700534742+00:00 INFO check_ldap [ 347µs | 100.00% ] port: 3890 2025-04-15T21:41:49.701978766+00:00 ERROR ┕━ 🚨 [error]: | error: Connection refused (os error 111) 2025-04-15T21:41:49.702442670+00:00 DEBUG 🐛 [debug]: flushed 60 bytes 2025-04-15T21:41:49.702571462+00:00 DEBUG 🐛 [debug]: parsed 2 headers 2025-04-15T21:41:49.702583475+00:00 DEBUG 🐛 [debug]: incoming body is empty 2025-04-15T21:41:49.700748255+00:00 INFO check_api [ 1.63ms | 100.00% ] port: 17170 2025-04-15T21:41:49.701739690+00:00 DEBUG ┝━ 🐛 [debug]: connecting to [::1]:17170 2025-04-15T21:41:49.702043791+00:00 DEBUG ┝━ 🐛 [debug]: connecting to 127.0.0.1:17170 2025-04-15T21:41:49.702173980+00:00 DEBUG ┝━ 🐛 [debug]: connected to 127.0.0.1:17170 2025-04-15T21:41:49.702658697+00:00 DEBUG ┝━ 🐛 [debug]: pooling idle connection for ("http", localhost:17170) 2025-04-15T21:41:49.703050731+00:00 INFO ┕━ i [info]: Success Error: Healthcheck failed ``` I look at the code (disclaimer: I do not know Rust), and when I read this: https://github.com/lldap/lldap/blob/1f89059c84d700ca198b2785657f33f438ea3e11/server/src/main.rs#L254 https://github.com/lldap/lldap/blob/1f89059c84d700ca198b2785657f33f438ea3e11/server/src/healthcheck.rs#L73-L75 It seems I can override whatever, healthcheck will still try to connect at `localhost`.
Author
Owner

@nitnelave commented on GitHub (Apr 15, 2025):

Ah, yes, sorry for misleading you. I guess that's not implemented, then.

<!-- gh-comment-id:2807633291 --> @nitnelave commented on GitHub (Apr 15, 2025): Ah, yes, sorry for misleading you. I guess that's not implemented, then.
Author
Owner

@fsdrw08 commented on GitHub (Apr 21, 2025):

currently, lldap healthcheck command can only detect the instance which running and listen on localhost

<!-- gh-comment-id:2817619527 --> @fsdrw08 commented on GitHub (Apr 21, 2025): currently, lldap healthcheck command can only detect the instance which running and listen on localhost
Author
Owner

@sdwilsh commented on GitHub (Oct 11, 2025):

@nitnelave, would you accept a PR to have the healthcheck use the configured address instead of a hardcoded localhost as you suggested in https://github.com/lldap/lldap/issues/700#issuecomment-2803582451? I think that meets the requirements of not breaking existing configurations for the default config nor for those who might have set an IP address.

<!-- gh-comment-id:3392956472 --> @sdwilsh commented on GitHub (Oct 11, 2025): @nitnelave, would you accept a PR to have the healthcheck use the configured address instead of a hardcoded `localhost` as you suggested in https://github.com/lldap/lldap/issues/700#issuecomment-2803582451? I think that meets the requirements of not breaking existing configurations for the default config nor for those who might have set an IP address.
Author
Owner

@nitnelave commented on GitHub (Oct 11, 2025):

I would accept a PR adding arguments to override the health check target addresses, yes

<!-- gh-comment-id:3392981069 --> @nitnelave commented on GitHub (Oct 11, 2025): I would accept a PR adding arguments to override the health check target addresses, yes
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/lldap-lldap#248
No description provided.