Library / SDK
geerlingguy/ansible-role-postgresql avatar
geerlingguy/ansible-role-postgresql

The geerlingguy PostgreSQL Ansible role, and where its defaults bite

Ansible Role - PostgreSQL

656 stars414 forksJinjaMIT

At a glance

What is it?
This role installs and configures a PostgreSQL server on RHEL/CentOS and Debian/Ubuntu hosts, with a long list of variables for databases, users, pg_hba.conf and postgresql.conf. It is opinionated, MIT licensed, and needs root plus the community.postgresql collection.
Who is it for?
Adopt geerlingguy.postgresql when you standardise PostgreSQL across RHEL/CentOS or Debian/Ubuntu hosts and want one reviewed set of defaults for packages, service state, pg_hba.conf and roles. Do not use it where you need a non-root setup, an unsupported distribution, or privileged settings the role does not expose, and note that the pg_hba_entries default is a full list rather than a merge.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Jinja, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One role for PostgreSQL on RHEL and Debian families

geerlingguy/ansible-role-postgresql is an Ansible role whose stated job is to install and configure PostgreSQL server on RHEL/CentOS or Debian/Ubuntu servers. That is the entire promise, and it is a small one, which is exactly why the role is easy to reason about. The users are infrastructure teams who keep landing on one of those two distribution families and want the same database server built the same way every time: same packages, same service state, same authentication rules, same database and user layout. The repository layout matches the shape of a well behaved role, with defaults/ holding every documented variable, tasks/, templates/, handlers/, vars/ and meta/ directories, plus molecule/ for scenario testing and an .ansible-lint configuration for linting. The primary language is listed as Jinja, which is the templating layer rather than a scripting language, and the project was created in 2016 by Jeff Geerling. It is published on Ansible Galaxy as geerlingguy.postgresql, and the code is MIT licensed.

Root access and the collection you must install first

The role needs to run as root, and the documentation is explicit that there are no other special requirements. Two ways of arranging that are given. You can run the role inside a playbook with a global become: true, or set become on the role itself, in which case the playbook looks like this:

yaml
- hosts: database
  roles:
    - role: geerlingguy.postgresql
      become: true

The second requirement is quieter and bites first time users. If you are running the role with ansible-core rather than a full Ansible installation, you need the community.postgresql collection installed first, so that the PostgreSQL modules used by the role are available. A missing collection is a hard failure at task execution, not a warning, and the fix is on the operator rather than in the role. Together these two facts define the audience: this is a role for teams whose automation already runs privileged, either through become on a Linux host or through a container platform that maps root inside the container to a privileged execution context.

The defaults decide the shape of the deployment

Most of the role behaviour lives in defaults/main.yml, and reading that file is the closest thing to understanding the role. The service is set to started and enabled, so it comes up at boot. The service state used when configuration changes land is set to restarted, with reloaded offered as the other recommended value. The unix socket directory list defaults to /var/run/postgresql, and the operating system user and group are postgres. The library Ansible uses to talk to the server defaults to python-psycopg2, and the documentation says that if you are on Python 3, set through ansible_python_interpreter for example, you should change it to python3-psycopg2. That single default is the most common friction point on modern distributions. Two more variables are worth noting: postgresql_enablerepo is empty by default and applies only on RHEL/CentOS, where it lets you choose the repository the packages come from, and a group of OS-specific variables, postgresql_version, postgresql_data_dir, postgresql_bin_path, postgresql_config_path, postgresql_daemon and postgresql_packages, is set by include files in the role's vars directory. The documentation warns against overriding those unless you installed PostgreSQL from something other than system packages.

postgresql.conf is written from an option and value list

Server configuration is handled by a single variable holding a list of option and value pairs, which the role writes into postgresql.conf:

yaml
postgresql_global_config_options:
  - option: unix_socket_directories
    value: '{{ postgresql_unix_socket_directories | join(",") }}'
  - option: log_directory
    value: 'log'

The default list is short on purpose, and the second entry shows the role taking responsibility for a detail you would otherwise handle by hand: if you override the value of the log_directory option with another path, relative or absolute, the role creates it for you. One compatibility detail is called out explicitly, that for PostgreSQL versions older than 9.3 you need to override this variable and set the option to unix_socket_directory instead of the plural form. That is a small signal about the age of the defaults. This variable is a list, so adding a server setting is a matter of appending an entry rather than replacing a file, which is a genuinely nicer way to run servers than templating a whole postgresql.conf yourself.

pg_hba.conf defaults replace rather than merge

Authentication is the part of the role that deserves the most attention, because the variable holds complete host based authentication entries:

yaml
postgresql_hba_entries:
  - { type: local, database: all, user: postgres, auth_method: peer }
  - { type: local, database: all, user: all, auth_method: peer }
  - { type: host, database: all, user: all, address: '127.0.0.1/32', auth_method: md5 }
  - { type: host, database: all, user: all, address: '::1/128', auth_method: md5 }

The shape is sensible for a single host: local connections authenticate with peer, loopback connections authenticate with md5, and nothing is exposed beyond that. What the documentation warns about is the override semantics. If you override postgresql_hba_entries, make sure you copy all of the existing entries from defaults/main.yml if you need to preserve existing entries. The list is the file, not a patch to it, so a partial override silently removes authentication lines you meant to keep. Each entry supports type, database and user as required, one of address, ip_address or ip_mask, a required auth_method, and optional auth_options. On a machine that already has other databases or other services in the same file, read that default file before you write your own list.

Databases, roles and privileges are declarative lists

The three stateful parts of the role are lists. postgresql_databases ensures each named database exists, with only the name required and everything else optional; the documented defaults include lc_collate and lc_ctype of en_US.UTF-8, encoding UTF-8, template template0, login_host localhost, a login_user that defaults to the postgresql_user value, a login_unix_socket that defaults to the first entry of postgresql_unix_socket_directories, and a state of present. postgresql_users works the same way for roles, with optional password, encrypted, role_attr_flags and db, and login_user defaulting to the postgresql_user value. postgresql_privs configures privileges and was new in role version 4.0.0, with db and roles required and privs, type, objs, schema, session_role, grant_option and target_roles all optional. Two details stand out. The privs entries carry their own login_host, login_password, login_user, login_unix_socket and port, so privilege changes can be performed by a different role than the one that created the objects. And postgres_users_no_log defaults to true, which controls whether user data, potentially including passwords, is printed when users are managed.

A first run, in one playbook and one variables file

The example playbook that ships with the role is short enough to copy:

yaml
- hosts: database
  become: yes
  vars_files:
    - vars/main.yml
  roles:
    - geerlingguy.postgresql

The variables file it points at holds the environment specific content, in this case one database and one user:

yaml
postgresql_databases:
  - name: example_db
postgresql_users:
  - name: example_user
    password: supersecure

Run that playbook and the role installs the server packages for the detected distribution, writes postgresql.conf and pg_hba.conf, starts the service, enables it at boot, and creates the database and the role. Two notes on the example. It uses become: yes at play level rather than become: true on the role, and the password is written in plain text in the variables file, which the postgres_users_no_log variable only affects in Ansible output, not in your source control. On Debian and Ubuntu the role also uses postgresql_locales, defaulting to en_US.UTF-8, to generate the locales PostgreSQL databases need.

Where the role stops, and what to use instead

Two boundaries define when this role is the wrong tool. The first is distribution support, which is limited to RHEL/CentOS and Debian/Ubuntu, so a Debian derivative outside that family or a Red Hat derivative with a different package layout is outside what the OS-specific vars cover. The second is privilege: the role requires root, so it cannot be used in an environment where the automation account is deliberately unprivileged, and there is no variable to relax that. The obvious alternative is not another role but the collection underneath it. The role itself depends on the PostgreSQL modules shipped in community.postgresql, and using those modules directly from your own tasks gives you the same database, user and privilege operations without the packaged defaults, the OS-specific packaging logic, and the pg_hba.conf and postgresql.conf management that comes with them. That trade is worth making when you already have your own host configuration, and worth refusing when you want a fresh host turned into a database server in one run. Maintenance is recent: the last push was on 2026-10-09, the project publishes no GitHub releases, so there are no version tags to pin, and the MIT licence and BSD mention in the licence section are what govern reuse.

Editorial conclusion

Adopt geerlingguy.postgresql when you standardise PostgreSQL across RHEL/CentOS or Debian/Ubuntu hosts and want one reviewed set of defaults for packages, service state, pg_hba.conf and roles. Do not use it where you need a non-root setup, an unsupported distribution, or privileged settings the role does not expose, and note that the pg_hba_entries default is a full list rather than a merge. Before the first run, confirm the community.postgresql collection is installed, set postgresql_python_library to python3-psycopg2 if your interpreter is Python 3, and read defaults/main.yml so you know which entries you will be replacing.

Frequently asked questions

What do I need before running the geerlingguy.postgresql Ansible role?

Root access on the target host, either through a global become: true in the playbook or become on the role itself, and the community.postgresql collection installed if you run ansible-core, so that the PostgreSQL modules the role uses are available.

How do I add a database and a user with this Ansible role?

Set postgresql_databases and postgresql_users as lists, where only the name is required and every other property has a documented default. The role documentation also exposes postgresql_privs for privileges, which is new in role version 4.0.0.

Will overriding postgresql_hba_entries keep my existing authentication rules?

No. The documentation says that if you override postgresql_hba_entries you must copy all of the existing entries from defaults/main.yml if you want to preserve existing entries, since the list describes the whole file rather than a change to it.

Which Python library does the role use to talk to PostgreSQL?

The default is postgresql_python_library set to python-psycopg2. If your interpreter is Python 3, for example when set via ansible_python_interpreter, the documentation says to change it to python3-psycopg2.

Official sources

  1. geerlingguy/ansible-role-postgresql on GitHub
  2. Issues
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/geerlingguy-ansible-role-postgresql.svg)](https://hysenlabs.com/projects/geerlingguy-ansible-role-postgresql)

Was this useful?