Securing Docker Registry with LDAP Authentication Using Goma Gateway

I'm a Software Engineer passionate about building scalable systems and simplifying infrastructure through open source. With over 5 years of hands-on experience, I specialize in Go (Golang), Kotlin, Spring Boot, and Linux-based systems, with a strong DevOps foundation in Docker, Kubernetes, and CI/CD automation.
I'm the author of several open source tools, including:
- PG-BKUP – PostgreSQL backup and restore
- MYSQL-BKUP – MySQL backup and restore solution
- Goma Gateway – Declarative API Gateway and reverse proxy
- Okapi – Fast and extensible web framework in Go
My focus is on building developer-friendly tools that are lightweight, portable, and production-ready.
Areas of Focus:
- Cloud-native architecture & API design
- Developer tooling & platform engineering
- DevOps, GitOps, and SRE best practices
- Secure infrastructure & automation workflows
Open source is at the core of my work. I thrive in both independent and collaborative environments, always aiming for clean code, thoughtful design, and real-world impact.
Introduction
Securing a self-hosted Docker Registry is crucial, especially in production environments. LDAP (Lightweight Directory Access Protocol) is a widely adopted standard for managing user authentication and access control across services.
In this tutorial, we’ll use Goma Gateway to secure a Docker Registry using LLDAP for authentication. Goma makes it easy to protect routes with built-in middleware and declarative configuration.
Prerequisites
Docker and Docker Compose installed
Basic understanding of:
Docker networking
Reverse proxies
LDAP concepts
Architecture Overview

1. What Is Goma Gateway?
Goma Gateway is a lightweight, high-performance, and security-first API Gateway built for modern cloud-native infrastructure. With a developer-friendly configuration, Goma supports powerful middleware, observability, and advanced protocols out of the box.
Key Features
Built-in authentication: Basic, JWT, OAuth2, LDAP, and ForwardAuth
Rate limiting, HTTP caching, and bot detection
Observability: Prometheus metrics, route health checks
Protocol support: REST, gRPC, TCP, UDP
TLS support: Let’s Encrypt and custom certificates
GitHub: jkaninda/goma-gateway
2. What Is LLDAP?
LLDAP is a lightweight, opinionated LDAP server designed to simplify authentication. It’s easy to deploy and comes with a minimal web UI for managing users and groups.
GitHub: lldap/lldap
3. Configure Local Hosts
Edit your /etc/hosts file to define virtual domains:
127.0.0.1 lldap.example.com registry.example.com okapi-api.example.com
Replace example.com With your domain, if needed.
4. Create a Docker Network
Create a shared Docker network for all services:
docker network create web
5. Docker Compose Setup
Create a compose.yaml file with the following services:
gateway: Goma Gatewaylldap: LDAP serverregistry: Docker Registryokapi-api: A test API service
services:
gateway:
image: jkaninda/goma-gateway
container_name: gateway
restart: always
volumes:
- ./goma.yml:/etc/goma/goma.yml
- ./extra:/etc/goma/extra
- ./certs:/etc/goma/certs
ports:
- 80:80
- 443:443
networks: [web]
lldap:
image: lldap/lldap:stable
container_name: lldap
restart: always
environment:
- UID=1
- GID=1
- TZ=Europe/Paris
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=example,dc=com
- LLDAP_LDAP_USER_PASS=adminPasword
ports:
- "3890:3890"
volumes:
- data:/data
networks: [web]
registry:
image: registry:3.0.0
container_name: registry
restart: always
volumes:
- registry:/var/lib/registry
networks: [web]
okapi-api:
image: jkaninda/okapi-example
container_name: okapi-api
restart: always
networks: [web]
volumes:
data: {}
registry: {}
networks:
web:
external: true
Important Security Notes:
Replace
LLDAP_JWT_SECRETandLLDAP_KEY_SEEDwith strong random valuesChange default
LLDAP_LDAP_USER_PASS
6. Goma Gateway Configuration
Create a file named goma.yml in the project root:
version: 2
gateway:
entryPoints:
web:
address: "[::]:80"
webSecure:
address: "[::]:443"
tls:
keys: []
# Uncomment for custom certs:
# - cert: /etc/goma/certs/cert.crt
# key: /etc/goma/certs/server.key.pem
log:
level: info
networking:
transport:
insecureSkipVerify: true
monitoring:
enableMetrics: true
metricsPath: /metrics
enableLiveness: true
enableRouteHealthCheck: true
includeRouteHealthErrors: true
extraConfig:
directory: /etc/goma/extra
watch: true
certManager:
provider: acme
acme:
# Uncomment to enable Let’s Encrypt
# email: admin@example.com
storageFile: /etc/letsencrypt/acme.json
7. Define Routes and Middlewares
Create a folder named extra and add two files: routes.yml and middlewares.yml.
extra/routes.yml
routes:
- name: lldap
path: /
hosts: [lldap.example.com]
target: http://lldap:17170
middlewares: [enforceHttps]
- name: registry
path: /
hosts: [registry.example.com]
rewrite: ''
target: http://registry:5000
middlewares: [enforceHttps]
- name: okapi-api
path: /
hosts: [okapi-api.example.com]
rewrite: ''
target: http://okapi-api:8080
middlewares: [enforceHttps]
extra/middlewares.yml
middlewares:
- name: enforceHttps
type: redirectScheme
rule:
scheme: https
permanent: true
8. Deployment
Launch all services:
docker compose up -d
9. Insecure Registry Configuration
If you haven't configured TLS yet, Docker needs to allow connections to the insecure registry (development only):
Create or edit /etc/docker/daemon.json:
{
"insecure-registries": ["registry.example.com"]
}
Restart Docker:
sudo systemctl restart docker
Tip: Use Let’s Encrypt or a custom certificate for production environments.
10. Access Your Services
LDAP UI: https://lldap.example.com Login with
admin / adminPasword. Then:Create a group:
registry_usersCreate a user:
bind_user(add tolldap_strict_readonly)Create another user and assign them to
registry_users
Okapi API: https://okapi-api.example.com/api/books
Docker Registry API: https://registry.example.com/v2/_catalog

11. Enable LDAP Authentication
Update middlewares.yml with LDAP auth middleware:
- name: ldap-auth
type: ldap
paths:
- /.*
rule:
forwardUsername: true
realm: restricted
url: ldap://lldap:3890
baseDN: dc=example,dc=com
bindDN: uid=bind_user,ou=people,dc=example,dc=com
bindPass: bind_user_password
userFilter: "(&(objectclass=person)(memberof=cn=registry_users,ou=groups,dc=example,dc=com)(uid=%s))"
startTLS: false
insecureSkipVerify: true
connPool:
size: 150
burst: 100
ttl: 30s
Then apply it in routes.yml:
- name: registry
path: /
hosts: [registry.example.com]
rewrite: ''
target: http://registry:5000
middlewares:
- enforceHttps
- ldap-auth
- name: okapi-api
path: /
hosts: [okapi-api.example.com]
rewrite: ''
target: http://okapi-api:8080
middlewares:
- enforceHttps
- ldap-auth
12. Test the Registry
Pull the Nginx image:
docker pull nginx:latest
Tag the image:
docker tag nginx:latest registry.example.com/nginx:latest
Push to your registry:
docker push registry.example.com/nginx:latest
You should be prompted for credentials, and only LDAP-authorized users will be able to push or pull.
Conclusion
You’ve successfully secured your Docker Registry using Goma Gateway and LLDAP. With just a few declarative configs and containers, you now have a robust, LDAP-backed authentication layer for your registry and a reusable pattern for protecting any internal API or service.
Feel free to extend this setup to protect other services and APIs with Goma’s flexible middleware system.



