Docker Compose로 Rocket.Chat 직접 구축하기
Docker Compose를 사용하여 VPS에 Rocket.Chat을 설치하는 방법을 설명합니다. MongoDB 레플리카 세트 설정, TLS 적용, 데이터 백업 및 OOM 킬러로 인한 컨테이너 종료 문제를 방지하는 권장 서버 사양을 상세히 안내합니다.
구축할 시스템
직접 소유하는 팀 전용 비공개 채팅 서비스입니다. Docker Compose를 사용하여 VPS에서 실행되는 Rocket.Chat을 구축하며, TLS 종료를 적용하고 모든 메시지는 백업 및 이전이 가능한 MongoDB 데이터베이스에 저장합니다. Rocket.Chat은 Slack 및 Teams를 대체할 수 있는 성숙한 오픈 소스 솔루션으로, 채널, 다이렉트 메시지, 스레드, 파일 공유, 음성 및 영상 통화 기능을 직접 임대하고 제어하는 하드웨어에서 제공합니다. 애플리케이션은 단일 컨테이너로 구성되어 몇 분 안에 실행할 수 있습니다. 실제 발생하는 대부분의 문제는 데이터베이스와 관련이 있으므로, 이 가이드의 상당 부분은 MongoDB, 특히 처음 접하는 사용자가 당황하기 쉬운 필수 요구 사항에 집중합니다. Rocket.Chat은 독립형(standalone) MongoDB에서는 실행되지 않으며, 단일 노드 구성이라 하더라도 반드시 레플리카 세트(replica set)가 필요합니다.
사전 요구 사항 및 아무도 알려주지 않는 RAM 계산법
서버 사양을 정직하게 산정하십시오. 소규모 팀을 위한 현실적인 최소 사양은 2 vCPU 및 4 GB RAM입니다. Rocket.Chat의 Node.js 프로세스는 자체적으로 약 1 GB에서 1.5 GB의 메모리를 점유하며, MongoDB의 WiredTiger 캐시는 기본적으로 남은 RAM의 절반 정도를 차지합니다. 2 GB VPS에서는 부팅 직후에는 두 프로세스가 공존할 수 있으나, 실제 트래픽이 유입되는 순간 충돌이 발생합니다. MongoDB는 캐시를 늘리고 Node는 힙 메모리를 확장하며, 커널은 페이지가 부족해집니다. 이때 OOM(Out-of-Memory) 킬러가 가장 큰 프로세스를 강제 종료하는데, 보통 mongod이 대상이 됩니다. 컨테이너는 Killed를 출력하고 Docker는 이를 재시작하며, 결과적으로 가벼운 부하조차 견디지 못하고 몇 분마다 끊기는 채팅 서버가 됩니다. 2 GB는 두 명 정도가 가볍게 테스트하기에는 적합하지만, 팀용 서버로는 부족합니다. 4 GB에서 시작하십시오. 수십 명의 동시 접속자, 화상 통화, 또는 증가하는 업로드 기록을 예상한다면 8 GB를 권장합니다.
시작하기 전에 세 가지를 준비해야 합니다. 첫째, VPS의 공인 IP를 가리키는 A 레코드가 포함된 도메인 이름이 필요합니다. Rocket.Chat의 실시간 기능과 모바일 클라이언트는 IP 주소가 아닌 안정적인 호스트네임을 요구합니다. 둘째, 서버 방화벽과 제공업체의 네트워크 방화벽(대부분의 제어판에서 별도로 관리됨) 모두에서 80번 및 443번 포트를 개방해야 합니다. 셋째, root 또는 sudo 권한을 가진 최신 Ubuntu 24.04 KVM VPS가 필요합니다. 채팅 서버를 첫 번째 서비스로 운영할지 고민 중이라면, 2026년 자가 호스팅의 가치에 대한 가이드에서 고려해야 할 장단점을 확인하십시오.
Docker 엔진 및 Compose 플러그인 설치
Ubuntu가 제공하는 docker.io 패키지가 아닌 Docker 공식 apt 저장소를 사용하십시오. 구형 독립형 docker-compose Python 바이너리도 사용하지 마십시오. 최신 Compose는 docker compose과 같이 하이픈 없이 공백을 사용하는 Docker 플러그인입니다. 구형 docker-compose v1은 지원이 종료되었으며 아래의 healthcheck 및 의존성 구문을 올바르게 처리하지 못합니다.
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin두 구성 요소가 모두 설치되었는지 확인하십시오:
sudo docker version
sudo docker compose versiondocker compose version 명령을 실행했을 때 Docker Compose version v2.x와 유사한 결과가 출력되는지가 핵심 확인 사항입니다. 만약 docker: 'compose' is not a docker command 오류가 발생한다면 플러그인이 설치되지 않은 것이며, 이후 혼란스러운 오류를 겪게 되므로 여기서 문제를 해결해야 합니다.
Compose 파일: 단일 노드 레플리카 세트로 구성하는 MongoDB
이 부분에서 실수가 잦으니 주의 깊게 읽어 주십시오. Rocket.Chat은 MongoDB의 change streams 기능을 사용하여 연결된 클라이언트에게 실시간으로 메시지를 전달하는데, 이 기능은 레플리카 세트에서만 사용할 수 있습니다. Rocket.Chat을 일반적인 독립형 mongod에 연결하면 연결은 성공하더라도 change stream을 열지 못해 재시작 루프에 빠지게 됩니다. 해결 방법은 간단합니다. 일반적인 MongoDB 컨테이너를 실행하되 --replSet 옵션을 추가하여 시작한 뒤, 단일 멤버 세트로 초기화하면 됩니다.
작업 디렉터리를 생성하고 compose.yml를 작성합니다.
services:
mongodb:
image: mongo:8.0
restart: always
command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--oplogSize", "128"]
volumes:
- mongodb_data:/data/db
- mongodb_config:/data/configdb
healthcheck:
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 10s
retries: 12
rocketchat:
image: registry.rocket.chat/rocketchat/rocket.chat:8.5.1
restart: always
depends_on:
mongodb:
condition: service_healthy
environment:
MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
ROOT_URL: "https://chat.example.com"
PORT: "3000"
ports:
- "127.0.0.1:3000:3000"
volumes:
mongodb_data:
mongodb_config:여기서 몇 가지 설정은 의도적으로 선택한 것입니다. Rocket.Chat 포트는 0.0.0.0이 아닌 127.0.0.1:3000에만 노출했습니다. 애플리케이션 자체에는 TLS가 없으므로 같은 서버 내의 리버스 프록시만 접근해야 합니다. 모든 인터페이스에 바인딩하면 평문 로그인 페이지가 공용 인터넷에 그대로 노출되기 때문입니다. MongoDB는 호스트에 전혀 노출되지 않으며, Compose 내부 네트워크에서 mongodb이라는 이름으로만 접근할 수 있습니다. 이는 MONGO_URL이 사용하는 호스트 이름과 정확히 일치합니다. MONGO_URL에는 ?replicaSet=rs0이 포함되어야 합니다. 이를 생략하면 드라이버는 레플리카 세트임에도 서버를 독립형으로 간주하여 change stream이 실패합니다. MONGO_OPLOG_URL은 oplog가 위치한 local 데이터베이스를 가리킵니다. 최신 Rocket.Chat은 change stream을 선호하지만, 이 설정을 유지해도 문제가 없으며 구형 코드 경로와의 호환성을 보장합니다. depends_on은 condition: service_healthy를 사용합니다. 따라서 Compose는 MongoDB가 ping에 응답할 때까지 Rocket.Chat 실행을 대기하는데, 이것이 바로 healthcheck의 목적입니다.
두 이미지 모두에 실제 버전 태그를 고정해야 한다. 여기서는 mongo:8.0와 8.5.1 같은 명시적인 Rocket.Chat 릴리스를 사용해야 하며, :latest는 절대 사용하지 않아야 한다. :latest는 무인 docker pull를 예기치 않은 업그레이드로 바꾸며, 이 업그레이드는 마이그레이션할 수 없다.
버전을 고정하기 전에 현재 안정 버전인 Rocket.Chat 릴리스와 해당 릴리스가 지원하는 MongoDB 버전을 확인해야 한다. Rocket.Chat은 릴리스마다 기계 판독이 가능한 정보 문서를 게시한다. curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}'는 8.5.1에서 compatibleMongoVersions: ["8.0"]를 반환하므로, 지원되는 엔진은 mongo:8.0뿐이다. 또한 서버를 지속적으로 관리하지 않으려는 경우 고정할 가치가 있는 장기 지원 빌드인지 알려 주는 lts 플래그도 제공한다.
모든 프로젝트가 버전이 지정된 이미지를 게시하는 것은 아니다. 이 경우 버전을 고정할 대상은 소스가 된다. openGym 운동 추적기 자체 호스팅은 변경되는 브랜치를 따라가는 대신 특정 git 태그를 체크아웃하고 해당 소스에서 빌드해야 한다는 뜻이다.
레플리카 세트 초기화
스택을 실행합니다:
sudo docker compose up -d레플리카 세트가 아직 존재하지 않으므로 Rocket.Chat은 즉시 충돌하고 Docker는 이를 계속 재시작합니다. 이는 예상된 동작입니다. 수동으로 한 번 생성하십시오:
sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'올바른 결과는 { ok: 1 }입니다. 몇 초 안에 단일 노드가 스스로를 프라이머리로 선출합니다. 다음 명령으로 확인하십시오:
sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'PRIMARY가 출력되어야 합니다. 이 페이지 전체에서 가장 중요한 세부 사항은 host: "mongodb:27017" 인수입니다. 멤버 목록 없이 rs.initiate()만 실행하면, MongoDB는 컨테이너의 내부 호스트 이름인 a1b2c3d4e5f6과 같은 임의의 해시 값으로 레플리카 세트를 알립니다. 자체 컨테이너에서 연결하는 Rocket.Chat은 해당 이름을 해석할 수 없으므로, MongoDB 드라이버는 DNS 확인에 실패하고 MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6를 기록하며 무한 루프에 빠집니다. 항상 MONGO_URL과 일치하는 명시적인 서비스 이름을 사용하여 초기화하십시오.
첫 부팅: 서비스 시작 모니터링
세트가 프라이머리가 되면, Rocket.Chat은 다음 재시작 시 정상적으로 연결되며 초기 실행 마이그레이션을 시작합니다. 다음 로그를 확인하십시오.
sudo docker compose logs -f rocketchat기다려야 할 줄은 시작 배너입니다.
+--------------------------------------------+
SERVER RUNNING
Rocket.Chat Version: 8.5.1
NodeJS Version: 22.22.3 - x64
+--------------------------------------------+첫 부팅은 애플리케이션이 데이터베이스 마이그레이션을 수행하고 인덱스를 생성하므로 시간이 다소 소요됩니다. 문제가 있다고 판단하기 전에 1~2분 정도 기다려 주십시오. 만약 로그에 MongoServerSelectionError: Server selection timed out after 30000 ms이 ReplicaSetNoPrimary 유형의 토폴로지 설명과 함께 반복된다면, 레플리카 세트가 초기화되지 않은 것입니다. 만약 임의의 해시값과 함께 getaddrinfo ENOTFOUND이 반복된다면, 잘못된 호스트로 초기화된 것입니다. 어느 경우든 이전 단계로 돌아가십시오. SERVER RUNNING가 표시되면 Rocket.Chat이 127.0.0.1:3000에서 리스닝 상태가 된 것이며, 이제 실제 호스트 이름을 설정하고 TLS를 적용할 차례입니다.
TLS 적용하기
Rocket.Chat을 평문 HTTP 상태로 노출하지 마십시오. http://를 통해 한 번만 로그인해도 관리자 비밀번호가 경로상의 모든 이에게 노출됩니다. 동일한 서버 내의 리버스 프록시에서 TLS를 종료하고 127.0.0.1:3000로 전달하십시오. 두 가지가 중요합니다. 첫째, Rocket.Chat은 실시간 서비스이므로 WebSocket 업그레이드 헤더를 프록시가 전달하지 않으면 오작동합니다. 둘째, 컨테이너의 ROOT_URL 설정이 사용자가 입력하는 공개 HTTPS 주소와 정확히 일치해야 합니다.
먼저 애플리케이션으로 프록시를 수행하고 업그레이드 헤더를 전달하는 평문 HTTP nginx 서버 블록을 작성하십시오. 이를 /etc/nginx/sites-available/rocketchat로 저장하고 sites-enabled에 심볼릭 링크를 생성한 뒤 리로드하십시오:
server {
listen 80;
server_name chat.example.com;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}현재는 80번 포트로 유지하십시오. listen 443 ssl; 설정이 없고 인증서가 없는 블록은 sudo nginx -t를 통과하지 못합니다. nginx를 리로드(sudo nginx -t && sudo systemctl reload nginx)한 다음 인증서를 발급받으십시오. Ubuntu에서 가장 깔끔한 방법은 Certbot과 nginx를 이용한 Let's Encrypt TLS 인증서 발급을 따르는 것입니다. certbot --nginx는 위 블록을 제자리에서 수정하여 listen 443 ssl;, ssl_certificate 라인, 그리고 80에서 443으로의 자동 리다이렉트를 추가하며 갱신 작업까지 예약해 줍니다. 이미 하나의 프록시 뒤에서 여러 컨테이너를 운영 중이라면 여러 Docker 앱을 위한 Traefik 자동 TLS 설정이 더 깔끔한 선택입니다. rocketchat 서비스에 라우터와 서비스 레이블을 추가하면 Traefik이 nginx 블록 없이도 인증서를 요청하고 갱신합니다. 어떤 방식을 선택하든 compose.yml에서 ROOT_URL을 https://chat.example.com로 설정하고 sudo docker compose up -d을 다시 실행하여 컨테이너가 변경 사항을 반영하도록 하십시오. 서버를 공용 인터넷이 아닌 내부 네트워크에서만 접근 가능하게 하려면 VPS에 직접 호스팅하는 WireGuard VPN을 앞단에 두고 프록시를 터널 주소에 바인딩하십시오.
최초 실행 설정 마법사
https://chat.example.com에 접속하면 Rocket.Chat이 간단한 설정 마법사를 안내합니다. 첫 번째 단계는 관리자 계정 설정으로, 실명, 사용자 이름, 이메일, 강력한 암호를 입력합니다. 이 계정은 현재 존재하는 유일한 계정이므로 분실하지 않도록 주의하십시오. 다음은 조직 및 서버 정보 단계로, 조직명, 업종, 규모, 사이트 이름 및 기본 언어를 입력합니다. 이는 부가적인 정보이므로 내용을 채우고 다음으로 진행하면 됩니다. 그 후 가장 중요한 선택 단계가 나타납니다. Rocket.Chat Cloud에 워크스페이스를 등록할지, 아니면 독립형(standalone)으로 유지할지 결정해야 합니다.
등록을 선택하면 Rocket.Chat 게이트웨이를 통한 모바일 푸시 알림과 애드온 마켓플레이스를 사용할 수 있지만, Rocket.Chat 클라우드와 제어 평면 연결이 생성됩니다. 독립형을 선택하면 서버를 완전히 비공개로 유지하고 외부 의존성을 없앨 수 있습니다. 하지만 Apple과 Google은 직접 빌드한 앱이 푸시 인증서를 보유하는 것을 허용하지 않으므로, 공식 앱이 클라우드 게이트웨이를 거치지 않는 한 iOS 및 Android 푸시 알림은 작동하지 않게 됩니다. 개인정보 보호가 최우선이고 사용자가 웹 앱을 주로 사용한다면 독립형을 선택하십시오. 모바일 푸시 알림이 반드시 필요하다면 등록을 선택하십시오. 이 설정은 나중에 관리자(Admin) 메뉴에서 변경할 수 있습니다.
사용자를 초대하기 전에 보안을 강화하십시오
Rocket.Chat은 기본적으로 open registration on 상태로 제공됩니다. 즉, 등록 양식(Registration Form)이 Public으로 설정되어 있어 URL을 아는 사람은 누구나 계정을 생성할 수 있습니다. 공개 호스트네임에서는 이는 열린 문과 다름없습니다. Admin → Settings → Accounts → Registration으로 이동하여 Registration Form을 Disabled로 설정하십시오. 이렇게 하면 관리자가 직접 계정을 생성하거나 초대 링크를 통해서만 가입할 수 있습니다. 또는 Secret URL로 설정할 수도 있습니다. 해당 설정 페이지에서 특별히 공개 읽기 전용 채널이 필요한 경우가 아니라면 Allow Anonymous Read와 Allow Anonymous Write를 끄십시오. 모든 계정을 수동으로 생성하는 것이 번거롭고 팀이 사용하는 서비스가 Rocket.Chat 하나뿐이 아니라면, Rocket.Chat의 OAuth 로그인을 자체 호스팅된 Authentik SSO 서버로 연결하십시오. 이렇게 하면 서비스마다 계정을 관리할 필요 없이 한 곳에서 입퇴사자를 처리할 수 있습니다.
파일 업로드 저장 위치도 결정해야 합니다. 기본 File Upload 저장소는 GridFS이며, 이는 모든 이미지와 첨부 파일을 MongoDB 내부에 저장합니다. 설정은 간단하지만, 사용자가 스크린샷을 붙여넣을 때마다 데이터베이스와 생성하는 모든 mongodump의 크기가 제한 없이 커집니다. Admin → Settings → File Upload에서 저장소를 로컬 파일 시스템이나 S3 호환 버킷으로 변경하고 적절한 최대 파일 크기를 설정할 수 있습니다. 소규모 팀의 경우 GridFS를 사용해도 괜찮지만, 시간이 지날수록 백업 데이터가 무거워진다는 점을 유의하십시오.
mongodump을 이용한 백업
모든 데이터는 mongodb_data 볼륨에 저장됩니다. 실행 중인 데이터베이스의 볼륨을 단순히 복사하지 말고, mongodump을 사용하여 일관된 덤프를 생성한 뒤 호스트의 파일로 스트리밍하십시오.
sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gz이 단일 gzipped 아카이브가 사용자, 채널, 메시지, 설정 등 전체 작업 공간을 포함합니다. GridFS에 업로드를 그대로 두었다면 파일까지 포함됩니다. 업로드를 파일 시스템이나 S3로 옮겼다면 해당 저장소는 별도로 백업해야 합니다. 새로운 스택에 복원하려면 먼저 레플리카 세트를 초기화한 후 다음 명령을 실행하십시오.
sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gz아카이브를 서버 외부인 오브젝트 스토리지, 다른 서버 등 VPS 장애 시 함께 소실되지 않을 곳으로 복사하고, cron을 통해 매일 밤 덤프를 실행하십시오. 복원해 본 적 없는 백업은 백업이 아니라 희망 사항일 뿐입니다. 실제 상황이 닥치기 전에 일회용 VPS에서 복원 과정을 연습하여 정상 작동 여부를 확인하십시오.
업그레이드: 태그 고정, 릴리스 노트 확인, MongoDB 매트릭스 준수
업그레이드를 지루하게 만드는 두 가지 규칙이 있습니다. 첫째, Rocket.Chat은 한 번에 하나의 메이저 버전씩 업그레이드하십시오. Rocket.Chat은 부팅 시 스키마 마이그레이션을 실행하며 메이저 버전을 건너뛰는 것을 의도적으로 차단합니다. 6.x에서 8.x로 바로 넘어가려 하면 데이터 손상 대신 마이그레이션 오류와 함께 중단됩니다. 이미지 태그를 다음 메이저 버전의 최신 릴리스로 변경하고, 해당 릴리스 노트에서 호환성이 깨지는 변경 사항을 확인한 뒤 docker compose up -d를 실행하십시오. 로그에서 마이그레이션이 완료될 때까지 기다린 후 다음 단계로 넘어가십시오. 둘째, MongoDB 지원 매트릭스를 준수하십시오. 각 Rocket.Chat 릴리스는 특정 버전의 MongoDB를 지원하며, curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions에서 지원 버전을 확인할 수 있습니다. MongoDB를 업그레이드할 때(예: 7.0에서 8.0)는 한 번에 하나의 메이저 버전씩 진행하고, 각 단계마다 기능 호환성 버전(feature-compatibility version)을 설정하십시오. MongoDB 8.0에서 해당 명령을 실행하려면 명시적인 confirm: true이 필요합니다. 그렇지 않으면 확인 플래그를 포함하여 다시 실행하라는 메시지와 함께 거부됩니다.
sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'두 구성 요소 중 어느 것을 업그레이드하든 사전에 mongodump를 수행하십시오. 이것이 유일한 보험 정책입니다.
실패 유형 및 정확한 문자열
Rocket.Chat이 docker compose up 직후 재시작 루프에 빠지고 docker compose logs rocketchat가 MongoServerSelectionError로 가득 찹니다. MongoDB는 실행 중이지만 드라이버가 프라이머리 노드를 선택하지 못하는 상태이며, 정확한 문자열을 통해 어떤 실수를 했는지 알 수 있습니다. 토폴로지 유형이 ReplicaSetNoPrimary인 Server selection timed out after 30000 ms은 rs.initiate()을 실행하지 않아 복제 세트에 아직 구성이 없음을 의미합니다. getaddrinfo ENOTFOUND 뒤에 무작위 해시가 붙는다면 명시적인 host: "mongodb:27017" 없이 초기화했기 때문에 MongoDB가 해결할 수 없는 컨테이너 호스트 이름을 광고한 것입니다. sudo docker compose exec mongodb mongosh --eval 'rs.status()'로 진단하십시오. 만약 MongoServerError: no replset config has been received 오류가 발생하면 세트를 초기화하고, name이 무작위 해시인 멤버가 보인다면 서비스 이름을 사용하여 다시 초기화하십시오.
웹 UI는 로드되지만 로그인 화면이 무한 로딩되며 완료되지 않습니다. 브라우저 콘솔을 열면 WebSocket connection to 'wss://chat.example.com/websocket' failed가 보일 것입니다. 이는 거의 항상 ROOT_URL 불일치이거나 업그레이드 헤더를 전달하지 않는 프록시 때문입니다. ROOT_URL이 https://을 포함한 정확한 공용 주소와 일치하는지, 그리고 nginx location 블록이 proxy_http_version 1.1을 사용하여 Upgrade 및 Connection "upgrade"을 설정했는지 확인하십시오. 둘 중 하나라도 변경했다면 docker compose up -d를 다시 실행하십시오.
컨테이너가 계속 죽고 docker compose ps에 Restarting가 표시됩니다. docker compose logs가 중간에 끊기고 sudo dmesg | tail에 oom-killer로부터의 Out of memory: Killed process 12345 (mongod)이 표시된다면 종료 코드는 137입니다. 서버의 RAM이 부족한 상태입니다. 근본적인 해결책은 최소 4 GB 이상의 더 큰 VPS를 사용하는 것입니다. 임시방편으로 스왑을 추가하고 MongoDB의 command에서 --wiredTigerCacheSizeGB 1로 캐시를 제한할 수 있지만, 스왑은 실제 부하가 걸렸을 때 OOM 발생을 늦출 뿐입니다.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfiledocker compose up이 Error response from daemon: driver failed programming external connectivity ... bind: address already in use 오류와 함께 실패합니다. 이미 다른 프로세스가 3000번 포트를 점유하고 있습니다. 보통 정상적으로 종료되지 않은 이전 Rocket.Chat 컨테이너나 다른 애플리케이션이 원인입니다. sudo ss -ltnp | grep :3000로 해당 프로세스를 찾아 중지하거나 컨테이너를 정지하십시오. 또는 매핑의 호스트 측 포트를 127.0.0.1:3001:3000으로 변경하고 프록시의 proxy_pass 설정을 그에 맞춰 업데이트하십시오.
FAQ
Rocket.Chat은 정말로 MongoDB 레플리카 세트가 필요한가요?
네, 데이터베이스 노드가 하나뿐인 단일 서버 환경에서도 필요합니다. Rocket.Chat은 MongoDB의 change streams 기능을 사용하여 메시지를 실시간으로 전달하는데, 이 기능은 레플리카 세트에서만 지원되므로 독립형 mongod로는 사용할 수 없습니다. 여러 대의 서버가 필요한 것은 아니며, --replSet rs0으로 MongoDB 컨테이너를 시작한 뒤 rs.initiate()을 사용하여 단일 멤버로 구성된 세트를 초기화하면 됩니다. 이 단계를 건너뛰면 드라이버가 프라이머리 노드를 찾지 못해 Rocket.Chat이 MongoServerSelectionError: Server selection timed out 오류를 내며 재시작을 반복하고 부팅을 완료하지 못합니다.
자체 호스팅 Rocket.Chat에는 어느 정도의 RAM이 필요한가요?
실질적인 최소 사양으로 4 GB를, 활발하게 사용하는 팀이라면 8 GB를 권장합니다. Rocket.Chat의 Node 프로세스는 약 1에서 1.5 GB를 사용하며, MongoDB는 남은 RAM의 절반 정도를 WiredTiger 캐시로 점유합니다. 따라서 2 GB 환경에서는 두 프로세스가 충돌하여 실제 부하가 발생할 경우 OOM(Out-of-Memory) 킬러가 mongod를 강제 종료하게 되며, 로그에는 Killed과 함께 종료 코드 137이 기록됩니다. 2 GB는 테스트 사용자를 몇 명 두고 소프트웨어를 평가하는 용도로만 적합합니다.
Rocket.Chat을 HTTPS 뒤에 두려면 어떻게 해야 하나요?
동일한 VPS에서 리버스 프록시를 실행하여 TLS를 종료하고 127.0.0.1:3000로 전달하도록 설정하십시오. 또한 컨테이너의 ROOT_URL를 공인 https:// 주소로 설정해야 합니다. 프록시는 WebSocket 업그레이드 헤더를 반드시 전달해야 하며, 그렇지 않으면 로그인이 진행되지 않습니다. 단일 애플리케이션 환경이라면 nginx와 Certbot을 사용하는 것이 가장 간단하며, 여러 컨테이너를 하나의 프록시 뒤에서 운영하고 인증서 관리를 자동화하고 싶다면 Traefik이 더 깔끔합니다.
자체 호스팅 Rocket.Chat은 어떻게 백업하나요?
볼륨을 그대로 복사하는 대신 mongodump를 사용하여 일관된 데이터베이스 덤프를 생성하십시오: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. 해당 아카이브에는 사용자, 채널, 메시지, 설정 정보가 포함되며, 스토리지를 GridFS로 사용 중이라면 업로드된 파일도 포함됩니다. 이 파일을 서버 외부로 복사하고 cron을 통해 매일 자동화하십시오. 또한 복구 절차가 실제로 작동하는지 확인하기 위해 임시 서버에서 mongorestore을 연습해 보아야 합니다.
MongoDB를 손상시키지 않고 Rocket.Chat을 업그레이드하려면 어떻게 해야 하나요?
Rocket.Chat은 부팅 시 마이그레이션을 수행하며 메이저 버전을 건너뛰는 것을 허용하지 않으므로, 한 번에 하나의 메이저 버전씩 업그레이드하십시오. 고정된 이미지 태그를 변경하기 전에 각 릴리스 노트를 읽어야 합니다. curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions을 통해 대상 릴리스가 지원하는 MongoDB 버전을 확인하고, MongoDB를 업그레이드할 때도 한 번에 하나의 메이저 버전씩 이동하며 각 단계마다 confirm: true를 사용하여 setFeatureCompatibilityVersion을 설정하십시오. 항상 업그레이드 전에 mongodump을 수행하십시오.