diff --git a/docs/en_US/release_notes.rst b/docs/en_US/release_notes.rst index 07c806f85..4306e7605 100644 --- a/docs/en_US/release_notes.rst +++ b/docs/en_US/release_notes.rst @@ -9,6 +9,7 @@ for it. .. toctree:: + release_notes_4_4 release_notes_4_3 release_notes_4_2 release_notes_4_1 diff --git a/docs/en_US/release_notes_4_4.rst b/docs/en_US/release_notes_4_4.rst new file mode 100644 index 000000000..314b88fdf --- /dev/null +++ b/docs/en_US/release_notes_4_4.rst @@ -0,0 +1,16 @@ +*********** +Version 4.4 +*********** + +Release date: 2019-04-04 + +This release contains a number of new features and fixes reported since the release of pgAdmin4 4.3 + +Features +******** + +| `Feature #2001 `_ - Add support for reverse proxied setups with Gunicorn, and document Gunicorn, uWSGI & NGINX configurations. + +Bug fixes +********* + diff --git a/docs/en_US/server_deployment.rst b/docs/en_US/server_deployment.rst index 8fa01bf0b..4b9787f4e 100644 --- a/docs/en_US/server_deployment.rst +++ b/docs/en_US/server_deployment.rst @@ -9,7 +9,9 @@ server mode and then deploying it either behind a webserver running as a reverse proxy, or using the WSGI interface. The following instructions demonstrate how pgAdmin may be run as a WSGI -application under ``Apache HTTP``, using ``mod_wsgi``. +application under ``Apache HTTP``, using ``mod_wsgi``, standalone using ``uWSGI`` +or ``Gunicorn``, or under ``NGINX`` using using ``uWSGI`` or ``Gunicorn``. + .. seealso:: For detailed instructions on building and configuring pgAdmin from scratch, please see the README file in the top level directory of the source code. @@ -174,3 +176,125 @@ with: Require all granted Adjust as needed to suit your access control requirements. + +Standalone Gunicorn Configuration +--------------------------------- + +pgAdmin may be hosted by Gunicorn directly simply by running a command such as +the one shown below. Note that this example assumes pgAdmin was installed using +the Python Wheel (you may need to adjust the path to suit your installation): + +.. code-block:: bash + + gunicorn --bind 0.0.0.0:80 \ + --workers=1 \ + --threads=25 \ + --chdir /usr/lib/python3.7/dist-packages/pgadmin4 \ + pgAdmin4:app + +Standalone uWSGI Configuration +------------------------------ + +pgAdmin may be hosted by uWSGI directly simply by running a command such as +the one shown below. Note that this example assumes pgAdmin was installed using +the Python Wheel (you may need to adjust the path to suit your installation): + +.. code-block:: bash + + uwsgi --http-socket 0.0.0.0:80 \ + --processes 1 \ + --threads 25 \ + --chdir /usr/lib/python3.7/dist-packages/pgadmin4/ \ + --mount /=pgAdmin4:app + +NGINX Configuration with Gunicorn +--------------------------------- + +pgAdmin can be hosted by Gunicorn, with NGINX in front of it. Note that these +examples assume pgAdmin was installed using the Python Wheel (you may need to +adjust the path to suit your installation). + +To run with pgAdmin in the root directory of the server, start Gunicorn using a +command similar to: + +.. code-block:: bash + + gunicorn --bind unix:/tmp/pgadmin4.sock \ + --workers=1 \ + --threads=25 \ + --chdir /usr/lib/python3.7/dist-packages/pgadmin4 \ + pgAdmin4:app + +And configure NGINX: + +.. code-block:: nginx + + location / { + include proxy_params; + proxy_pass http://unix:/tmp/pgadmin4.sock; + } + +Alternatively, pgAdmin can be hosted in a sub-directory (/pgadmin4 in this case) +on the server. Start Gunicorn as when using the root directory, but configure +NGINX as follows: + +.. code-block:: nginx + + location /pgadmin4/ { + include proxy_params; + proxy_pass http://unix:/tmp/pgadmin4.sock; + proxy_set_header X-Script-Name /pgadmin4; + } + +NGINX Configuration with uWSGI +------------------------------ + +pgAdmin can be hosted by uWSGI, with NGINX in front of it. Note that these +examples assume pgAdmin was installed using the Python Wheel (you may need to +adjust the path to suit your installation). + +To run with pgAdmin in the root directory of the server, start Gunicorn using a +command similar to: + +.. code-block:: bash + + uwsgi --socket /tmp/pgadmin4.sock \ + --processes 1 \ + --threads 25 \ + --chdir /usr/lib/python3.7/dist-packages/pgadmin4/ \ + --manage-script-name \ + --mount /=pgAdmin4:app + +And configure NGINX: + +.. code-block:: nginx + + location / { try_files $uri @pgadmin4; } + location @pgadmin4 { + include uwsgi_params; + uwsgi_pass unix:/tmp/pgadmin4.sock; + } + +Alternatively, pgAdmin can be hosted in a sub-directory (/pgadmin4 in this case) +on the server. Start uWSGI, noting that the directory name is specified in the +``mount`` parameter: + +.. code-block:: bash + + uwsgi --socket /tmp/pgadmin4.sock \ + --processes 1 \ + --threads 25 \ + --chdir /usr/lib/python3.7/dist-packages/pgadmin4/ \ + --manage-script-name \ + --mount /pgadmin4=pgAdmin4:app + +Then, configure NGINX: + +.. code-block:: nginx + + location = /pgadmin4 { rewrite ^ /pgadmin4/; } + location /pgadmin4 { try_files $uri @pgadmin4; } + location @pgadmin4 { + include uwsgi_params; + uwsgi_pass unix:/tmp/pgadmin4.sock; + } diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py index 75a4f3b6d..dd5d67fb1 100644 --- a/web/pgAdmin4.py +++ b/web/pgAdmin4.py @@ -57,6 +57,27 @@ if not os.path.isfile(config.SQLITE_PATH): ) exec(open(file_quote(setupfile), 'r').read()) + +########################################################################## +# Support reverse proxying +########################################################################## +class ReverseProxied(object): + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + script_name = environ.get("HTTP_X_SCRIPT_NAME", "") + if script_name: + environ["SCRIPT_NAME"] = script_name + path_info = environ["PATH_INFO"] + if path_info.startswith(script_name): + environ["PATH_INFO"] = path_info[len(script_name):] + scheme = environ.get("HTTP_X_SCHEME", "") + if scheme: + environ["wsgi.url_scheme"] = scheme + return self.app(environ, start_response) + + ########################################################################## # Server startup ########################################################################## @@ -68,6 +89,7 @@ if config.DEBUG: # Create the app! app = create_app() +app.wsgi_app = ReverseProxied(app.wsgi_app) if config.DEBUG: app.debug = True