Search code examples
phppostgresqlapacheselinux

PHP PDO Unix socket to Postgresql fails


Testing out a LAMP like application, fails with:

SQLSTATE[08006] [7] connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory

After a lot of troubleshooting, I am stumped. I may have to resort to reinstalling linux to fix any issues I introduced by blindly hacking away. Before I do that, is there any way to debug this to get at the root cause?

This is my LAMP box:

  • Postgresql 14
  • Fedora Linux 36 (Workstation Edition)
  • php 4.1.12
  • Apache 2.2

This is what I have tried so far:

  1. Check that the file exists. It does, but is the lock a problem?
[xxx@mybox~]$ sudo ls -al /tmp/.s.*
srwxrwxrwx. 1 postgres postgres  0 Nov 28 12:10 /tmp/.s.PGSQL.5432
-rw-------. 1 postgres postgres 48 Nov 28 12:10 /tmp/.s.PGSQL.5432.lock
  1. Try to connect with php. It connects and returns expected table data from Postgresql.

php /var/www/html/lamp/connect.php

  1. Try with curl. Errors.

curl http://localhost/lamp/connect.php

SQLSTATE[08006] [7] connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory Is the server running locally and accepting connections on that socket?

Test file connect.php. Use PDO to connect to Postgresql:

<?php

require_once 'config.php';

function connect(string $host, string $db, string $user, string $password): PDO
{
        try {
                $dsn = "pgsql:host=/tmp;port=5432;dbname=$db";

                // make a database connection
                return new PDO(
                        $dsn,
                        $user,
                        $password,
                        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
                );
        } catch (PDOException $e) {
                die($e->getMessage());
        }
}

return connect($host, $db, $user, $password);
  1. I have tried troubleshooting SELinux following
    Troubleshooting SELinux.

I did find an audit log notice which relates directly to the issue, used sealert to allow the access required. That didn't work. I disabled the repair modules may have screwed up SE because I can't find the denial anymore. Turning SE and Firewall off does not work either.

[peter@fedora ~]$ getenforce
Permissive
$ firewall-cmd --state
not running

Solution

  • Modern Ubuntu/Debian+systemd installs have a relegated /tmp/ directory for the Apache server process. It is from a feature of systemd called PrivateTmp. It's supposed to be more "secure" or something. This means /tmp/ from the command line doesn't equal /tmp/ from within PHP, instead being somewhere in /var/tmp/, e.g. /var/tmp/blabla-0123456abcd.

    You can disable it by editing the .service file and setting PrivateTmp=no.

    Other workarounds

    Try specifying host=localhost:port=5432 in your $dsn. This'll force it connect over the "network."

    $dsn = "pgsql:host=localhost;port=5432;dbname=$db";
    

    If that doesn't work, try leaving out the host= and port= from your DSN. AFAIK this'll make PDO connect to the local socket:

    $dsn = "pgsql:dbname=$db";
    

    Another workaround would be to have Postgres store its socket somewhere other than /tmp. See the PostgreSQL docs on how to change this.