{"id":165029,"date":"2026-03-29T12:12:55","date_gmt":"2026-03-29T09:12:55","guid":{"rendered":"https:\/\/computingforgeeks.com\/install-postgresql-void-linux\/"},"modified":"2026-04-02T23:56:12","modified_gmt":"2026-04-02T20:56:12","slug":"install-postgresql-void-linux","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/install-postgresql-void-linux\/","title":{"rendered":"Install PostgreSQL on Void Linux"},"content":{"rendered":"\n<p>Void Linux is one of those distributions that rewards you for understanding how your system works. No systemd, no hand-holding, just runit and XBPS doing exactly what you tell them. PostgreSQL fits right into that philosophy: a database engine that does one thing extremely well and stays out of your way.<\/p>\n\n\n\n<p>This guide walks through installing PostgreSQL 16 on Void Linux, initializing the database cluster, creating a runit service from scratch (Void doesn&#8217;t ship one), and locking down authentication. If you&#8217;re coming from Debian or RHEL, the biggest difference is the service management piece, which we&#8217;ll cover in detail. For PostgreSQL on RHEL-based systems, see <a href=\"https:\/\/computingforgeeks.com\/install-postgresql-rocky-almalinux\/\">PostgreSQL on Rocky Linux 10<\/a>.<\/p>\n\n\n\n<p><em>Tested <strong>March 2026<\/strong> | Void Linux (glibc), PostgreSQL 16.10<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Void Linux (glibc variant, x86_64) with root or sudo access<\/li>\n\n\n\n<li>XBPS package manager up to date<\/li>\n\n\n\n<li>Tested on: Void Linux rolling (glibc), PostgreSQL 16.10<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Install PostgreSQL<\/h2>\n\n\n\n<p>Void&#8217;s XBPS repository ships PostgreSQL 16.x. Install the server and client packages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo xbps-install -Sy postgresql16 postgresql16-client<\/code><\/pre>\n\n\n\n<p>Confirm the installed version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>psql --version<\/code><\/pre>\n\n\n\n<p>You should see the version string confirming 16.x:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>psql (PostgreSQL) 16.10<\/code><\/pre>\n\n\n\n<p>XBPS creates a <code>postgres<\/code> system user automatically during installation. Verify it exists:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>id postgres<\/code><\/pre>\n\n\n\n<p>The output confirms the user and group:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uid=997(postgres) gid=997(postgres) groups=997(postgres)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. Initialize the Database Cluster<\/h2>\n\n\n\n<p>PostgreSQL needs an initialized data directory before it can start. Create the directory and set ownership to the <code>postgres<\/code> user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mkdir -p \/var\/lib\/postgresql\/data\nsudo chown postgres:postgres \/var\/lib\/postgresql\/data<\/code><\/pre>\n\n\n\n<p>Now initialize the cluster. This must run as the <code>postgres<\/code> user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres initdb -D \/var\/lib\/postgresql\/data<\/code><\/pre>\n\n\n\n<p>The initialization output shows the cluster being created with default settings:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>The files belonging to this database system will be owned by user \"postgres\".\nThis user must also own the server process.\n\nThe database cluster will be initialized with locale \"en_US.UTF-8\".\nThe default database encoding has accordingly been set to \"UTF8\".\nThe default text search configuration will be set to \"english\".\n\nData page checksums are disabled.\n\nfixing permissions on existing directory \/var\/lib\/postgresql\/data ... ok\ncreating subdirectories ... ok\nselecting dynamic shared memory implementation ... posix\nselecting default \"max_connections\" ... 100\nselecting default \"shared_buffers\" ... 128MB\nselecting default \"timezone\" ... UTC\ncreating configuration files ... ok\nrunning bootstrap script ... ok\nperforming post-bootstrap initialization ... ok\nsyncing data to disk ... ok\n\ninitdb: warning: enabling \"trust\" authentication for local connections\ninitdb: hint: You can change this by editing pg_hba.conf or using the option -A,\nor --auth-local and --auth-host, the next time you run initdb.\n\nSuccess. You can now start the database server using:\n\n    pg_ctl -D \/var\/lib\/postgresql\/data -l logfile start<\/code><\/pre>\n\n\n\n<p>Notice the warning about trust authentication. We&#8217;ll tighten that up after getting the service running.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Create a Runit Service<\/h2>\n\n\n\n<p>Void Linux uses runit for service management, and PostgreSQL doesn&#8217;t ship with a runit service file by default. You need to create one manually. This catches most people off guard when coming from distributions where <code>systemctl enable postgresql<\/code> just works.<\/p>\n\n\n\n<p>Create the service directory structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo mkdir -p \/etc\/sv\/postgresql\/log<\/code><\/pre>\n\n\n\n<p>Create the main run script that starts PostgreSQL as the <code>postgres<\/code> user:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/sv\/postgresql\/run<\/code><\/pre>\n\n\n\n<p>Add the following content:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/sh\nexec chpst -u postgres postgres -D \/var\/lib\/postgresql\/data 2>&1<\/code><\/pre>\n\n\n\n<p>Make it executable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chmod +x \/etc\/sv\/postgresql\/run<\/code><\/pre>\n\n\n\n<p>Now create the log service. Runit expects a <code>log\/run<\/code> script to capture output via <code>svlogd<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/sv\/postgresql\/log\/run<\/code><\/pre>\n\n\n\n<p>Add the logging script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/sh\nexec svlogd -tt \/var\/log\/postgresql<\/code><\/pre>\n\n\n\n<p>Make it executable and create the log directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chmod +x \/etc\/sv\/postgresql\/log\/run\nsudo mkdir -p \/var\/log\/postgresql<\/code><\/pre>\n\n\n\n<p>Enable the service by creating a symlink to <code>\/var\/service\/<\/code>. Runit picks it up automatically within a few seconds:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo ln -s \/etc\/sv\/postgresql \/var\/service\/<\/code><\/pre>\n\n\n\n<p>Check the service status:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo sv status postgresql<\/code><\/pre>\n\n\n\n<p>A healthy service looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>run: postgresql: (pid 1423) 5s; run: log: (pid 1420) 5s<\/code><\/pre>\n\n\n\n<p>If the status shows <code>down<\/code>, check the log at <code>\/var\/log\/postgresql\/current<\/code> for errors. Common causes include wrong permissions on the data directory or a missing <code>postgres<\/code> user.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Secure the Installation<\/h2>\n\n\n\n<p>The default <code>initdb<\/code> configuration uses trust authentication for local connections, which means any local user can connect as any database user without a password. Fix this by setting a password for the <code>postgres<\/code> superuser and switching to password-based authentication.<\/p>\n\n\n\n<p>Connect to PostgreSQL and set the superuser password:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres psql -c \"ALTER USER postgres PASSWORD 'StrongPassword123!';\"<\/code><\/pre>\n\n\n\n<p>The response confirms the change:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ALTER ROLE<\/code><\/pre>\n\n\n\n<p>Now edit <code>pg_hba.conf<\/code> to enforce password authentication. Open the file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/var\/lib\/postgresql\/data\/pg_hba.conf<\/code><\/pre>\n\n\n\n<p>Find the lines near the bottom that control local connections and change <code>trust<\/code> to <code>scram-sha-256<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \"local\" is for Unix domain socket connections only\nlocal   all             all                                     scram-sha-256\n# IPv4 local connections:\nhost    all             all             127.0.0.1\/32            scram-sha-256\n# IPv6 local connections:\nhost    all             all             ::1\/128                 scram-sha-256<\/code><\/pre>\n\n\n\n<p>Reload PostgreSQL to apply the changes without dropping existing connections:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres pg_ctl reload -D \/var\/lib\/postgresql\/data<\/code><\/pre>\n\n\n\n<p>The reload confirmation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server signaled<\/code><\/pre>\n\n\n\n<p>From now on, every connection requires a password. Test it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>psql -U postgres -h 127.0.0.1 -c \"SELECT version();\"<\/code><\/pre>\n\n\n\n<p>Enter the password you set earlier. The query output shows your running version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>                                                version\n---------------------------------------------------------------------------------------------------------\n PostgreSQL 16.10 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 13.2.0, 64-bit\n(1 row)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">5. Create a Database and User<\/h2>\n\n\n\n<p>Production applications should never connect as the <code>postgres<\/code> superuser. Create a dedicated user and database for your application.<\/p>\n\n\n\n<p>Connect as the superuser first:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>psql -U postgres -h 127.0.0.1<\/code><\/pre>\n\n\n\n<p>Create a new user, database, and grant privileges. This is an interactive psql session:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE USER appuser WITH PASSWORD 'AppUserPass456!';\nCREATE DATABASE appdb OWNER appuser;\nGRANT ALL PRIVILEGES ON DATABASE appdb TO appuser;\n\\q<\/code><\/pre>\n\n\n\n<p>Verify the new user can connect to the database:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>psql -U appuser -h 127.0.0.1 -d appdb -c \"\\conninfo\"<\/code><\/pre>\n\n\n\n<p>The connection info confirms the user and database:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>You are connected to database \"appdb\" as user \"appuser\" on host \"127.0.0.1\" at port \"5432\".<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Enable Remote Connections (Optional)<\/h2>\n\n\n\n<p>By default, PostgreSQL 16 listens only on localhost. If other machines on your network need to connect, you&#8217;ll need to change the listen address and add a firewall rule.<\/p>\n\n\n\n<p>Open the main configuration file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/var\/lib\/postgresql\/data\/postgresql.conf<\/code><\/pre>\n\n\n\n<p>Find the <code>listen_addresses<\/code> line and change it to listen on all interfaces:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>listen_addresses = '*'<\/code><\/pre>\n\n\n\n<p>Next, add a line to <code>pg_hba.conf<\/code> to allow connections from your network. Open the file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/var\/lib\/postgresql\/data\/pg_hba.conf<\/code><\/pre>\n\n\n\n<p>Add this line at the end, adjusting the subnet to match your network:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Allow connections from local network\nhost    all             all             10.0.1.0\/24             scram-sha-256<\/code><\/pre>\n\n\n\n<p>Restart PostgreSQL to apply the listen address change (a reload isn&#8217;t enough for <code>listen_addresses<\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo sv restart postgresql<\/code><\/pre>\n\n\n\n<p>Void Linux uses nftables for firewalling. Allow TCP port 5432:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nft add rule inet filter input tcp dport 5432 accept<\/code><\/pre>\n\n\n\n<p>To make the firewall rule persistent across reboots, save the current ruleset:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo nft list ruleset | sudo tee \/etc\/nftables.conf<\/code><\/pre>\n\n\n\n<p>Verify PostgreSQL is listening on all interfaces:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ss -tlnp | grep 5432<\/code><\/pre>\n\n\n\n<p>The output should show <code>0.0.0.0:5432<\/code> instead of <code>127.0.0.1:5432<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>LISTEN 0      244          0.0.0.0:5432       0.0.0.0:*    users:((\"postgres\",pid=1423,fd=6))<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">7. Basic psql Commands<\/h2>\n\n\n\n<p>Quick reference for the most common <code>psql<\/code> commands you&#8217;ll use daily. Connect with <code>psql -U postgres -h 127.0.0.1<\/code> and run these from the psql prompt:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Command<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>\\l<\/code><\/td><td>List all databases<\/td><\/tr><tr><td><code>\\dt<\/code><\/td><td>List tables in the current database<\/td><\/tr><tr><td><code>\\c dbname<\/code><\/td><td>Connect to a different database<\/td><\/tr><tr><td><code>\\d tablename<\/code><\/td><td>Describe a table (columns, types, indexes)<\/td><\/tr><tr><td><code>\\du<\/code><\/td><td>List all roles\/users<\/td><\/tr><tr><td><code>SELECT version();<\/code><\/td><td>Show the PostgreSQL server version<\/td><\/tr><tr><td><code>\\timing<\/code><\/td><td>Toggle query execution time display<\/td><\/tr><tr><td><code>\\x<\/code><\/td><td>Toggle expanded (vertical) output<\/td><\/tr><tr><td><code>\\q<\/code><\/td><td>Exit psql<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">PostgreSQL on Void vs Other Distros<\/h2>\n\n\n\n<p>If you manage PostgreSQL across multiple distributions, these are the key differences to keep in mind:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Item<\/th><th>Void Linux<\/th><th>Debian\/Ubuntu<\/th><th>RHEL\/Rocky 10<\/th><\/tr><\/thead><tbody><tr><td>Package name<\/td><td><code>postgresql16<\/code><\/td><td><code>postgresql-16<\/code><\/td><td><code>postgresql16-server<\/code><\/td><\/tr><tr><td>Data directory<\/td><td><code>\/var\/lib\/postgresql\/data<\/code><\/td><td><code>\/var\/lib\/postgresql\/16\/main<\/code><\/td><td><code>\/var\/lib\/pgsql\/16\/data<\/code><\/td><\/tr><tr><td>Config path<\/td><td><code>\/var\/lib\/postgresql\/data\/<\/code><\/td><td><code>\/etc\/postgresql\/16\/main\/<\/code><\/td><td><code>\/var\/lib\/pgsql\/16\/data\/<\/code><\/td><\/tr><tr><td>Service manager<\/td><td>runit (manual setup)<\/td><td>systemd<\/td><td>systemd<\/td><\/tr><tr><td>Start command<\/td><td><code>sv up postgresql<\/code><\/td><td><code>systemctl start postgresql<\/code><\/td><td><code>systemctl start postgresql-16<\/code><\/td><\/tr><tr><td>Auto-init on install<\/td><td>No<\/td><td>Yes<\/td><td>No (<code>postgresql-setup --initdb<\/code>)<\/td><\/tr><tr><td>Firewall<\/td><td>nftables<\/td><td>ufw<\/td><td>firewalld<\/td><\/tr><tr><td>SELinux\/AppArmor<\/td><td>Neither<\/td><td>AppArmor (usually permissive)<\/td><td>SELinux enforcing<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The biggest difference on Void is the manual service setup. On Debian, the package creates the cluster and starts the service automatically. On Void, you handle both yourself, which gives you full control over the data directory location and startup flags.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tuning for Production<\/h2>\n\n\n\n<p>PostgreSQL&#8217;s default configuration is deliberately conservative. On a dedicated database server, you&#8217;ll want to adjust these settings in <code>postgresql.conf<\/code>. The values below assume a server with 4 GB of RAM.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo -u postgres vi \/var\/lib\/postgresql\/data\/postgresql.conf<\/code><\/pre>\n\n\n\n<p>Key parameters to change:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Memory (adjust proportionally to your RAM)\nshared_buffers = 1GB              # 25% of total RAM\neffective_cache_size = 3GB        # 75% of total RAM\nwork_mem = 16MB                   # per-operation sort memory\nmaintenance_work_mem = 256MB      # for VACUUM, CREATE INDEX\n\n# WAL and checkpoints\nwal_buffers = 64MB\ncheckpoint_completion_target = 0.9\nmax_wal_size = 2GB\n\n# Connections\nmax_connections = 100             # lower this if using pgbouncer<\/code><\/pre>\n\n\n\n<p>After editing, reload the configuration without restarting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo sv reload postgresql<\/code><\/pre>\n\n\n\n<p>Some parameters (like <code>shared_buffers<\/code> and <code>max_connections<\/code>) require a full restart to take effect. Check the <a href=\"https:\/\/www.postgresql.org\/docs\/16\/\" target=\"_blank\" rel=\"noreferrer noopener\">PostgreSQL 16 documentation<\/a> for which settings need a restart versus a reload. For a web application backend, pairing this with a <a href=\"https:\/\/computingforgeeks.com\/install-lamp-stack-void-linux\/\" target=\"_blank\" rel=\"noreferrer noopener\">LAMP<\/a> or <a href=\"https:\/\/computingforgeeks.com\/install-nginx-void-linux\/\" target=\"_blank\" rel=\"noreferrer noopener\">Nginx<\/a> stack on the same Void Linux host works well for small to medium deployments. Once the database holds real data, set up a <a href=\"https:\/\/computingforgeeks.com\/postgresql-mariadb-backup-pitr\/\" target=\"_blank\" rel=\"noreferrer noopener\">backup strategy with point-in-time recovery<\/a> so you can restore to any moment before a failure.<\/p>\n\n\n","protected":false},"excerpt":{"rendered":"<p>Void Linux is one of those distributions that rewards you for understanding how your system works. No systemd, no hand-holding, just runit and XBPS doing exactly what you tell them. PostgreSQL fits right into that philosophy: a database engine that does one thing extremely well and stays out of your way. This guide walks through &#8230; <a title=\"Install PostgreSQL on Void Linux\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/install-postgresql-void-linux\/\" aria-label=\"Read more about Install PostgreSQL on Void Linux\">Read more<\/a><\/p>\n","protected":false},"author":32,"featured_media":165024,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[461,299,50,37631],"tags":[],"class_list":["post-165029","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-databases","category-how-to","category-linux-tutorials","category-postgresql"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/165029","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/32"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=165029"}],"version-history":[{"count":2,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/165029\/revisions"}],"predecessor-version":[{"id":165197,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/165029\/revisions\/165197"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/165024"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=165029"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=165029"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=165029"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}