[pgAdmin][RM4768] Reverse proxy on non-standard port

Aditya Toshniwal <[email protected]>
Newsgroups gmane.comp.db.postgresql.pgadmin.devel
Message-ID <CAM9w-_nsTA0hT7imVnq89A=d-+bBQgNySEaiEowvv2oa8tKgNA@mail.gmail.com>
Hi Hackers,

Attached is the patch to allow pgAdmin to run behind reverse proxy on a non
standard port.
The middleware -
https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#werkzeug.middleware.proxy_fix.ProxyFix
allows us to set the number of trusted ports (and few other params) behind
the proxy. By default it is zero.
With this patch, user can set these params using pgAdmin config.
I have set the default value for port as 1, which will allow to run behind
non-standard port.

I have added the documentation under reverse proxy section.

Kindly review.

-- 
Thanks and Regards,
Aditya Toshniwal
Sr. Software Engineer | EnterpriseDB India | Pune
"Don't Complain about Heat, Plant a TREE"
RM4768.patch (application/octet-stream, 3.2 KB)
diff --git a/docs/en_US/container_deployment.rst b/docs/en_US/container_deployment.rst
index 2d672c12..941e966c 100644
--- a/docs/en_US/container_deployment.rst
+++ b/docs/en_US/container_deployment.rst
@@ -197,6 +197,27 @@ for example:
         -e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
         -d dpage/pgadmin4
 
+pgAdmin configuration
+---------------------
+
+You must tell the middleware how many proxies set each header so it knows what values to trust.
+Below is the pgAdmin config params with default and take values as "Number of values to trust for".
+pgAdmin is ready by default to run behind reverse proxy even on a non-standard port and
+these config options doesn't need to be changed. If required, you can tweak these config as per your need.
+
+.. code-block:: python
+
+    # Number of values to trust for X-Forwarded-For
+    PROXY_X_FOR_COUNT = 1
+    # Number of values to trust for X-Forwarded-Proto.
+    PROXY_X_PROTO_COUNT = 0
+    # Number of values to trust for X-Forwarded-Host.
+    PROXY_X_HOST_COUNT = 0
+    # Number of values to trust for X-Forwarded-Port.
+    PROXY_X_PORT_COUNT = 1
+    # Number of values to trust for X-Forwarded-Prefix.
+    PROXY_X_PREFIX_COUNT = 0
+
 HTTP via Nginx
 --------------
 
diff --git a/web/config.py b/web/config.py
index 76ea7ef8..16a5d6f4 100644
--- a/web/config.py
+++ b/web/config.py
@@ -155,6 +155,22 @@ X_FRAME_OPTIONS = "SAMEORIGIN"
 # Hashing algorithm used for password storage
 SECURITY_PASSWORD_HASH = 'pbkdf2_sha512'
 
+# Proxy related changes
+# You must tell the middleware how many proxies set each header so
+# it knows what values to trust
+# https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#werkzeug.middleware.proxy_fix.ProxyFix
+# Below params take values as "Number of values to trust for"
+# Number of values to trust for X-Forwarded-For
+PROXY_X_FOR_COUNT = 1
+# Number of values to trust for X-Forwarded-Proto.
+PROXY_X_PROTO_COUNT = 0
+# Number of values to trust for X-Forwarded-Host.
+PROXY_X_HOST_COUNT = 0
+# Number of values to trust for X-Forwarded-Port.
+PROXY_X_PORT_COUNT = 1
+# Number of values to trust for X-Forwarded-Prefix.
+PROXY_X_PREFIX_COUNT = 0
+
 # NOTE: CSRF_SESSION_KEY, SECRET_KEY and SECURITY_PASSWORD_SALT are no
 #       longer part of the main configuration, but are stored in the
 #       configuration databases 'keys' table and are auto-generated.
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index 2063603a..4bcfccc5 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -71,7 +71,13 @@ if not os.path.isfile(config.SQLITE_PATH):
 class ReverseProxied(object):
     def __init__(self, app):
         # https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#module-werkzeug.middleware.proxy_fix
-        self.app = ProxyFix(app)
+        self.app = ProxyFix(app,
+                            x_for=config.PROXY_X_FOR_COUNT,
+                            x_proto=config.PROXY_X_PROTO_COUNT,
+                            x_host=config.PROXY_X_HOST_COUNT,
+                            x_port=config.PROXY_X_PORT_COUNT,
+                            x_prefix=config.PROXY_X_PREFIX_COUNT
+                            )
 
     def __call__(self, environ, start_response):
         script_name = environ.get("HTTP_X_SCRIPT_NAME", "")
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.