diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d3f4f3e3f6c8134ff438357d2795b255cad56137
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,83 @@
+variables:
+  GITLAB_PASTEUR_PROJECT_ID: 6531
+
+stages:
+  - build
+  - deploy
+
+.build-with-dind:
+  # https://dsi-docs.pasteur.cloud/docs/gitlab/cicd/docker-build/
+  stage: build
+  image: docker:24
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
+  script:
+    - docker build -t "$FQ_IMAGE_NAME" -f "$CONTAINERFILE" "$BUILD_CONTEXT"
+    - docker push "$FQ_IMAGE_NAME"
+
+.build-with-buildah:
+  # see https://dsi-docs.pasteur.cloud/docs/gitlab/cicd/buildah/
+  stage: build
+  image: quay.io/buildah/stable:v1.37
+  variables:
+    STORAGE_DRIVER: vfs
+    BUILDAH_FORMAT: docker
+    BUILDAH_ISOLATION: chroot
+  before_script:
+    - export REGISTRY_AUTH_FILE="$HOME/auth.json"
+    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
+  script:
+    - buildah build -t "$FQ_IMAGE_NAME" -f "$CONTAINERFILE" "$BUILD_CONTEXT"
+    - buildah push "$FQ_IMAGE_NAME"
+
+build on gitlab.pasteur.fr:
+  extends: .build-with-buildah
+  rules:
+    - if: $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID      # gitlab.pasteur.fr only
+  variables:
+    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/front:$CI_COMMIT_SHORT_SHA"
+    BUILD_CONTEXT: "."
+    CONTAINERFILE: "front/Containerfile"
+
+.deploy-with-enix-toolbox:
+  stage: deploy
+  image: docker.io/enix/ci-toolbox:1.21
+  variables:
+    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/front:$CI_COMMIT_SHORT_SHA"
+  script:
+    - kubectl create secret
+      docker-registry registry-gitlab
+      --docker-server=registry-gitlab.pasteur.fr
+      --docker-username="$DOCKER_USER"
+      --docker-password="$DOCKER_TOKEN"
+      --docker-email=kubernetes@pasteur.fr
+      -n "$NAMESPACE"
+      --dry-run -o yaml | kubectl apply -f -
+    - envsubst < k8s/nyx-deployment.yaml | kubectl apply -n "$NAMESPACE" -f -
+    - envsubst < k8s/nyx-service.yaml | kubectl apply -n "$NAMESPACE" -f -
+    - envsubst < k8s/nyx-ingress.yaml | kubectl apply -n "$NAMESPACE" -f -
+  rules:
+    - if: $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID      # gitlab.pasteur.fr only
+
+deploy to pasteur.cloud:
+  extends: .deploy-with-enix-toolbox
+  variables:
+    NAMESPACE: "nyx-prod"
+  environment:
+    name: k8sprod-02/nyx-prod
+    url: https://nyx.pasteur.cloud
+  rules:
+    - if: $CI_COMMIT_BRANCH == "main"
+      when: manual
+
+deploy to dev.pasteur.cloud:
+  extends: .deploy-with-enix-toolbox
+  variables:
+    NAMESPACE: "nyx-dev"
+  environment:
+    name: k8sdev-01/nyx-dev
+    url: https://nyx.dev.pasteur.cloud
+  rules:
+    - if: $CI_COMMIT_BRANCH == "dev"
+      when: manual
+
diff --git a/k8s/nyx-deployment.yaml b/k8s/nyx-deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6d016a0509c20c1d81c011d82b03047529075e04
--- /dev/null
+++ b/k8s/nyx-deployment.yaml
@@ -0,0 +1,21 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: ${NAMESPACE}-depl
+  labels:
+    app: nyxui
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: nyxui
+  template:
+    metadata:
+      labels:
+        app: nyxui
+    spec:
+      containers:
+      - name: nyxui
+        image: $FQ_IMAGE_NAME
+        ports:
+        - containerPort: 8080
diff --git a/k8s/nyx-ingress.yaml b/k8s/nyx-ingress.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d959e16936ef3d6df88b65613467418b61d1bd55
--- /dev/null
+++ b/k8s/nyx-ingress.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Ingress
+metadata:
+  name: ${NAMESPACE}-ingress
+spec:
+  ingressClassName: external
+  rules:
+  - host: $PUBLIC_URL
+    http:
+      paths:
+      - backend:
+          serviceName: ${NAMESPACE}-service
+          servicePort: 80
+        path: /
diff --git a/k8s/nyx-service.yaml b/k8s/nyx-service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cded451fd059955ce7e234aa3298de996cf67b2e
--- /dev/null
+++ b/k8s/nyx-service.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: ${NAMESPACE}-service
+spec:
+  selector:
+    app: nyxui
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 8080