diff --git a/layerindex/tasks.py b/layerindex/tasks.py
index 4af9466..5bd40a8 100644
--- a/layerindex/tasks.py
+++ b/layerindex/tasks.py
@@ -16,13 +16,11 @@ import subprocess
 import shlex
 from datetime import datetime
 
-try:
-    from django.conf import settings
-except ImportError:
-    # not in a full django env, so settings is inaccessible.
-    # setup django to access settings.
-    utils.setup_django()
-    from django.conf import settings
+# The Celery worker imports this module outside Django; point it at the
+# settings, as utils.setup_django() does. (Importing django.conf always
+# succeeds; the settings are only loaded when first used.)
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
+from django.conf import settings
 
 tasks = Celery('layerindex',
     broker=settings.RABBIT_BROKER,
diff --git a/tests/test_celery_app.py b/tests/test_celery_app.py
new file mode 100644
index 0000000..bbd12a1
--- /dev/null
+++ b/tests/test_celery_app.py
@@ -0,0 +1,19 @@
+# layerindex-web - test that the Celery worker can load the task module
+#
+# Licensed under the MIT license, see COPYING.MIT for details
+#
+# SPDX-License-Identifier: MIT
+
+import os
+import subprocess
+import sys
+
+
+def test_tasks_module_loads_without_django_settings_module():
+    # As the worker does: celery --workdir=<source> --app layerindex.tasks
+    env = {k: v for k, v in os.environ.items() if k != 'DJANGO_SETTINGS_MODULE'}
+    srcdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    result = subprocess.run([sys.executable, '-c', 'import layerindex.tasks as t; print(t.tasks.conf.broker_url)'],
+                            cwd=srcdir, env=env, capture_output=True, text=True)
+    assert result.returncode == 0, result.stderr
+    assert result.stdout.startswith('amqp://')
