Skip to content

DB config, including port, through libpq env vars#1647

Merged
brontolosone merged 8 commits intogetodk:nextfrom
brontolosone:db-config-through-libpq-env-vars
Mar 2, 2026
Merged

DB config, including port, through libpq env vars#1647
brontolosone merged 8 commits intogetodk:nextfrom
brontolosone:db-config-through-libpq-env-vars

Conversation

@brontolosone
Copy link
Contributor

@brontolosone brontolosone commented Feb 14, 2026

Alternative to this contributor PR: #915

Companion PR to getodk/central-backend#1748

This demonstrates using the backend's new DB configuration approach (through libpq's PG* environment variables) in the Central dockerized setup.

In a nutshell:

  • Backwards compatible with existing .env files
  • Though users should be encouraged to head to our docs to learn about the PostgreSQL libpq env vars in order to set PG* environment variables in the .env to configure their database access to the full extent now made possible.

What has been done to verify that this works as intended?

Deployed to dev.getodk.cloud .

Why is this the best possible solution? Were any other approaches considered?

Not being backwards compatible would have been easier and more clear. But then users would be required to do a (trivial? 🤷‍♂️ ) migration of their .env database directives to the new variables.

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

Users may have workarounds for our previous incapability of exposing the full configuration surface (for instance, one couldn't configure the port number).

In particular for the port number, users have been tacking it onto the host variable, which would work in a number of places (but also not, in some others, eg probably not for wait-for-it) as we would concatenate host and port number anyway to form a connection URI, and had hardcoded the port number there). But this doesn't work with the environment variables.

If we want to pursue backwards compatibility even for THAT kind of workaround, then I would suggest we modify service/scripts/start-odk.sh some more, see if the port is unset yet the host ends with a port specification, and then mangle the variables appropriately.

Does this change require updates to documentation? If so, please file an issue here and include the link below.

The additional comments I made in .env.example suffice to explain, in my opinion.

Before submitting this PR, please make sure you have:

  • branched off and targeted the next branch OR only changed documentation/infrastructure (master is stable and used in production)
  • verified that any code or assets from external sources are properly credited in comments or that everything is internally sourced

@brontolosone brontolosone changed the base branch from master to next February 14, 2026 12:28
@brontolosone brontolosone force-pushed the db-config-through-libpq-env-vars branch 2 times, most recently from 8c1ab99 to 3ac371c Compare February 14, 2026 12:33
@brontolosone brontolosone marked this pull request as ready for review February 14, 2026 12:36
@brontolosone brontolosone force-pushed the db-config-through-libpq-env-vars branch from 3ac371c to 8aeec85 Compare February 14, 2026 12:38
@matthew-white
Copy link
Member

Users may have workarounds for our previous incapability of exposing the full configuration surface …
In particular for the port number, users have been tacking it onto the host variable, which would work in a number of places (but also not, in some others) … If we want to pursue backwards compatibility even for THAT kind of workaround, then I would suggest we modify service/scripts/start-odk.sh some more

My initial feeling is that we don't need to support this particular workaround. Let's just make it clear how to set the port going forward.

@matthew-white
Copy link
Member

Just FYI, it looks like CI failed. It looks like #1640 to me. Could it be because .gitmodules changed? Maybe try rerunning the failed action? Maybe we just need the Backend PR to get merged so .gitmodules doesn't have to change.

@matthew-white
Copy link
Member

Users may have workarounds for our previous incapability of exposing the full configuration surface …
In particular for the port number, users have been tacking it onto the host variable, which would work in a number of places (but also not, in some others) … If we want to pursue backwards compatibility even for THAT kind of workaround, then I would suggest we modify service/scripts/start-odk.sh some more

My initial feeling is that we don't need to support this particular workaround. Let's just make it clear how to set the port going forward.

I may have spoken too hastily here. Let's get a second opinion from @lognaturel. I see that she requested that:

could you please check whether [including the port in DB_HOST is] possible and if so make sure that the approach taken here is compatible with it?

@lognaturel
Copy link
Member

I disagree with myself of the past! Anyone who had been somehow getting a port number in is probably more technical. I can put a note in the upgrade docs on how to migrate to the new way. I've added that to the docs issue.

@brontolosone brontolosone force-pushed the db-config-through-libpq-env-vars branch from 8aeec85 to add3b93 Compare February 27, 2026 09:36
… provide backward compatibility for DB_* environment variables
@brontolosone brontolosone force-pushed the db-config-through-libpq-env-vars branch from add3b93 to 5f6dd0b Compare February 27, 2026 09:44
# Ideally we'd set the corresponding PG* variable here, but we can't, because we can't translate values here.
# So to maintain backwards compatibility with existing .env files, this one is handled in `start-odk.sh`:
# if `true`; and PGSSLMODE nor PGREQUIRESSL are defined, then we set PGSSLMODE=require.
- DB_SSL=${DB_SSL:-null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- DB_SSL=${DB_SSL:-null}
- DB_SSL=${DB_SSL:-}

If DB_SSL is only relevant to shell stuff now, maybe an empty string reads better than null? null made sense when this value was being passed off to JSON/JS, but maybe it's kind of historical baggage now.

No strong feelings, also fine to keep.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, we can now drop this line (and comment) altogether. If DB_SSL is set in the .env, it will now end up in the container's env (and thus start-odk.sh) anyways, because of that newly added env_file: ".env" in the dockerfile. Thus: 860b29d

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think the explictness is helpful. It documents which environment variables in .env are relevant to the service container and which aren't. E.g., DOMAIN=${DOMAIN} and SYSADMIN_EMAIL=${SYSADMIN_EMAIL} could now go away given env_file: "env", but I'm not totally convinced we want to do that yet.

So I'd say let's keep it DB_SSL=${DB_SSL:-null} or make it DB_SSL=${DB_SSL:-}, but I think it's worth it to continue listing the variable. Otherwise, there's no single list of environment variables anymore.

Copy link
Member

@matthew-white matthew-white Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to get the PG* env vars out of docker-compose.yml so that you can distinguish between empty vs. unset. It's necessary to move them out, and there's also no point in trying to list all the PG* vars, since we don't know which PG* vars will actually be used in .env. But I think DB_SSL is a different case, as we aren't passing it to Postgres. It's our own variable, and it'd be good to document its existence. So for DB_SSL, I'd prefer leaving it in docker-compose.yml for now. We can always reevaluate that later, just in terms of getting this PR merged.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I see you added a comment about DB_SSL to docker-compose.yml, so maybe that's enough. 🤔 But then it feels kind of inconsistent with our treatment of vars like DOMAIN and SYSADMIN_EMAIL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how it's nice that start-odk.sh handles all DB-related vars now without docker-compose.yml getting in the way. E.g., start-odk.sh is also now the only place where DB_HOST appears. So I think I'm talking myself into DB_SSL staying just in start-odk.sh and not docker-compose.yml. Sorry for the back and forth, I'm happy either way at this point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BackwardsCompat and TidyBranchless are seldom seen walking hand in hand. 🤷‍♂️

Comment on lines +58 to +61
- PGHOST=${PGHOST:-${DB_HOST:-postgres14}}
- PGUSER=${PGUSER:-${DB_USER:-odk}}
- PGPASSWORD=${PGPASSWORD:-${DB_PASSWORD:-odk}}
- PGDATABASE=${PGDATABASE:-${DB_NAME:-odk}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, will users ever need one or more of these env vars to be empty strings? Seems like that's not possible right now: they will always fall back to some default value.

Copy link
Contributor Author

@brontolosone brontolosone Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh.

On my machine if I empty all these PG*s, I get connected to the database of the same name as my unix user, over a unix socket, using peer auth (no password).
So that's a scenario in which it matters (that these vars are empty), but that's not a scenario you'd encounter in our docker setup; you'd always connect over the network, not over a unix socket, thus no peer auth and no visibility of your unix uid on the serverside, and thus also no default database.

But I guess you could have an empty password. Plus PostgreSQL has a 'trust' auth mode which does what it says and works over the network. And in that case you'd also be annoyed because you can't express "no or empty password". You couldn't before this change either, though.

So what we really need is to be able to distinguish "variable is undefined" from "variable is empty". Bash can do that in a clean way apparently, so if we move this logic out of this yaml into start-odk.sh (where, anyway, the DB_SSL logic already exclusively lives now, since 860b29d), then we could behave properly.

Copy link
Contributor Author

@brontolosone brontolosone Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

40c0b52 implements the above idea, it's running on dev.getodk.cloud .

Copy link
Member

@matthew-white matthew-white left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking great!

My only real question at this point is my comment about whether there are cases where one of PGHOST, PGUSER, PGPASSWORD, or PGDATABASE must be an empty string. I don't think we really support that case right now. But maybe it's a non-issue. Certainly it would be a preexisting issue — one that we could track in a follow-up issue. I'll go ahead and approve assuming that it's a non-issue, but I'm also happy to keep discussing it here.

@brontolosone brontolosone force-pushed the db-config-through-libpq-env-vars branch from c7153bb to 40c0b52 Compare February 28, 2026 17:07
@brontolosone
Copy link
Contributor Author

I added support for specifying empty PG* vars, we won't override them, and they'll end up in the container env.
@matthew-white Please re-review!

Copy link
Member

@matthew-white matthew-white left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! I don't have super strong feelings on DB_SSL anymore, so I'd say just do whatever feels the most consistent.

@brontolosone brontolosone merged commit d10cccb into getodk:next Mar 2, 2026
5 checks passed
@brontolosone brontolosone mentioned this pull request Mar 3, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants