diff --git a/.github/workflows/test-stack-reusable-workflow.yml b/.github/workflows/test-stack-reusable-workflow.yml index af3d0fe2..e3712e01 100644 --- a/.github/workflows/test-stack-reusable-workflow.yml +++ b/.github/workflows/test-stack-reusable-workflow.yml @@ -179,6 +179,17 @@ jobs: docker kill test-changedetectionio + - name: Test HTTPS SSL mode + run: | + openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost" + docker run --name test-changedetectionio-ssl --rm -e SSL_CERT_FILE=cert.pem -e SSL_PRIVKEY_FILE=privkey.pem -p 5000:5000 -v ./cert.pem:/app/cert.pem -v ./privkey.pem:/app/privkey.pem -d test-changedetectionio + sleep 3 + # Should return 0 (no error) when grep finds it + # -k because its self-signed + curl --retry-connrefused --retry 6 -k https://localhost:5000 -v|grep -q checkbox-uuid + + docker kill test-changedetectionio-ssl + - name: Test changedetection.io SIGTERM and SIGINT signal shutdown run: | diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index c8fc71bc..5015dc86 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -123,6 +123,20 @@ def main(): if opt == '-l': logger_level = int(arg) if arg.isdigit() else arg.upper() + + logger.success(f"changedetection.io version {get_version()} starting.") + # Launch using SocketIO run method for proper integration (if enabled) + ssl_cert_file = os.getenv("SSL_CERT_FILE", 'cert.pem') + ssl_privkey_file = os.getenv("SSL_PRIVKEY_FILE", 'privkey.pem') + if os.getenv("SSL_CERT_FILE") and os.getenv("SSL_PRIVKEY_FILE"): + ssl_mode = True + + # SSL mode could have been set by -s too, therefor fallback to default values + if ssl_mode: + if not os.path.isfile(ssl_cert_file) or not os.path.isfile(ssl_privkey_file): + logger.critical(f"Cannot start SSL/HTTPS mode, Please be sure that {ssl_cert_file}' and '{ssl_privkey_file}' exist in in {os.getcwd()}") + os._exit(2) + # Without this, a logger will be duplicated logger.remove() try: @@ -222,19 +236,19 @@ def main(): # SocketIO instance is already initialized in flask_app.py - - # Launch using SocketIO run method for proper integration (if enabled) if socketio_server: if ssl_mode: - socketio.run(app, host=host, port=int(port), debug=False, - certfile='cert.pem', keyfile='privkey.pem', allow_unsafe_werkzeug=True) + logger.success(f"SSL mode enabled, attempting to start with '{ssl_cert_file}' and '{ssl_privkey_file}' in {os.getcwd()}") + socketio.run(app, host=host, port=int(port), debug=False, + ssl_context=(ssl_cert_file, ssl_privkey_file), allow_unsafe_werkzeug=True) else: socketio.run(app, host=host, port=int(port), debug=False, allow_unsafe_werkzeug=True) else: # Run Flask app without Socket.IO if disabled logger.info("Starting Flask app without Socket.IO server") if ssl_mode: - app.run(host=host, port=int(port), debug=False, - ssl_context=('cert.pem', 'privkey.pem')) + logger.success(f"SSL mode enabled, attempting to start with '{ssl_cert_file}' and '{ssl_privkey_file}' in {os.getcwd()}") + app.run(host=host, port=int(port), debug=False, + ssl_context=(ssl_cert_file, ssl_privkey_file)) else: app.run(host=host, port=int(port), debug=False) diff --git a/docker-compose.yml b/docker-compose.yml index b796f263..e8b1f626 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,6 +69,11 @@ services: # Maximum height of screenshots, default is 16000 px, screenshots will be clipped to this if exceeded. # RAM usage will be higher if you increase this. # - SCREENSHOT_MAX_HEIGHT=16000 + # + # HTTPS SSL Mode for webserver, unset both of these, you may need to volume mount these files also. + # ./cert.pem:/app/cert.pem and ./privkey.pem:/app/privkey.pem + # - SSL_CERT_FILE=cert.pem + # - SSL_PRIVKEY_FILE=privkey.pem # Comment out ports: when using behind a reverse proxy , enable networks: etc. ports: