중소기업 OpenLDAP 통합 인증 구축 – 02. Rootless Docker로 OpenLDAP 설치하기: docker-compose부터 systemd 자동 시작까지

2026.10.14

·

Rootless Docker를 선택한 이유

서버에서 Docker를 운영하는 방법은 크게 두 가지입니다.

방식root 권한포트 1024 미만보안
일반 Docker (root 모드)필요바인딩 가능컨테이너 탈출 시 호스트 root 탈취 위험
Rootless Docker불필요바인딩 불가컨테이너 탈출해도 일반 사용자 권한만

Rootless Docker는 Docker 데몬 자체를 일반 사용자 권한으로 실행합니다.
컨테이너 프로세스가 호스트 OS에 미치는 영향이 제한되므로 보안이 더 강합니다.

단, 1024 미만 포트를 바인딩할 수 없다는 제약이 있습니다.
LDAP 표준 포트는 389(LDAP)와 636(LDAPS)이지만, Rootless 환경에서는 이 포트를 쓸 수 없습니다.
그래서 10389 / 10636을 사용합니다. 내부 서비스 연동이므로 포트 번호는 맞춰서 설정하면 됩니다.

Sponsored


디렉토리 구조 설계

설치 전에 파일과 데이터가 어디에 놓일지 먼저 정합니다.

/app/openldap/       ← 설정·스크립트 (docker-compose.yml, .env, ldif 등)
/data/openldap/      ← LDAP DB (MDB 데이터베이스)
/data/ldap-config/   ← slapd 설정 (cn=config OLC)
/data/ldap-certs/    ← TLS 인증서 (ca.crt, ldap.crt, ldap.key)
/log/openldap/       ← slapd 로그
/data/backup/ldap/   ← 백업 (daily / weekly / monthly)

/app은 애플리케이션 설정, /data는 영구 데이터, /log는 로그로 역할을 분리했습니다.
컨테이너를 지우고 다시 올려도 /data와 /log 아래 데이터는 그대로 남습니다.

# 디렉토리 생성
mkdir -p /data/openldap /data/ldap-config /data/ldap-certs
mkdir -p /log/openldap /log/phpldapadmin
mkdir -p /data/backup/ldap
mkdir -p /app/openldap

.env 파일 작성

인증 정보와 경로를 docker-compose.yml에 하드코딩하지 않고 .env로 분리합니다.
git에 올릴 때 .env를 .gitignore에 추가하는 것을 잊지 마세요.

# /app/openldap/.env

# 도메인 설정
LDAP_ORGANISATION=YourOrganization
LDAP_DOMAIN=ldap.example.com
LDAP_BASE_DN=dc=ldap,dc=example,dc=com

# 관리자 비밀번호 — 강력한 값으로 변경 필수
LDAP_ADMIN_PASSWORD=change_this_strong_password
LDAP_CONFIG_PASSWORD=change_this_strong_password
LDAP_READONLY_USER_PASSWORD=change_this_readonly_password

# TLS 설정
LDAP_TLS=true
LDAP_TLS_CRT_FILENAME=ldap.crt
LDAP_TLS_KEY_FILENAME=ldap.key
LDAP_TLS_CA_CRT_FILENAME=ca.crt
LDAP_TLS_ENFORCE=false
LDAP_TLS_VERIFY_CLIENT=never

# 로그 레벨 (256 = stats, 0 = 없음)
LDAP_LOG_LEVEL=256

# 포트 (Rootless Docker: 1024 이상 필수)
LDAP_PORT=10389
LDAPS_PORT=10636
PHPLDAPADMIN_PORT=8080

# 데이터 경로
DATA_PATH=/data
LOG_PATH=/log

# phpLDAPadmin 설정
PHPLDAPADMIN_HTTPS=false
PHPLDAPADMIN_LDAP_HOSTS=openldap

docker-compose.yml 작성

version: '3.8'

services:
  openldap:
    image: osixia/openldap:1.5.0
    container_name: openldap
    hostname: openldap
    restart: unless-stopped
    environment:
      - LDAP_ORGANISATION=${LDAP_ORGANISATION}
      - LDAP_DOMAIN=${LDAP_DOMAIN}
      - LDAP_BASE_DN=${LDAP_BASE_DN}
      - LDAP_ADMIN_PASSWORD=${LDAP_ADMIN_PASSWORD}
      - LDAP_CONFIG_PASSWORD=${LDAP_CONFIG_PASSWORD}
      - LDAP_READONLY_USER=true
      - LDAP_READONLY_USER_USERNAME=readonly
      - LDAP_READONLY_USER_PASSWORD=${LDAP_READONLY_USER_PASSWORD}
      - LDAP_TLS=${LDAP_TLS}
      - LDAP_TLS_CRT_FILENAME=${LDAP_TLS_CRT_FILENAME}
      - LDAP_TLS_KEY_FILENAME=${LDAP_TLS_KEY_FILENAME}
      - LDAP_TLS_CA_CRT_FILENAME=${LDAP_TLS_CA_CRT_FILENAME}
      - LDAP_TLS_ENFORCE=${LDAP_TLS_ENFORCE}
      - LDAP_TLS_VERIFY_CLIENT=${LDAP_TLS_VERIFY_CLIENT}
      - LDAP_LOG_LEVEL=${LDAP_LOG_LEVEL}
    ports:
      - "${LDAP_PORT}:389"
      - "${LDAPS_PORT}:636"
    volumes:
      - ${DATA_PATH}/openldap:/var/lib/ldap
      - ${DATA_PATH}/ldap-config:/etc/ldap/slapd.d
      - ${DATA_PATH}/ldap-certs:/container/service/slapd/assets/certs
      - ${LOG_PATH}/openldap:/var/log/slapd
      - ./ldap-init.ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom/50-init.ldif
    command: --copy-service --loglevel debug
    networks:
      - ldap-network

  phpldapadmin:
    image: osixia/phpldapadmin:0.9.0
    container_name: phpldapadmin
    hostname: phpldapadmin
    restart: unless-stopped
    environment:
      - PHPLDAPADMIN_LDAP_HOSTS=${PHPLDAPADMIN_LDAP_HOSTS}
      - PHPLDAPADMIN_HTTPS=${PHPLDAPADMIN_HTTPS}
    ports:
      - "${PHPLDAPADMIN_PORT}:80"
    volumes:
      - ${DATA_PATH}/phpldapadmin:/var/www/phpldapadmin
      - ${LOG_PATH}/phpldapadmin:/var/log/nginx
    depends_on:
      - openldap
    networks:
      - ldap-network

networks:
  ldap-network:
    driver: bridge
    name: ldap-network

주요 설정 설명

restart: unless-stopped
수동으로 멈추지 않는 한 컨테이너가 항상 재시작됩니다. systemd와 함께 쓸 때 유용합니다.

--copy-service 커맨드
osixia/openldap 이미지는 초기화 스크립트가 /container/service/ 아래에 있습니다.
--copy-service를 붙이면 이 스크립트를 컨테이너 내부로 복사해서 볼륨 마운트와 충돌 없이 실행됩니다.

50-init.ldif 마운트
컨테이너가 처음 시작될 때 자동으로 로드할 LDIF 파일을 지정합니다.
OU 구조, 기본 그룹 같은 초기 데이터를 여기에 넣어두면 컨테이너 재생성 시 자동으로 반영됩니다.
파일 이름의 숫자(50-)는 로드 순서를 제어합니다. 기본 스크립트들이 먼저 실행된 후 로드됩니다.

ldap-network
phpLDAPadmin과 openldap이 같은 Docker 네트워크에 있어야 컨테이너 이름(openldap)으로 내부 통신이 됩니다.
phpLDAPadmin의 PHPLDAPADMIN_LDAP_HOSTS=openldap 설정이 이 네트워크 이름을 사용합니다.


ldap-init.ldif: 초기 OU 구조 정의

컨테이너가 처음 뜰 때 자동으로 생성할 OU와 기본 엔트리를 정의합니다.

# OU: 사용자
dn: ou=people,dc=ldap,dc=example,dc=com
objectClass: organizationalUnit
ou: people
description: User accounts

# OU: 그룹
dn: ou=Groups,dc=ldap,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups
description: Groups

# OU: 서비스 계정
dn: ou=services,dc=ldap,dc=example,dc=com
objectClass: organizationalUnit
ou: services
description: Service accounts

주의: 이 파일은 컨테이너가 처음 초기화될 때 한 번만 실행됩니다. 이미 /data/openldap에 데이터가 있으면 재실행하지 않습니다. 초기화를 다시 하려면 /data/openldap와 /data/ldap-config를 비우고 컨테이너를 재생성해야 합니다.


서비스 시작

cd /app/openldap

# 처음 시작
docker compose up -d

# 로그 확인
docker compose logs -f openldap

정상 시작 로그에는 이런 메시지가 나옵니다.

slapd starting

동작 확인

# LDAP 연결 테스트 (익명 바인드)
docker exec openldap ldapsearch -x \
  -H ldap://localhost:389 \
  -s base -b "" "(objectClass=*)" namingContexts

# 관리자로 OU 조회
docker exec openldap ldapsearch -x \
  -H ldap://localhost:389 \
  -D "cn=admin,dc=ldap,dc=example,dc=com" \
  -w 'your_admin_password' \
  -b "dc=ldap,dc=example,dc=com" \
  "(objectClass=organizationalUnit)" dn

systemd user 서비스 등록

Docker Compose를 수동으로 up하면 서버가 재시작될 때 LDAP도 같이 내려갑니다.
systemd user 서비스로 등록하면 로그인 없이도 부팅 시 자동으로 올라옵니다.

서비스 파일 작성

mkdir -p ~/.config/systemd/user
# ~/.config/systemd/user/openldap.service
[Unit]
Description=OpenLDAP Docker Service
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/app/openldap
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=30

[Install]
WantedBy=default.target

서비스 등록 및 활성화

# systemd 데몬 재로드
systemctl --user daemon-reload

# 부팅 시 자동 시작 등록
systemctl --user enable openldap.service

# 지금 시작
systemctl --user start openldap.service

# 상태 확인
systemctl --user status openldap.service

Linger 설정 (로그인 없이 자동 실행)

systemd user 서비스는 기본적으로 해당 사용자가 로그인해야 시작됩니다.
서버 재시작 후 로그인 없이 LDAP이 올라오려면 Linger를 활성화해야 합니다.

# 현재 사용자에 대해 Linger 활성화
sudo loginctl enable-linger $USER

# 확인
loginctl show-user $USER | grep Linger
# Linger=yes

관리 스크립트 (ldapserver.sh)

매번 systemctl --user 명령을 치는 게 번거롭다면 래퍼 스크립트 하나로 묶어두면 편합니다.

#!/bin/bash
# ldapserver.sh — OpenLDAP 서비스 관리

SERVICE="openldap.service"
COMPOSE_DIR="$(cd "$(dirname "$0")" && pwd)"

case "$1" in
  start)
    systemctl --user start $SERVICE
    ;;
  stop)
    systemctl --user stop $SERVICE
    ;;
  restart)
    systemctl --user restart $SERVICE
    ;;
  status)
    systemctl --user status $SERVICE --no-pager
    docker compose -f $COMPOSE_DIR/docker-compose.yml ps
    ;;
  logs)
    docker compose -f $COMPOSE_DIR/docker-compose.yml logs --tail=${2:-50}
    ;;
  health)
    docker inspect --format='{{.State.Status}}' openldap
    docker stats --no-stream openldap
    ;;
esac
chmod +x ldapserver.sh
./ldapserver.sh start
./ldapserver.sh status
./ldapserver.sh logs 100

여기까지의 상태

이 편을 마치면 다음 상태입니다.

  • OpenLDAP 컨테이너가 10389(LDAP) / 10636(LDAPS) 포트로 실행 중
  • phpLDAPadmin이 8080 포트에서 접속 가능
  • 서버 재시작 후 자동으로 올라오는 systemd user 서비스 등록 완료
  • ou=people, ou=Groups, ou=services OU 구조 초기화 완료

다음 편에서는 LDAPS 통신에 필요한 TLS 인증서를 직접 발급하고 OpenLDAP에 적용하는 방법을 다룹니다.


MORE POSTS

다른 글 보기

테크 랩

PMBOK 완독기 – 00. 오리엔테이션: 왜 정석을 완독하나 + 6판·7판 지도

PMBOK을 목차대로 완독하며 IT 현장에 번역하는 시리즈 시작. 6판(10지식영역)·7판(원칙·테일러링) 지도와 15편 로드맵.
2026.10.22
guniq 인사이트 썸네일 — 중소기업 OpenLDAP 통합 인증 구축 – 07. 백업·로그·운영 자동화: 장애 없는 LDAP 서버 유지하기
테크 랩

중소기업 OpenLDAP 통합 인증 구축 – 07. 백업·로그·운영 자동화: 장애 없는 LDAP 서버 유지하기

LDAP 서버는 설치 후가 더 중요합니다. 데이터 유실을 막는 백업 전략(daily/weekly/monthly), slapd 로그 관리와 logrotate 설정, 헬스체크 자동화까지 — 실제 운영 중인 스크립트를 바탕으로 LDAP 서버를 안정적으로 유지하는 방법을 정리합니다.
2026.10.21
guniq 인사이트 썸네일 — 중소기업 OpenLDAP 통합 인증 구축 – 06. Synology NAS LDAP 연동: DSM 설정과 그룹 권한 매핑
테크 랩

중소기업 OpenLDAP 통합 인증 구축 – 06. Synology NAS LDAP 연동: DSM 설정과 그룹 권한 매핑

Synology DSM의 LDAP 클라이언트를 커스텀 프로파일로 설정하는 방법을 정리합니다. groupPosixAux 필터, memberUid 매핑, LDAPS 인증서 처리까지 — 표준을 지킨 LDAP 구조가 NAS 연동을 얼마나 단순하게 만드는지 확인합니다.
2026.10.20

프로젝트 문의 환영합니다

기획부터 개발, 운영까지 함께 만들어 드립니다.

무료 3분 자가진단

우리 회사, 자체 클라우드가 답일까?

AWS vs 자체 인프라 · 11개 항목 3분 체크