diff --git a/.deploy.gitlab-ci.yml b/.deploy.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7825d67ce9a73e1e4b7368e0f6900bd362280267
--- /dev/null
+++ b/.deploy.gitlab-ci.yml
@@ -0,0 +1,48 @@
+variables:
+  STATION: "LOFAR station to deploy on"
+
+stages:
+  - deploy
+
+deploy_nomad:
+  stage: deploy
+  image:
+    name: hashicorp/levant
+    entrypoint: [ "" ]
+  parallel:
+    matrix:
+      - COMPONENT:
+          - stingray
+          - stingray-bucket-replication
+  environment:
+    name: $STATION
+  script:
+    - |
+      if [ "${STATION}" == "dts-lab" ]; then
+          # dts-lab test station
+          HOSTNAME="dts-lab.lofar.net"
+          EXTRA_VARFILES="-var-file=infra/env/cs.yaml"
+      elif [ "${STATION::2}" == "rs" ]; then
+          # remote station
+          HOSTNAME="${STATION}c.control.lofar"
+          EXTRA_VARFILES="-var-file=infra/env/rs.yaml"
+      else
+          # core station
+          HOSTNAME="${STATION}c.control.lofar"
+          EXTRA_VARFILES="-var-file=infra/env/cs.yaml"
+      fi
+
+      # To deploy manually, get the env.yaml and the .levant.nomad file,
+      # and run docker run --rm -i --net=host -v /path/to/env.yaml:/env.yaml:ro hashicorp/levant deploy --var-file=/env.yaml /dev/stdin < /path/to/file.levant.nomad
+      levant deploy \
+        -address="http://${HOSTNAME}:4646" \
+        -var-file=infra/env/common.yaml ${EXTRA_VARFILES} \
+        -var image_tag="${CI_COMMIT_REF_SLUG}" \
+        -var station="${STATION}" \
+        -ignore-no-changes \
+        infra/jobs/station/${COMPONENT}.levant.nomad
+
+workflow:
+  name: 'deploy on $STATION'
+  rules:
+    - when: always
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index adfd7f5cea0a7913b2bb068bf2a4db0e697deed8..5856d56ada71951cdc02835bc14bf1477305619d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -113,7 +113,7 @@ package_docs:
   script:
     - tox -e docs
 
-docker_build:
+docker_build_image:
   stage: images
   image: docker:latest
   needs:
@@ -163,30 +163,24 @@ publish_to_readthedocs:
 
 deploy_nomad_station:
   stage: deploy
-  image:
-    name: hashicorp/levant
-    entrypoint: [ "" ]
-  when: manual
   rules:
-    - if: $CI_COMMIT_TAG
+    - if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH) || $CI_COMMIT_TAG
+  when: manual
+  needs:
+    - docker_build_image
+  variables:
+    PARENT_PIPELINE_ID: $CI_PIPELINE_ID
+  trigger:
+    include: .deploy.gitlab-ci.yml
+    forward:
+      pipeline_variables: true
   parallel:
     matrix:
       - STATION:
           - cs001
           - cs032
-        COMPONENT:
-          - stingray
-          - stingray-bucket-replication
-  environment:
-    name: $STATION
-  script:
-    - |
-      levant deploy \
-        -address="http://${STATION}c.control.lofar:4646" \
-        -var-file=infra/env.yaml \
-        -var station="${STATION}" \
-        -var image_tag="$CI_COMMIT_REF_SLUG" \
-        infra/jobs/station/${COMPONENT}.levant.nomad
+          - rs307
+          - dts-lab
 
 deploy_nomad_central:
   stage: deploy
@@ -194,6 +188,8 @@ deploy_nomad_central:
     name: hashicorp/levant
     entrypoint: [ "" ]
   when: manual
+  needs:
+    - docker_build_image
   rules:
     - if: $CI_COMMIT_TAG
   parallel:
@@ -205,7 +201,7 @@ deploy_nomad_central:
   script:
     - |
       levant deploy \
-        -address="http://codlet01.control.lofar:4646" \
+        -address="http://nomad.central.lofar.net:4646" \
         -var-file=infra/env.yaml \
         -var image_tag="$CI_COMMIT_REF_SLUG" \
         infra/jobs/central/${COMPONENT}.levant.nomad
diff --git a/infra/env/README.md b/infra/env/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..741ec635e16356a6bb1e5fe9a043111b1d285373
--- /dev/null
+++ b/infra/env/README.md
@@ -0,0 +1,9 @@
+This directory contains the station-specific deployment settings, and selected versions of external images. The YAML files
+are used by levant for rendering the nomad templates.
+
+ For production, they are loaded in `.gitlab-ci.yml` as
+part of deployment.
+
+NB:
+
+* For each section, only the one in the last applied file will be used. The sections will not be merged. So be careful when specifying a section in multiple files.
diff --git a/infra/env/common.yaml b/infra/env/common.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..674bf29c910a1528954ee3da6eba4c75b929cb2d
--- /dev/null
+++ b/infra/env/common.yaml
@@ -0,0 +1,6 @@
+object_storage:
+  mc:
+    version: RELEASE.2024-08-26T10-49-58Z
+  user:
+    name: minioadmin
+    pass: minioadmin
diff --git a/infra/env.yaml b/infra/env/cs.yaml
similarity index 58%
rename from infra/env.yaml
rename to infra/env/cs.yaml
index f2476cec16c26ceaa8a5a02061aafef2274481de..6597eeacca3c3f7382543bbf1ef207707f6e2a72 100644
--- a/infra/env.yaml
+++ b/infra/env/cs.yaml
@@ -11,10 +11,3 @@ stingray:
     sst: 5121
     xst: 5122
     bst: 5123
-
-object_storage:
-  mc:
-    version: RELEASE.2024-03-09T06-43-06Z
-  user:
-    name: minioadmin
-    pass: minioadmin
diff --git a/infra/env/rs.yaml b/infra/env/rs.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..335b01221c0351600ff8e77c2c42c15578e0e984
--- /dev/null
+++ b/infra/env/rs.yaml
@@ -0,0 +1,9 @@
+stingray:
+  lba:
+    sst: 5101
+    xst: 5102
+    bst: 5103
+  hba:
+    sst: 5111
+    xst: 5112
+    bst: 5113
diff --git a/lofar_stingray/aggregator/_sst_aggregator.py b/lofar_stingray/aggregator/_sst_aggregator.py
index bc719bbfcc9e7dbc488655abbe7c82e2e81c6b1f..5b270d1581dde93ad9890bf195f8cbd46517bf4a 100644
--- a/lofar_stingray/aggregator/_sst_aggregator.py
+++ b/lofar_stingray/aggregator/_sst_aggregator.py
@@ -31,7 +31,7 @@ class SstAggregator(BaseAggregator):
         packets: Iterable,
         nr_signal_inputs: int = MAX_INPUTS,
         first_signal_input_index: int = 0,
-    ):  # pylint: disable=too-many-arguments
+    ):  # pylint: disable=too-many-arguments,too-many-positional-arguments
         super().__init__(station, antennafield, metadata_packets)
         self.package_loader = packets
         self.nr_signal_inputs = nr_signal_inputs
diff --git a/lofar_stingray/aggregator/_xst_aggregator.py b/lofar_stingray/aggregator/_xst_aggregator.py
index a9d58d58c03322558176c5acd9388c572cab27cb..6a0a771db4150b6437ac78316db813aac541e9cd 100644
--- a/lofar_stingray/aggregator/_xst_aggregator.py
+++ b/lofar_stingray/aggregator/_xst_aggregator.py
@@ -49,7 +49,7 @@ class XstAggregator(BaseAggregator):
         packets: Iterable,
         nr_signal_inputs=MAX_INPUTS,
         first_signal_input_index=0,
-    ):  # pylint: disable=too-many-arguments
+    ):  # pylint: disable=too-many-arguments,too-many-positional-arguments
         super().__init__(station, antennafield, metadata_packets)
         self.packets = packets
         self.nr_signal_inputs = nr_signal_inputs