From e6fadc44fa09b9c88a5d718c95312f02f1de9369 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 14 Jul 2021 14:02:24 +1000 Subject: [PATCH] #76 app path prefix when behind proxy_pass (#91) Support for running in a sub-path under proxy_pass (Running changedetection.io behind a reverse proxy sub directory) More here https://github.com/dgtlmoon/changedetection.io/wiki/Running-changedetection.io-behind-a-reverse-proxy-sub-directory --- backend/__init__.py | 7 ++++--- backend/templates/base.html | 14 +++++++------- backend/templates/edit.html | 5 ++--- backend/templates/scrub.html | 2 +- backend/templates/settings.html | 8 +++----- backend/templates/watch-overview.html | 21 +++++++++++---------- backend/tests/test_access_control.py | 4 ++-- changedetection.py | 12 ++++++++++++ docker-compose.yml | 6 ++++++ 9 files changed, 48 insertions(+), 31 deletions(-) diff --git a/backend/__init__.py b/backend/__init__.py index 3c9b650e..b1653007 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -468,11 +468,12 @@ def changedetection_app(config=None, datastore_o=None): form.notification_body.data = datastore.data['settings']['application']['notification_body'] # Password unset is a GET - if request.values.get('removepassword') == 'true': + if request.values.get('removepassword') == 'yes': from pathlib import Path datastore.data['settings']['application']['password'] = False flash("Password protection removed.", 'notice') flask_login.logout_user() + return redirect(url_for('settings_page')) if request.method == 'POST' and form.validate(): @@ -577,7 +578,7 @@ def changedetection_app(config=None, datastore_o=None): if uuid == 'first': uuid = list(datastore.data['watching'].keys()).pop() - extra_stylesheets = ['/static/styles/diff.css'] + extra_stylesheets = [url_for('static_content', group='styles', filename='diff.css')] try: watch = datastore.data['watching'][uuid] except KeyError: @@ -634,7 +635,7 @@ def changedetection_app(config=None, datastore_o=None): if uuid == 'first': uuid = list(datastore.data['watching'].keys()).pop() - extra_stylesheets = ['/static/styles/diff.css'] + extra_stylesheets = [url_for('static_content', group='styles', filename='diff.css')] try: watch = datastore.data['watching'][uuid] diff --git a/backend/templates/base.html b/backend/templates/base.html index cc53ac69..649b204e 100644 --- a/backend/templates/base.html +++ b/backend/templates/base.html @@ -5,8 +5,8 @@ Change Detection{{extra_title}} - - + + {% if extra_stylesheets %} {% for m in extra_stylesheets %} @@ -21,7 +21,7 @@ {% if has_password and not current_user.is_authenticated %} ChangeDetection.io {% else %} - ChangeDetection.io + ChangeDetection.io {% endif %} {% if current_diff_url %} {{ current_diff_url }} @@ -35,13 +35,13 @@ {% if current_user.is_authenticated or not has_password %} {% if not current_diff_url %}
  • - BACKUP + BACKUP
  • - IMPORT + IMPORT
  • - SETTINGS + SETTINGS
  • {% else %}
  • @@ -55,7 +55,7 @@ {% endif %} {% if current_user.is_authenticated %} -
  • LOG OUT
  • +
  • LOG OUT
  • {% endif %}

  • - {% endblock %} diff --git a/backend/templates/scrub.html b/backend/templates/scrub.html index 4798bf57..557095f0 100644 --- a/backend/templates/scrub.html +++ b/backend/templates/scrub.html @@ -26,7 +26,7 @@
    diff --git a/backend/templates/settings.html b/backend/templates/settings.html index a17ba2c7..48733cf7 100644 --- a/backend/templates/settings.html +++ b/backend/templates/settings.html @@ -12,7 +12,7 @@
    {% if current_user.is_authenticated %} - Remove password + Remove password {% else %} {{ render_field(form.password, size=10) }} Password protection for your changedetection.io application. @@ -97,11 +97,9 @@ SMTPS - mailtos://user:pass@mail.domain.com?to=receivingAddress@example.com") }}

    - - diff --git a/backend/templates/watch-overview.html b/backend/templates/watch-overview.html index 11d3776a..883d96f2 100644 --- a/backend/templates/watch-overview.html +++ b/backend/templates/watch-overview.html @@ -15,10 +15,10 @@
    - All + All {% for tag in tags %} {% if tag != "" %} - {{ tag }} + {{ tag }} {% endif %} {% endfor %}
    @@ -45,7 +45,8 @@ {% if watch.paused is defined and watch.paused != False %}paused{% endif %} {% if watch.newest_history_key| int > watch.last_viewed| int %}unviewed{% endif %}"> {{ loop.index }} - Pause + Pause + {{watch.title if watch.title is not none and watch.title|length > 0 else watch.url}} {% if watch.last_error is defined and watch.last_error != False %} @@ -63,14 +64,14 @@ {% endif %} - Recheck - Edit + Edit {% if watch.history|length >= 2 %} - Diff + Diff {% else %} {% if watch.history|length == 1 %} - Preview + Preview {% endif %} {% endif %} @@ -81,15 +82,15 @@ diff --git a/backend/tests/test_access_control.py b/backend/tests/test_access_control.py index f8cb5be3..14e0880a 100644 --- a/backend/tests/test_access_control.py +++ b/backend/tests/test_access_control.py @@ -46,7 +46,7 @@ def test_check_access_control(app, client): assert b"LOG OUT" in res.data # Now remove the password so other tests function, @todo this should happen before each test automatically - res = c.get(url_for("settings_page", removepassword="true"), + res = c.get(url_for("settings_page", removepassword="yes"), follow_redirects=True) assert b"Password protection removed." in res.data @@ -93,7 +93,7 @@ def test_check_access_no_remote_access_to_remove_password(app, client): assert b"Password protection enabled." in res.data assert b"Login" in res.data - res = c.get(url_for("settings_page", removepassword="true"), + res = c.get(url_for("settings_page", removepassword="yes"), follow_redirects=True) assert b"Password protection removed." not in res.data diff --git a/changedetection.py b/changedetection.py index bd959dc3..c6461b62 100755 --- a/changedetection.py +++ b/changedetection.py @@ -65,6 +65,18 @@ def main(argv): has_password=datastore.data['settings']['application']['password'] != False ) + # Proxy sub-directory support + # Set environment var USE_X_SETTINGS=1 on this script + # And then in your proxy_pass settings + # + # proxy_set_header Host "localhost"; + # proxy_set_header X-Forwarded-Prefix /app; + + if os.getenv('USE_X_SETTINGS'): + print ("USE_X_SETTINGS is ENABLED\n") + from werkzeug.middleware.proxy_fix import ProxyFix + app.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1, x_host=1) + if ssl_mode: # @todo finalise SSL config, but this should get you in the right direction if you need it. eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen(('', port)), diff --git a/docker-compose.yml b/docker-compose.yml index bb806657..7000de35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,8 +17,14 @@ services: # Base URL of your changedetection.io install (Added to notification alert # - BASE_URL="https://mysite.com" + # Respect proxy_pass type settings, `proxy_set_header Host "localhost";` and `proxy_set_header X-Forwarded-Prefix /app;` + # More here https://github.com/dgtlmoon/changedetection.io/wiki/Running-changedetection.io-behind-a-reverse-proxy-sub-directory + # - USE_X_SETTINGS=1 + + # Comment out ports: when using behind a reverse proxy , enable networks: etc. ports: - 5000:5000 + restart: always volumes: