Cannot connect to PostgreSQL unix domain socket
I'm trying to connect to PostgreSQL Unix domain socket from a PHP web application. Relevant system components:
- CentOS 7 x64 (SELinux enforced)
- postgresql93 9.3.5-2PGDG.rhel7
- nginx 1.6.2-1.el7.ngx
- php-common 5.4.16-23.el7_0.3
- php-fpm 5.4.16-23.el7_0.3
- php-pdo 5.4.16-23.el7_0.3
- php-pgsql 5.4.16-23.el7_0.3
PostgreSQL is listening on standard port 5432 and I have no problems to use it via TCP/IP at 127.0.0.1:5432, but when I try to connect to its Unix domain socket, I have a following error:
Cannot connect to database: SQLSTATE[08006] [7] could not connect to server:
No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
File /tmp/.s.PGSQL.5432 exists and I can connect using psql:
$ psql -Uusername db_name
psql (9.3.5)
Type "help" for help.
db_name=>
So there should be no problems from the PostgreSQL side. Or are there?
Relevant line from /var/lib/pgsql/9.3/data/pg_hba.conf:
local all username trust
Change of location for Unix domain socket file in /var/lib/pgsql/9.3/data/postgresql.conf did not help:
unix_socket_directories = '/var/run/pgsql'
There was nothing in /var/log/audit/audit.log, but I've tried to disable SELinux, just to be sure:
# setenforce 0
This did not help, so it is not SELinux.
Relevant lines from strace of php-fpm:
[pid 882] socket(PF_LOCAL, SOCK_STREAM, 0) = 5
[pid 882] fcntl(5, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
[pid 882] fcntl(5, F_SETFD, FD_CLOEXEC) = 0
[pid 882] connect(5, {sa_family=AF_LOCAL, sun_path="/tmp/.s.PGSQL.5432"}, 110) = -1 ENOENT (No such file or directory)
[pid 882] close(5) = 0
The file name is correct and, again, file /tmp/.s.PGSQL.5432 exists:
$ ls -l /tmp/.s.PGSQL.5432
srwxrwxrwx. 1 postgres postgres 0 Nov 1 09:47 /tmp/.s.PGSQL.5432
It looks like php-fpm process is not chroot'ed:
# ls -l /proc/882/root
lrwxrwxrwx. 1 apache apache 0 Oct 31 19:54 /proc/882/root -> /
At this point I have no more ideas where the problem can be and I would appreciate any help.
Solution 1:
I've resolved the problem. The initial cause of it was in systemd service file for php-fpm /usr/lib/systemd/system/php-fpm.service:
[Service]
PrivateTmp=true
This means that php-fpm could not see /tmp/.s.PGSQL.5432 nor anything else located in /tmp. To resolve the issue I've changed the location for PostgreSQL Unix domain socket file with following steps:
-
Create a new directory /var/pgsql (note changing SELinux file context):
# mkdir /var/pgsql # chown posgres:postgres /var/pgsql # chmod 0755 /var/pgsql # semanage fcontext -a -t httpd_var_run_t "/var/pgsql(/.*)?" # restorecon -R /var/pgsql
-
Uncomment and modify unix_socket_directories parameter in /var/lib/pgsql/9.3/data/postgresql.conf (/tmp is still needed not to break psql and other programs):
unix_socket_directories = '/tmp,/var/pgsql'
And here was another tricky part... In the original post I wrote that I've tried to change the location of Unix domain socket file, and I really did. What I missed was the changed error message. I thought that the error was the same, but it wasn't:
Error (256): Cannot connect to database: SQLSTATE[08006] [7] could not connect to
server: Permission denied
Is the server running locally and accepting
connections on Unix domain socket "/var/pgsql/.s.PGSQL.5432"?
Permission denied - this is something one can fight.
Everything works with
# setenforce 0
The problem is:
# audit2allow -a
#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
And it can be fixed:
# audit2allow -a -M httpd_postgresql_unix_socket_connect
# semodule -i httpd_postgresql_unix_socket_connect.pp
Content of httpd_postgresql_unix_socket_connect.te:
module httpd_postgresql_unix_socket_connect 1.0;
require {
type httpd_t;
type initrc_t;
class unix_stream_socket connectto;
}
#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
Turn SELinux back on:
# setenforce 1
And everything works!
P.S. I'd be glad to know if there is a way to avoid custom SELinux module by changing some file contexts or booleans. It might be the case, because SELinux allows nginx to use php-fpm Unix domain socket (/var/run/php5-fpm.sock), but for some reason blocks usage of PostgreSQL Unix domain socket (/var/pgsql/.s.PGSQL.5432).