diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b9e25f249556c0ff7c0948070f05afb1dfc93856
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,46 @@
+---
+image: adarnimrod/ci-images:docker
+
+stages:
+  - test
+  - build
+  - run
+
+pre-commit:
+  stage: test
+  image: adarnimrod/ci-images:pre-commit
+  variables:
+    XDG_CACHE_HOME: "$CI_PROJECT_DIR/.cache"
+    # Disabled until https://github.com/pre-commit/pre-commit/issues/1387 is
+    # resolved.
+    SKIP: "hadolint,docker-compose"
+  script:
+    - pre-commit run --all-files
+  cache:
+    paths:
+      - .cache/
+
+build:
+  stage: build
+  tags: ["host01.shore.co.il"]
+  variables:
+    # COMPOSE_DOCKER_CLI_BUILD: "1"
+    # DOCKER_BUILDKIT: "1"
+  script:
+    - docker-compose build --no-cache --pull
+    - docker-compose pull --quiet
+
+run:
+  stage: run
+  tags: ["host01.shore.co.il"]
+  when: manual
+  script:
+    - docker-compose up --detach --remove-orphans
+    # yamllint disable rule:line-length
+    - |
+        for i in $(seq 12)
+        do
+            docker container inspect --format '{{ .State.Health.Status }}' $(docker-compose ps -q) | grep -v '^healthy$' || break
+            sleep 10
+        done
+        ! docker container inspect --format '{{ .State.Health.Status }}' $(docker-compose ps -q) | grep -v '^healthy$'
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7dfd794966c6d010a34f012fa91b73e022c889be..593c19f554b57e842dfb7e459f64bc3e9356ee35 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -19,14 +19,19 @@ repos:
     hooks:
       - id: proselint
         types: [plain-text]
-        exclude: LICENSE|requirements
-  - repo: https://www.shore.co.il/git/shell-pre-commit/
+        exclude: LICENSE
+  - repo: https://git.shore.co.il/nimrod/shell-pre-commit.git/
     rev: v0.6.0
     hooks:
       - id: shell-lint
       - id: shellcheck
-  - repo: https://www.shore.co.il/git/docker-pre-commit
+  - repo: https://git.shore.co.il/nimrod/docker-pre-commit.git/
     rev: v0.3.0
     hooks:
       - id: hadolint
       - id: docker-compose
+  - repo: https://github.com/Yelp/detect-secrets
+    rev: v0.13.0
+    hooks:
+      - id: detect-secrets
+        exclude: \.diff$
diff --git a/docker-compose.yml b/docker-compose.yml
index 5aab8144a4480f1a442460ca41c1978e731cd797..ec4f4d4d5ae8205089320a068f70c1e60685315c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -10,53 +10,50 @@ services:
 
   ldap:
     build:
-      cache_from:
-        - adarnimrod/slapd
       context: slapd/
-    domainname: "${LDAP_HOSTNAME:-ldap}.${LDAP_DOMAIN:-nowhere.com}"
     environment:
       LDAP_ROOTPASS: &password "${LDAP_ROOTPASS:-foo}"
-      LDAP_DOMAIN: "${LDAP_DOMAIN:-nowhere.com}"
-      LDAP_ORGANIZATION: "${LDAP_ORGANIZATION:-none}"
-    hostname: "${LDAP_HOSTNAME:-ldap}"
+      LDAP_DOMAIN: "${LDAP_DOMAIN:-shore.co.il}"
+      LDAP_ORGANIZATION: "${LDAP_ORGANIZATION:-shore}"
+      #SLAPD_DEBUG_LEVEL: "any"
+      SSL_DHPARAMS_FILE: /var/ssl/dhparams
+    hostname: "${LDAP_HOSTNAME:-ldap}.${LDAP_DOMAIN:-shore.co.il}"
     image: adarnimrod/slapd
     restart: always
     volumes:
       - _run_slapd:/run/slapd
       - ldap:/var/lib/ldap
       - backup_ldap:/var/backups/ldap
-
-  nss-pam-ldapd:
-    build:
-      context: nss-pam-ldapd/
-    command: /usr/sbin/nslcd --debug --nofork
-    depends_on:
-      - ldap
-    environment:
-      LDAP_BASE_DN: &base_dn "${LDAP_BASE_DN:-dc=nowhere,dc=com}"
-    volumes:
-      - _run_slapd:/run/slapd
+      - /var/ssl/dhparams:/var/ssl/dhparams:ro
 
   ldap-account-manager:
     build:
-      cache_from:
-        - adarnimrod/ldap-account-manager
       context: ldap-account-manager/
     depends_on:
       - ldap
     environment:
-      LAM_PASSWORD: *password
-      LDAP_ADMIN_DN: "cn=admin,${LDAP_BASE_DN:-dc=nowhere,dc=com}"
-      LDAP_BASE_DN: *base_dn
+      LAM_PASSWORD: *password  # pragma: allowlist secret
+      LDAP_ADMIN_DN: "cn=admin,${LDAP_BASE_DN:-dc=shore,dc=co,dc=il}"
+      LDAP_BASE_DN: &base_dn "${LDAP_BASE_DN:-dc=shore,dc=co,dc=il}"
     image: adarnimrod/ldap-account-manager
-    ports:
-      - 80:80
     restart: always
     volumes:
       - _run_slapd:/run/slapd
 
+  # nss-pam-ldapd:
+  #   build:
+  #     context: nss-pam-ldapd/
+  #   command: /usr/sbin/nslcd --debug --nofork
+  #   depends_on:
+  #     - ldap
+  #   environment:
+  #     LDAP_BASE_DN: *base_dn
+  #   volumes:
+  #     - _run_slapd:/run/slapd
+
 volumes:
   _run_slapd:
+    name: run_slapd
   ldap:
   backup_ldap:
     labels:
diff --git a/ldap-account-manager/Dockerfile b/ldap-account-manager/Dockerfile
index ea9a02cd34cc3da79023a6faf1a76a96044e726b..67bfa936f192b413c920bb70afd5c53d4ddb5a78 100644
--- a/ldap-account-manager/Dockerfile
+++ b/ldap-account-manager/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:sid-slim
+FROM debian:bullseye-slim
 # hadolint ignore=DL3008
 RUN apt-get update && \
     DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
@@ -15,7 +15,6 @@ RUN apt-get update && \
     a2enmod status && \
     ln -sf /dev/stdout /var/log/apache2/access.log && \
     ln -sf /dev/stderr /var/log/apache2/error.log && \
-    ln -sf /dev/stdout /var/log/apache2/lam.log && \
     ln -sf /dev/stdout /var/log/apache2/other_vhosts_access.log && \
     rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/archives/*
 ENV APACHE_RUN_DIR=/run/apache2 \
@@ -28,8 +27,7 @@ COPY --chown=root:root entrypoint /usr/local/bin/
 COPY --chown=root:root lam-setpass /usr/local/bin/
 RUN patch --strip 0 --verbose --directory / --input /root/patch.diff && \
     apache2 -t
-ENV LDAP_URI=ldapi:/// \
-    LAM_PASSWORD=lam
+ENV LDAP_URI=ldapi:///
 EXPOSE 80
 USER "www-data"
 WORKDIR /var/www
diff --git a/ldap-account-manager/README.md b/ldap-account-manager/README.md
index b333d630b3ee93849db92842f44f79987d1583e4..7d55bf161a8021faeba7addcd29d291e0b0df976 100644
--- a/ldap-account-manager/README.md
+++ b/ldap-account-manager/README.md
@@ -6,7 +6,7 @@
 
 Name | Description | Default value
 --- | --- | ---
-`LAM_PASSWORD` | Password for administrating LAM | `lam`
+`LAM_PASSWORD` | Password for administering LAM | `lam`
 `LDAP_URI` | URI of the LDAP service | `ldapi:///`
 `LDAP_ADMIN_DN` | DN of the admin account
 `LDAP_BASE_DN` | Base DN
diff --git a/ldap-account-manager/patch.diff b/ldap-account-manager/patch.diff
index d39c2fb5fc2a6ffa0e70b5981e62b2e5b3a58310..a796b93eaf755e60da10e34801088335123d6e03 100644
--- a/ldap-account-manager/patch.diff
+++ b/ldap-account-manager/patch.diff
@@ -5,7 +5,7 @@
  
  # log destination
 -logDestination: SYSLOG
-+logDestination: /var/log/apache2/lam.log
++logDestination: /dev/stdout
 --- /etc/apache2/sites-available/000-default.conf	2018-11-03 13:34:33.000000000 +0200
 +++ /etc/apache2/sites-available/000-default.conf	2019-06-25 14:55:43.956626591 +0300
 @@ -18,7 +18,7 @@
diff --git a/slapd/Dockerfile b/slapd/Dockerfile
index 85c054075cc66998ec8785a74cb44f95133be359..118c59e66dd09c2f1956df848999467b67e380a0 100644
--- a/slapd/Dockerfile
+++ b/slapd/Dockerfile
@@ -43,5 +43,5 @@ WORKDIR /var/lib/ldap
 USER openldap
 ENTRYPOINT [ "entrypoint" ]
 CMD [ "slapd", "-F", "/var/lib/ldap/config", "-u", "openldap", "-g", "openldap", "-h", "\"$LDAP_URLS\"", "-d", "$SLAPD_DEBUG_LEVEL" ]
-HEALTHCHECK CMD ldapsearch -b cn=config > /dev/null || exit 1
+HEALTHCHECK --start-period=5m CMD ldapsearch -b cn=config > /dev/null || exit 1
 STOPSIGNAL INT
diff --git a/slapd/backup b/slapd/backup
index 6ba3110ff0b866dbea711b51333110ffefba07b4..320d7ff7230c6f15fb7db5e53e76faa30d6a859f 100755
--- a/slapd/backup
+++ b/slapd/backup
@@ -1,9 +1,11 @@
 #!/bin/sh
 set -eux
 
+alias slapcat='slapcat -vF /var/lib/ldap/config'
+
 slapcat -n0 -v -l /var/backups/ldap/config.ldif
 
 for dn in $(ldapsearch -Y EXTERNAL -LLL -s base -b '' o namingContexts | sed -n '/namingContexts/ s/namingContexts: //gp')
 do
-    slapcat -b "$dn" -v -l "/var/backups/$dn.ldif"
+    slapcat -b "$dn" -v -l "/var/backups/ldap/$dn.ldif"
 done
diff --git a/slapd/config.ldif b/slapd/config.ldif
index 433d8261f04baf6af475af5df6333eef95a0af94..e10040d3d63236a2dac6ca9c78fb5a798c0382a3 100644
--- a/slapd/config.ldif
+++ b/slapd/config.ldif
@@ -18,7 +18,7 @@ olcTLSCertificateFile: ${SSL_CERT_FILE}
 olcTLSCertificateKeyFile: ${SSL_KEY_FILE}
 olcTLSCipherSuite: SECURE256:+SECURE128
 olcTLSProtocolMin: 3.1
-olcTLSDHParamFile: /usr/share/slapd/dh.pem
+olcTLSDHParamFile: ${SSL_DHPARAMS_FILE}
 
 # Frontend settings
 dn: olcDatabase={-1}frontend,cn=config
@@ -29,16 +29,20 @@ olcDatabase: {-1}frontend
 olcSizeLimit: 500
 # Allow unlimited access to local connection from the local root user
 olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
+# Allow unlimited access to local connection from the local slapd user
+olcAccess: {1}to * by dn.exact=gidNumber=${SLAPD_GID}+uidNumber=${SLAPD_UID},cn=peercred,cn=external,cn=auth manage by * break
 # Allow unauthenticated read access for schema and base DN autodiscovery
-olcAccess: {1}to dn.exact="" by * read
-olcAccess: {2}to dn.base="cn=Subschema" by * read
+olcAccess: {2}to dn.exact="" by * read
+olcAccess: {3}to dn.base="cn=Subschema" by * read
 
 # Config db settings
 dn: olcDatabase=config,cn=config
 objectClass: olcDatabaseConfig
 olcDatabase: config
 # Allow unlimited access to local connection from the local root user
-olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
+olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
+# Allow unlimited access to local connection from the local slapd user
+olcAccess: {1}to * by dn.exact=gidNumber=${SLAPD_GID}+uidNumber=${SLAPD_UID},cn=peercred,cn=external,cn=auth manage by * break
 olcRootDN: cn=admin,cn=config
 
 # Load schemas
diff --git a/slapd/entrypoint b/slapd/entrypoint
index 862d6221fc9b51d734fe5cb69ba197c5db594b8f..95c232baad556d2f6c01e26e65af00cbaabda5a6 100755
--- a/slapd/entrypoint
+++ b/slapd/entrypoint
@@ -27,8 +27,12 @@ then
 fi
 
 # Generate random DH parameters.
-echo Generating DH parameters, this will take a while. >&2
-time openssl dhparam -out /usr/share/slapd/dh.pem 2048
+if [ -z "${SSL_DHPARAMS_FILE:-}" ] || [ ! -f "${SSL_DHPARAMS_FILE:-}" ]
+then
+    echo Generating DH parameters, this will take a while. >&2
+    export SSL_DHPARAMS_FILE='/usr/share/slapd/dh.pem'
+    time openssl dhparam -out "$SSL_DHPARAMS_FILE" 2048
+fi
 
 # Run slapadd with the correct user and location of the config directory.
 alias slapadd='slapadd -gv -F /var/lib/ldap/config'
@@ -37,6 +41,10 @@ alias slapadd='slapadd -gv -F /var/lib/ldap/config'
 if [ -z "$(find /var/lib/ldap/config -maxdepth 1 -mindepth  1)" ]
 then
     echo No configuration found, generating a new one. >&2
+    SLAPD_UID="$(id -u openldap)"
+    export SLAPD_UID
+    SLAPD_GID="$(id -g openldap)"
+    export SLAPD_GID
     # shellcheck disable=SC2002
     cat /usr/share/slapd/config.ldif | envsubst | slapadd -b 'cn=config'
 fi
@@ -50,7 +58,7 @@ then
 fi
 
 # Configure the client.
-cat << EOF >> /etc/ldap/ldap.conf
+cat >> /etc/ldap/ldap.conf <<EOF
 URI         ldapi:///
 SASL_MECH   EXTERNAL
 BASE        $BASE_DN