Docker Compose로 Mattermost 사내 메신저 구축하기 (Teams 대체)
Teams를 더 이상 쓰지 않게 되면서, 무료 오픈소스 메신저를 자체 서버에 설치해보기로 했다. 여러 후보(Rocket.Chat, Zulip, Matrix) 중 Mattermost를 선택했다. Slack과 가장 비슷한 UX를 제공하고, 오픈소스 Team Edition은 인원 제한 없이 완전 무료이기 때문이다.
왜 Mattermost인가
- 2015년부터 개발된 오픈소스 프로젝트로 커뮤니티/문서가 풍부하다.
- 채팅, 채널, 파일 업로드, 검색, 멘션, DM, 이모지 반응 등 기본 기능은 전부 무료(Team Edition)이며 인원 제한이 없다.
- LDAP/SSO, 고가용성 클러스터링, 컴플라이언스 리포트 같은 기능만 유료(Professional/Enterprise) 티어에서 제공된다. 일반적인 사내 채팅+파일공유 용도라면 무료판으로 충분하다.
docker-compose.yml 작성
Mattermost(Team Edition) + PostgreSQL 조합으로 구성했다.
version: "3.8"
services:
postgres:
image: postgres:15-alpine
container_name: mattermost-postgres
restart: unless-stopped
environment:
POSTGRES_USER: mmuser
POSTGRES_PASSWORD: <비밀번호>
POSTGRES_DB: mattermost
volumes:
- /mnt/data/mattermost/postgres:/var/lib/postgresql/data
networks:
- mattermost-network
mattermost:
image: mattermost/mattermost-team-edition:latest
container_name: mattermost
restart: unless-stopped
depends_on:
- postgres
ports:
- "8065:8065"
environment:
MM_SQLSETTINGS_DRIVERNAME: postgres
MM_SQLSETTINGS_DATASOURCE: "postgres://mmuser:<비밀번호>@postgres:5432/mattermost?sslmode=disable&connect_timeout=10"
MM_SERVICESETTINGS_SITEURL: "http://서버IP:8065"
MM_FILESETTINGS_DRIVERNAME: "local"
MM_FILESETTINGS_DIRECTORY: "/mattermost/data"
volumes:
- /mnt/data/mattermost/config:/mattermost/config
- /mnt/data/mattermost/data:/mattermost/data
- /mnt/data/mattermost/logs:/mattermost/logs
- /mnt/data/mattermost/plugins:/mattermost/plugins
- /mnt/data/mattermost/client-plugins:/mattermost/client/plugins
- /mnt/data/mattermost/bleve-indexes:/mattermost/bleve-indexes
networks:
- mattermost-network
networks:
mattermost-network:
driver: bridge
포인트
- 포트 충돌 방지: 서버에 이미 여러 서비스(Jenkins, GitLab, Elasticsearch 등)가 떠 있었기 때문에,
docker ps로 사용 중인 포트를 먼저 확인하고 8065 포트가 비어있는지 체크했다. - 볼륨 경로: 루트 파티션 용량이 넉넉하지 않아서(
df -h확인 결과 71% 사용 중), 별도로 마운트된 대용량 디스크(/mnt/data) 아래에 데이터를 저장하도록 경로를 잡았다. - DB 격리: postgres 서비스는 호스트에 포트를 노출하지 않고 컨테이너 내부 네트워크에서만 통신하도록 설정했다. 컨테이너 이름과 데이터 경로가 기존에 떠 있던 다른 postgres/mariadb 컨테이너들과 전혀 겹치지 않아 기존 서비스에 영향이 없다.
트러블슈팅 1: 권한 에러 (permission denied)
처음 docker compose up -d 실행 시 아래 에러가 반복적으로 발생했다.
Error: failed to load configuration: could not create config file: open /mattermost/config/config.json: permission denied원인: Mattermost 컨테이너는 root가 아닌 UID 2000 사용자로 실행되는데, mkdir -p로 만든 호스트 폴더의 소유자가 root(또는 sudo 실행 계정)라서 컨테이너 내부에서 쓰기 권한이 없었다.
해결:
sudo chown -R 2000:2000 /mnt/data/mattermost/config
sudo chown -R 2000:2000 /mnt/data/mattermost/data
sudo chown -R 2000:2000 /mnt/data/mattermost/logs
sudo chown -R 2000:2000 /mnt/data/mattermost/plugins
sudo chown -R 2000:2000 /mnt/data/mattermost/client-plugins
sudo chown -R 2000:2000 /mnt/data/mattermost/bleve-indexes
이후 재기동하니 정상적으로 마이그레이션이 진행되고 서버가 떴다.
초기 설정: 관리자 계정 & 팀 초대
- 첫 계정 생성 시 사용자명(Username)은 영문 소문자 + 숫자만 가능하다. 한글 사용자명 입력 시 에러가 난다.
- 팀원 초대는 두 가지 방식이 있다.
- 초대 링크 복사 → 카톡 등으로 직접 전달
- 관리자 도구 → 사이트 구성 → "누구나 이 팀에 참여할 수 있습니다" 토글 활성화 → 서버 주소만 알려주면 팀원이 알아서 가입
- 이메일 초대는 SMTP 서버가 설정되어 있지 않으면 전송되지 않는다("SMTP가 시스템 콘솔에서 구성되지 않았습니다"). 소규모 팀이면 SMTP 설정 없이 링크/오픈서버 방식으로 충분하다.
- 데스크톱 앱에서 초대 링크 클립보드 복사가 안 되는 경우가 있었는데, 이때는 System Console에서 "공개 서버"를 활성화하고 서버 주소만 공유하는 방식으로 우회했다. (관리자 도구 → 사이트 구성 → 인증 → 가입 → 공개 서버: 활성화)
트러블슈팅 2: 개인 메시지가 실시간으로 안 뜸
DM을 보내도 바로 화면에 안 뜨고, 다른 채널로 갔다 와야 보이는 증상이 있었다.
확인한 것들:
docker stats로 CPU/메모리 확인 → 리소스는 충분히 여유로움 (CPU 0.1%대)- 컨테이너 로그에서 웹소켓 에러 확인 → 특이 에러 없음
이 증상은 전형적으로 웹소켓 연결 문제일 때 나타난다. Mattermost는 실시간 메시지 전달을 위해 웹소켓을 쓰는데, MM_SERVICESETTINGS_SITEURL 값이 실제 접속 주소와 다르면 웹소켓 연결이 불안정해질 수 있어 이 값을 서버 실제 IP로 맞춰주는 것이 첫 번째 점검 포인트였다.
트러블슈팅 3: 모바일 푸시 알림이 안 옴
모바일 앱에서 "이 서버의 알림을 수신할 수 없습니다" 메시지가 계속 떴다.
1차 조치: System Console → 환경 → 푸시 알림 서버에서 다음과 같이 설정
- 모바일 푸시 알림:
TPNS 연결을 사용하여 iOS 및 Android 앱에 알림을 전송합니다 - 푸시 알림 서버:
https://push.mattermost.com(기본값인push-test.mattermost.com이 아니라 test가 빠진 정식 URL로 변경)
이 값을 바꾸고 컨테이너를 재시작해도 동일한 에러가 계속 발생했다.
진짜 원인: 서버 주소가 http://(HTTPS 아님)였기 때문이다. Mattermost 공식 모바일 앱은 보안 정책상 서버가 HTTPS로 연결되어 있어야만 푸시 알림 등록을 허용한다. 즉 TPNS 설정 자체는 문제가 아니었고, 사이트 자체가 HTTPS가 아닌 것이 근본 원인이었다.
해결 방향:
- 사내망 + IP 접속이라면 → 자체 서명 SSL 인증서 + Nginx 리버스 프록시 (기기에서 인증서 신뢰 예외 처리 필요)
- 사용 가능한 도메인이 있다면 → Let's Encrypt 무료 인증서로 정식 HTTPS 적용 (권장)
정리
| 항목 | 무료 여부 |
|---|---|
| 채팅, 채널, DM, 파일 업로드 | 무료 (Team Edition) |
| 데스크톱/모바일 알림 | 무료, 단 모바일 푸시는 HTTPS 필요 |
| SSO/LDAP, 고가용성, 컴플라이언스 | 유료 (Professional/Enterprise) |
소규모 팀의 사내 채팅용으로는 무료 Team Edition만으로 충분했고, docker-compose 하나로 기존에 운영 중이던 다른 서비스들과 완전히 격리된 상태로 손쉽게 추가할 수 있었다. 다만 모바일 푸시 알림까지 정상적으로 받으려면 HTTPS 적용이 사실상 필수라는 점은 미리 알아두면 좋을 것 같다.
파일 공유/동기화가 추가로 필요하다면 OneDrive 대체제로 Nextcloud를 같은 방식(docker-compose)으로 조합해서 쓸 수 있다.
'DevOps > Docker' 카테고리의 다른 글
| Docker Desktop - WSL kernel verision too low (0) | 2023.09.06 |
|---|---|
| windows에서 'docker-compose'은 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. (0) | 2023.09.06 |
