diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 283c21c9dbbd9b458d872ea503dd2ff768e99ba9..9a0ca79d954f3c0cd808148b50bcd7d4999f69d0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,15 +5,38 @@ workflow:
   rules:
     - if: $CI_COMMIT_BRANCH
 
+# We can't do variable substitution in a job and then also use that computed
+# variable in the Environment URL of the same job, so we have to do the
+# substitution in an earlier stage. All of this variable substitution is only
+# required for projects in sub-groups because GitLab doesn't have a predefined
+# variable that contains the project namespace relative to the root namespace.
+#
+# For example, if the project path is "/group/subgroup-1" then we need just the
+# "/subgroup-1" portion because that is used in the Environment URL path, while
+# the "/group" root namespace is used as the subdomain.
+setup:
+  stage: .pre
+  tags:
+    - docker
+  script:
+    - echo "ROOT_RELATIVE_NAMESPACE=${CI_PROJECT_NAMESPACE#$CI_PROJECT_ROOT_NAMESPACE}" >> build.env
+  artifacts:
+    reports:
+      dotenv: build.env
+
 # We can't deploy multiple different variants of GitLab Pages sites (e.g. one
-# per branch), so we use this quick instead. GitLab has a special browsable URL
-# for job artifacts on public projects, and we can create an Environment that
-# points to that URL so it's easy for devs to know what the current Environment
-# URL for their branch is.
+# per branch), so we use this workaround instead. GitLab has a special browsable
+# URL for job artifacts on public projects, and we can create an Environment
+# that points to that URL so it's easy for devs to know what the current
+# Environment URL for their branch is.
 .deploy:
   stage: deploy
   tags:
     - docker
+  before_script:
+    - echo $CI_ENVIRONMENT_URL
+    - echo $ROOT_RELATIVE_NAMESPACE
+    - test "$ROOT_RELATIVE_NAMESPACE" == "${CI_PROJECT_NAMESPACE#$CI_PROJECT_ROOT_NAMESPACE}" || { echo "ROOT_RELATIVE_NAMESPACE is not set correctly" ; exit 1 ; }
   script:
     - sed -i "s/%%BRANCH%%/$CI_COMMIT_BRANCH/g" src/index.html
     - mv src public
@@ -29,7 +52,7 @@ review:
     - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
   environment:
     name: "review $CI_COMMIT_BRANCH"
-    url: "https://$CI_PROJECT_NAMESPACE.$CI_PAGES_DOMAIN/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/public/index.html"
+    url: "https://${CI_PROJECT_ROOT_NAMESPACE}.${CI_PAGES_DOMAIN}/-${ROOT_RELATIVE_NAMESPACE}/${CI_PROJECT_NAME}/-/jobs/$CI_JOB_ID/artifacts/public/index.html"
 
 # Deploy to GitLab Pages for pushes on the default branch
 pages: