Я пытаюсь подключиться к сокету домена PostgreSQL Unix из веб-приложения PHP. Соответствующие компоненты системы:
PostgreSQL прослушивает стандартный порт 5432, и у меня нет проблем с его использованием через TCP / IP на 127.0.0.1:5432, но когда я пытаюсь подключиться к его сокету домена Unix, у меня появляется следующая ошибка:
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"?
файл /tmp/.s.PGSQL.5432 существует, и я могу подключиться, используя psql:
$ psql -Uusername db_name
psql (9.3.5)
Type "help" for help.
db_name=>
Так что со стороны PostgreSQL проблем возникнуть не должно. Или есть?
Соответствующая строка из /var/lib/pgsql/9.3/data/pg_hba.conf:
local all username trust
Изменение местоположения файла сокета домена Unix в /var/lib/pgsql/9.3/data/postgresql.conf не помогло:
unix_socket_directories = '/var/run/pgsql'
Не было ничего в /var/log/audit/audit.log, но я попытался отключить SELinux, на всякий случай:
# setenforce 0
Это не помогло, значит, это не SELinux.
Соответствующие строки из Strace из 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
Имя файла правильное и снова файл /tmp/.s.PGSQL.5432 существуют:
$ ls -l /tmp/.s.PGSQL.5432
srwxrwxrwx. 1 postgres postgres 0 Nov 1 09:47 /tmp/.s.PGSQL.5432
Похоже, процесс php-fpm не привязан к корневому каталогу:
# ls -l /proc/882/root
lrwxrwxrwx. 1 apache apache 0 Oct 31 19:54 /proc/882/root -> /
На данный момент у меня больше нет идей, где может быть проблема, и я был бы признателен за любую помощь.
Я решил проблему. Первоначальная причина была в служебном файле systemd для php-fpm. /usr/lib/systemd/system/php-fpm.service:
[Service]
PrivateTmp=true
Это означает, что php-fpm не мог видеть /tmp/.s.PGSQL.5432 ни что-либо еще расположенное в / tmp. Чтобы решить эту проблему, я изменил расположение файла сокета домена PostgreSQL Unix, выполнив следующие действия:
Создать новый каталог / var / pgsql (обратите внимание на изменение контекста файла SELinux):
# 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
Раскомментировать и изменить unix_socket_directories параметр в /var/lib/pgsql/9.3/data/postgresql.conf (/ tmp все еще нужно, чтобы не ломать psql и другие программы):
unix_socket_directories = '/tmp,/var/pgsql'
И вот еще одна хитрость ... В исходном посте я написал, что пытался изменить расположение файла сокета домена Unix, и я действительно это сделал. Я пропустил измененное сообщение об ошибке. Я думал, что ошибка такая же, но это не так:
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"?
Доступ запрещен - с этим можно бороться.
Все работает с
# setenforce 0
Проблема в:
# audit2allow -a
#============= httpd_t ==============
allow httpd_t initrc_t:unix_stream_socket connectto;
И это можно исправить:
# audit2allow -a -M httpd_postgresql_unix_socket_connect
# semodule -i httpd_postgresql_unix_socket_connect.pp
Содержание 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;
Снова включите SELinux:
# setenforce 1
И все работает!
P.S. Я был бы рад узнать, есть ли способ избежать использования настраиваемого модуля SELinux, изменив некоторые файловые контексты или логические значения. Это может быть так, потому что SELinux позволяет nginx использовать сокет домена Unix php-fpm (/var/run/php5-fpm.sock), но почему-то блокирует использование сокета домена PostgreSQL Unix (/var/pgsql/.s.PGSQL.5432).