我遇到了一个奇怪的问题,我试图运行一个 Flask 应用程序(https://github.com/pyfarm/pyfarm-master) 在 CentOS 7 下的 Apache 下 mod_wsgi 无法连接到本地 postgresql 服务器 - 但前提是该 apache 已使用 systemctl 从 systemd 启动。如果我/usr/sbin/httpd -DFOREGROUND
在命令行上手动使用 apache(systemd 说它使用的相同命令),则一切正常。
Apache、Postgresql 和 mod_wsgi 几乎未作任何改动,都是来自 CentOS 存储库或 EPEL 的默认安装。Pyfarm-core 和 pyfarm-master 已在 pip 的帮助下安装。
除了将基于主机的身份验证设置为“信任”所有本地主机之外,postgresql 配置与默认配置没有变化:
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
之后,我创建了一个用户和数据库
CREATE USER pyfarm WITH PASSWORD 'pyfarmpw';
CREATE DATABASE pyfarm WITH OWNER pyfarm;
之后我可以使用 psql 以用户 pyfarm 身份登录数据库 pyfarm。
Apache 也几乎与默认配置没有太大变化。我唯一更改的是添加了一个新文件,/etc/httpd/conf.d/pyfarm.conf
内容如下:
<VirtualHost *>
ServerName pyfarm.produktion.local
ServerAlias pyfarm
SetEnv PYFARM_APP_INSTANCE True
SetEnv PYFARM_SECRET_KEY 2qgsd4hHaalvAn7
SetEnv PYFARM_CONFIG Prod
SetEnv PYFARM_DB_PREFIX ""
SetEnv PYFARM_DATABASE_URI postgresql+psycopg2://pyfarm:[email protected]/pyfarm
SetEnv TDB_DRIVER psycopg2
WSGIScriptAlias / /var/www/pyfarm/pyfarm.wsgi
DocumentRoot /var/www/pyfarm
<Directory /var/www/pyfarm>
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
(这些配置文件里的密码和密钥并不是很重要,无论如何都会被改变……)
该文件引用/var/www/pyfarm/pyfarm.wsgi,如下所示:
import os
def application(environ, start_response):
for key in environ:
if key.startswith("PYFARM_") or key.startswith("TDB_"):
os.environ[key] = environ[key]
from pyfarm.master.entrypoints import app as application_
return application_(environ, start_response)
(它需要非常复杂,因为否则应用程序将看不到 apache 中设置的环境变量。)
完成这些步骤后,从应用程序访问任何实际上不需要数据库的页面都可以正常工作,但是,一旦我尝试访问需要数据库的页面,就会收到 500 返回代码,并且在 Apache 的 error_log 中出现以下错误:
[Thu Jul 03 18:01:20.099007 2014] [:info] [pid 18094] mod_wsgi (pid=18094): Initializing Python.
[Thu Jul 03 18:01:20.106601 2014] [:info] [pid 18094] mod_wsgi (pid=18094): Attach interpreter ''.
[Thu Jul 03 18:01:20.116951 2014] [:error] [pid 18080] \x1b[31m2014-07-03 18:01:20 ERROR - pyfarm.master - Exception on /api/v1/agents/ [GET]
[Thu Jul 03 18:01:20.116964 2014] [:error] [pid 18080] Traceback (most recent call last):
[Thu Jul 03 18:01:20.116968 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
[Thu Jul 03 18:01:20.116971 2014] [:error] [pid 18080] response = self.full_dispatch_request()
[Thu Jul 03 18:01:20.116974 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
[Thu Jul 03 18:01:20.116977 2014] [:error] [pid 18080] rv = self.handle_user_exception(e)
[Thu Jul 03 18:01:20.116989 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
[Thu Jul 03 18:01:20.116993 2014] [:error] [pid 18080] reraise(exc_type, exc_value, tb)
[Thu Jul 03 18:01:20.116996 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
[Thu Jul 03 18:01:20.116999 2014] [:error] [pid 18080] rv = self.dispatch_request()
[Thu Jul 03 18:01:20.117001 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
[Thu Jul 03 18:01:20.117005 2014] [:error] [pid 18080] return self.view_functions[rule.endpoint](**req.view_args)
[Thu Jul 03 18:01:20.117007 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/views.py", line 84, in view
[Thu Jul 03 18:01:20.117010 2014] [:error] [pid 18080] return self.dispatch_request(*args, **kwargs)
[Thu Jul 03 18:01:20.117013 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/flask/views.py", line 149, in dispatch_request
[Thu Jul 03 18:01:20.117016 2014] [:error] [pid 18080] return meth(*args, **kwargs)
[Thu Jul 03 18:01:20.117019 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/pyfarm/master/api/agents.py", line 412, in get
[Thu Jul 03 18:01:20.117021 2014] [:error] [pid 18080] for host in query:
[Thu Jul 03 18:01:20.117024 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2405, in __iter__
[Thu Jul 03 18:01:20.117027 2014] [:error] [pid 18080] return self._execute_and_instances(context)
[Thu Jul 03 18:01:20.117030 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2418, in _execute_and_instances
[Thu Jul 03 18:01:20.117033 2014] [:error] [pid 18080] close_with_result=True)
[Thu Jul 03 18:01:20.117037 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2409, in _connection_from_session
[Thu Jul 03 18:01:20.117040 2014] [:error] [pid 18080] **kw)
[Thu Jul 03 18:01:20.117043 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 846, in connection
[Thu Jul 03 18:01:20.117046 2014] [:error] [pid 18080] close_with_result=close_with_result)
[Thu Jul 03 18:01:20.117048 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 850, in _connection_for_bind
[Thu Jul 03 18:01:20.117051 2014] [:error] [pid 18080] return self.transaction._connection_for_bind(engine)
[Thu Jul 03 18:01:20.117054 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 315, in _connection_for_bind
[Thu Jul 03 18:01:20.117057 2014] [:error] [pid 18080] conn = bind.contextual_connect()
[Thu Jul 03 18:01:20.117060 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1737, in contextual_connect
[Thu Jul 03 18:01:20.117063 2014] [:error] [pid 18080] self.pool.connect(),
[Thu Jul 03 18:01:20.117065 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 332, in connect
[Thu Jul 03 18:01:20.117068 2014] [:error] [pid 18080] return _ConnectionFairy._checkout(self)
[Thu Jul 03 18:01:20.117071 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 630, in _checkout
[Thu Jul 03 18:01:20.117074 2014] [:error] [pid 18080] fairy = _ConnectionRecord.checkout(pool)
[Thu Jul 03 18:01:20.117076 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 433, in checkout
[Thu Jul 03 18:01:20.117079 2014] [:error] [pid 18080] rec = pool._do_get()
[Thu Jul 03 18:01:20.117082 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 949, in _do_get
[Thu Jul 03 18:01:20.117085 2014] [:error] [pid 18080] return self._create_connection()
[Thu Jul 03 18:01:20.117091 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 278, in _create_connection
[Thu Jul 03 18:01:20.117094 2014] [:error] [pid 18080] return _ConnectionRecord(self)
[Thu Jul 03 18:01:20.117097 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 404, in __init__
[Thu Jul 03 18:01:20.117099 2014] [:error] [pid 18080] self.connection = self.__connect()
[Thu Jul 03 18:01:20.117102 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 530, in __connect
[Thu Jul 03 18:01:20.117105 2014] [:error] [pid 18080] connection = self.__pool._creator()
[Thu Jul 03 18:01:20.117108 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 95, in connect
[Thu Jul 03 18:01:20.117111 2014] [:error] [pid 18080] connection_invalidated=invalidated
[Thu Jul 03 18:01:20.117113 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 189, in raise_from_cause
[Thu Jul 03 18:01:20.117116 2014] [:error] [pid 18080] reraise(type(exception), exception, tb=exc_tb)
[Thu Jul 03 18:01:20.117119 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 89, in connect
[Thu Jul 03 18:01:20.117122 2014] [:error] [pid 18080] return dialect.connect(*cargs, **cparams)
[Thu Jul 03 18:01:20.117125 2014] [:error] [pid 18080] File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 376, in connect
[Thu Jul 03 18:01:20.117127 2014] [:error] [pid 18080] return self.dbapi.connect(*cargs, **cparams)
[Thu Jul 03 18:01:20.117130 2014] [:error] [pid 18080] File "/usr/lib64/python2.7/site-packages/psycopg2/__init__.py", line 164, in connect
[Thu Jul 03 18:01:20.117133 2014] [:error] [pid 18080] conn = _connect(dsn, connection_factory=connection_factory, async=async)
[Thu Jul 03 18:01:20.117136 2014] [:error] [pid 18080] OperationalError: (OperationalError) could not connect to server: Permission denied
[Thu Jul 03 18:01:20.117138 2014] [:error] [pid 18080] \tIs the server running on host "127.0.0.1" and accepting
[Thu Jul 03 18:01:20.117141 2014] [:error] [pid 18080] \tTCP/IP connections on port 5432?
[Thu Jul 03 18:01:20.117144 2014] [:error] [pid 18080] None None\x1b[39m
但是,当我使用 停止 apachesystemctl stop httpd.service
并使用 重新启动它时/usr/sbin/httpd -DFOREGROUND
,一切都正常运行,包括需要数据库访问的页面。
当 Apache 像这样运行时,我可以看到应用程序在中创建并使用数据库连接tcpdump -i lo
。当从 systemd 启动 Apache 时,在 tcpdump 中看不到这样的连接,甚至没有 SYN 数据包。
显然,每次都手动启动 Apache 并不是一个长期的解决方案。有人知道这里出了什么问题吗?也许是某种特定于 systemd 的功能限制阻止某些服务建立出站 TCP 连接?
答案1
启用 SELinux 后,Web 服务器(以及在其中运行的进程,例如 mod_wsgi,以及在 EL 7 上,类似的服务器进程甚至与 Web 服务器分开运行)不允许建立传出网络连接,除非您明确允许它们这样做,例如使用 SELinux 布尔值。
为了解决该问题,请设置布尔值以允许与数据库的网络连接:
setsebool -P httpd_can_network_connect_db 1