lol
at 23.11-beta 329 lines 13 kB view raw view rendered
1# PostgreSQL {#module-postgresql} 2 3<!-- FIXME: render nicely --> 4<!-- FIXME: source can be added automatically --> 5 6*Source:* {file}`modules/services/databases/postgresql.nix` 7 8*Upstream documentation:* <https://www.postgresql.org/docs/> 9 10<!-- FIXME: more stuff, like maintainer? --> 11 12PostgreSQL is an advanced, free relational database. 13<!-- MORE --> 14 15## Configuring {#module-services-postgres-configuring} 16 17To enable PostgreSQL, add the following to your {file}`configuration.nix`: 18``` 19services.postgresql.enable = true; 20services.postgresql.package = pkgs.postgresql_15; 21``` 22Note that you are required to specify the desired version of PostgreSQL (e.g. `pkgs.postgresql_15`). Since upgrading your PostgreSQL version requires a database dump and reload (see below), NixOS cannot provide a default value for [](#opt-services.postgresql.package) such as the most recent release of PostgreSQL. 23 24<!-- 25After running {command}`nixos-rebuild`, you can verify 26whether PostgreSQL works by running {command}`psql`: 27 28```ShellSession 29$ psql 30psql (9.2.9) 31Type "help" for help. 32 33alice=> 34``` 35--> 36 37By default, PostgreSQL stores its databases in {file}`/var/lib/postgresql/$psqlSchema`. You can override this using [](#opt-services.postgresql.dataDir), e.g. 38``` 39services.postgresql.dataDir = "/data/postgresql"; 40``` 41 42## Initializing {#module-services-postgres-initializing} 43 44As of NixOS 23.11, 45`services.postgresql.ensureUsers.*.ensurePermissions` has been 46deprecated, after a change to default permissions in PostgreSQL 15 47invalidated most of its previous use cases: 48 49- In psql < 15, `ALL PRIVILEGES` used to include `CREATE TABLE`, where 50 in psql >= 15 that would be a separate permission 51- psql >= 15 instead gives only the database owner create permissions 52- Even on psql < 15 (or databases migrated to >= 15), it is 53 recommended to manually assign permissions along these lines 54 - https://www.postgresql.org/docs/release/15.0/ 55 - https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PRIV 56 57### Assigning ownership {#module-services-postgres-initializing-ownership} 58 59Usually, the database owner should be a database user of the same 60name. This can be done with 61`services.postgresql.ensureUsers.*.ensureDBOwnership = true;`. 62 63If the database user name equals the connecting system user name, 64postgres by default will accept a passwordless connection via unix 65domain socket. This makes it possible to run many postgres-backed 66services without creating any database secrets at all 67 68### Assigning extra permissions {#module-services-postgres-initializing-extra-permissions} 69 70For many cases, it will be enough to have the database user be the 71owner. Until `services.postgresql.ensureUsers.*.ensurePermissions` has 72been re-thought, if more users need access to the database, please use 73one of the following approaches: 74 75**WARNING:** `services.postgresql.initialScript` is not recommended 76for `ensurePermissions` replacement, as that is *only run on first 77start of PostgreSQL*. 78 79**NOTE:** all of these methods may be obsoleted, when `ensure*` is 80reworked, but it is expected that they will stay viable for running 81database migrations. 82 83**NOTE:** please make sure that any added migrations are idempotent (re-runnable). 84 85#### as superuser {#module-services-postgres-initializing-extra-permissions-superuser} 86 87**Advantage:** compatible with postgres < 15, because it's run 88as the database superuser `postgres`. 89 90##### in database `postStart` {#module-services-postgres-initializing-extra-permissions-superuser-post-start} 91 92**Disadvantage:** need to take care of ordering yourself. In this 93example, `mkAfter` ensures that permissions are assigned after any 94databases from `ensureDatabases` and `extraUser1` from `ensureUsers` 95are already created. 96 97```nix 98 systemd.services.postgresql.postStart = lib.mkAfter '' 99 $PSQL service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 100 $PSQL service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 101 # .... 102 ''; 103``` 104 105##### in intermediate oneshot service {#module-services-postgres-initializing-extra-permissions-superuser-oneshot} 106 107```nix 108 systemd.services."migrate-service1-db1" = { 109 serviceConfig.Type = "oneshot"; 110 requiredBy = "service1.service"; 111 before = "service1.service"; 112 after = "postgresql.service"; 113 serviceConfig.User = "postgres"; 114 environment.PSQL = "psql --port=${toString services.postgresql.port}"; 115 path = [ postgresql ]; 116 script = '' 117 $PSQL service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 118 $PSQL service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 119 # .... 120 ''; 121 }; 122``` 123 124#### as service user {#module-services-postgres-initializing-extra-permissions-service-user} 125 126**Advantage:** re-uses systemd's dependency ordering; 127 128**Disadvantage:** relies on service user having grant permission. To be combined with `ensureDBOwnership`. 129 130##### in service `preStart` {#module-services-postgres-initializing-extra-permissions-service-user-pre-start} 131 132```nix 133 environment.PSQL = "psql --port=${toString services.postgresql.port}"; 134 path = [ postgresql ]; 135 systemd.services."service1".preStart = '' 136 $PSQL -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 137 $PSQL -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 138 # .... 139 ''; 140``` 141 142##### in intermediate oneshot service {#module-services-postgres-initializing-extra-permissions-service-user-oneshot} 143 144```nix 145 systemd.services."migrate-service1-db1" = { 146 serviceConfig.Type = "oneshot"; 147 requiredBy = "service1.service"; 148 before = "service1.service"; 149 after = "postgresql.service"; 150 serviceConfig.User = "service1"; 151 environment.PSQL = "psql --port=${toString services.postgresql.port}"; 152 path = [ postgresql ]; 153 script = '' 154 $PSQL -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 155 $PSQL -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 156 # .... 157 ''; 158 }; 159``` 160 161## Upgrading {#module-services-postgres-upgrading} 162 163::: {.note} 164The steps below demonstrate how to upgrade from an older version to `pkgs.postgresql_13`. 165These instructions are also applicable to other versions. 166::: 167 168Major PostgreSQL upgrades require a downtime and a few imperative steps to be called. This is the case because 169each major version has some internal changes in the databases' state during major releases. Because of that, 170NixOS places the state into {file}`/var/lib/postgresql/&lt;version&gt;` where each `version` 171can be obtained like this: 172``` 173$ nix-instantiate --eval -A postgresql_13.psqlSchema 174"13" 175``` 176For an upgrade, a script like this can be used to simplify the process: 177``` 178{ config, pkgs, ... }: 179{ 180 environment.systemPackages = [ 181 (let 182 # XXX specify the postgresql package you'd like to upgrade to. 183 # Do not forget to list the extensions you need. 184 newPostgres = pkgs.postgresql_13.withPackages (pp: [ 185 # pp.plv8 186 ]); 187 in pkgs.writeScriptBin "upgrade-pg-cluster" '' 188 set -eux 189 # XXX it's perhaps advisable to stop all services that depend on postgresql 190 systemctl stop postgresql 191 192 export NEWDATA="/var/lib/postgresql/${newPostgres.psqlSchema}" 193 194 export NEWBIN="${newPostgres}/bin" 195 196 export OLDDATA="${config.services.postgresql.dataDir}" 197 export OLDBIN="${config.services.postgresql.package}/bin" 198 199 install -d -m 0700 -o postgres -g postgres "$NEWDATA" 200 cd "$NEWDATA" 201 sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" 202 203 sudo -u postgres $NEWBIN/pg_upgrade \ 204 --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ 205 --old-bindir $OLDBIN --new-bindir $NEWBIN \ 206 "$@" 207 '') 208 ]; 209} 210``` 211 212The upgrade process is: 213 214 1. Rebuild nixos configuration with the configuration above added to your {file}`configuration.nix`. Alternatively, add that into separate file and reference it in `imports` list. 215 2. Login as root (`sudo su -`) 216 3. Run `upgrade-pg-cluster`. It will stop old postgresql, initialize a new one and migrate the old one to the new one. You may supply arguments like `--jobs 4` and `--link` to speedup migration process. See <https://www.postgresql.org/docs/current/pgupgrade.html> for details. 217 4. Change postgresql package in NixOS configuration to the one you were upgrading to via [](#opt-services.postgresql.package). Rebuild NixOS. This should start new postgres using upgraded data directory and all services you stopped during the upgrade. 218 5. After the upgrade it's advisable to analyze the new cluster. 219 220 - For PostgreSQL ≥ 14, use the `vacuumdb` command printed by the upgrades script. 221 - For PostgreSQL < 14, run (as `su -l postgres` in the [](#opt-services.postgresql.dataDir), in this example {file}`/var/lib/postgresql/13`): 222 223 ``` 224 $ ./analyze_new_cluster.sh 225 ``` 226 227 ::: {.warning} 228 The next step removes the old state-directory! 229 ::: 230 231 ``` 232 $ ./delete_old_cluster.sh 233 ``` 234 235## Options {#module-services-postgres-options} 236 237A complete list of options for the PostgreSQL module may be found [here](#opt-services.postgresql.enable). 238 239## Plugins {#module-services-postgres-plugins} 240 241Plugins collection for each PostgreSQL version can be accessed with `.pkgs`. For example, for `pkgs.postgresql_15` package, its plugin collection is accessed by `pkgs.postgresql_15.pkgs`: 242```ShellSession 243$ nix repl '<nixpkgs>' 244 245Loading '<nixpkgs>'... 246Added 10574 variables. 247 248nix-repl> postgresql_15.pkgs.<TAB><TAB> 249postgresql_15.pkgs.cstore_fdw postgresql_15.pkgs.pg_repack 250postgresql_15.pkgs.pg_auto_failover postgresql_15.pkgs.pg_safeupdate 251postgresql_15.pkgs.pg_bigm postgresql_15.pkgs.pg_similarity 252postgresql_15.pkgs.pg_cron postgresql_15.pkgs.pg_topn 253postgresql_15.pkgs.pg_hll postgresql_15.pkgs.pgjwt 254postgresql_15.pkgs.pg_partman postgresql_15.pkgs.pgroonga 255... 256``` 257 258To add plugins via NixOS configuration, set `services.postgresql.extraPlugins`: 259``` 260services.postgresql.package = pkgs.postgresql_12; 261services.postgresql.extraPlugins = with pkgs.postgresql_12.pkgs; [ 262 pg_repack 263 postgis 264]; 265``` 266 267You can build custom PostgreSQL-with-plugins (to be used outside of NixOS) using function `.withPackages`. For example, creating a custom PostgreSQL package in an overlay can look like: 268``` 269self: super: { 270 postgresql_custom = self.postgresql_12.withPackages (ps: [ 271 ps.pg_repack 272 ps.postgis 273 ]); 274} 275``` 276 277Here's a recipe on how to override a particular plugin through an overlay: 278``` 279self: super: { 280 postgresql_15 = super.postgresql_15.override { this = self.postgresql_15; } // { 281 pkgs = super.postgresql_15.pkgs // { 282 pg_repack = super.postgresql_15.pkgs.pg_repack.overrideAttrs (_: { 283 name = "pg_repack-v20181024"; 284 src = self.fetchzip { 285 url = "https://github.com/reorg/pg_repack/archive/923fa2f3c709a506e111cc963034bf2fd127aa00.tar.gz"; 286 sha256 = "17k6hq9xaax87yz79j773qyigm4fwk8z4zh5cyp6z0sxnwfqxxw5"; 287 }; 288 }); 289 }; 290 }; 291} 292``` 293 294## JIT (Just-In-Time compilation) {#module-services-postgres-jit} 295 296[JIT](https://www.postgresql.org/docs/current/jit-reason.html)-support in the PostgreSQL package 297is disabled by default because of the ~300MiB closure-size increase from the LLVM dependency. It 298can be optionally enabled in PostgreSQL with the following config option: 299 300```nix 301{ 302 services.postgresql.enableJIT = true; 303} 304``` 305 306This makes sure that the [`jit`](https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-JIT)-setting 307is set to `on` and a PostgreSQL package with JIT enabled is used. Further tweaking of the JIT compiler, e.g. setting a different 308query cost threshold via [`jit_above_cost`](https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-JIT-ABOVE-COST) 309can be done manually via [`services.postgresql.settings`](#opt-services.postgresql.settings). 310 311The attribute-names of JIT-enabled PostgreSQL packages are suffixed with `_jit`, i.e. for each `pkgs.postgresql` 312(and `pkgs.postgresql_<major>`) in `nixpkgs` there's also a `pkgs.postgresql_jit` (and `pkgs.postgresql_<major>_jit`). 313Alternatively, a JIT-enabled variant can be derived from a given `postgresql` package via `postgresql.withJIT`. 314This is also useful if it's not clear which attribute from `nixpkgs` was originally used (e.g. when working with 315[`config.services.postgresql.package`](#opt-services.postgresql.package) or if the package was modified via an 316overlay) since all modifications are propagated to `withJIT`. I.e. 317 318```nix 319with import <nixpkgs> { 320 overlays = [ 321 (self: super: { 322 postgresql = super.postgresql.overrideAttrs (_: { pname = "foobar"; }); 323 }) 324 ]; 325}; 326postgresql.withJIT.pname 327``` 328 329evaluates to `"foobar"`.