> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/on-premises/ko/maintenance/horizontal-scaling.md).

# 수평 확장

버전 3.5.6부터 Server Pro는 수평 확장을 지원합니다.

이 문서는 기술 요구 사항을 나열하고, 하나 이상의 노드에서 Server Pro를 실행하기 위한 지침을 제공합니다.

{% hint style="danger" %}
Server CE/Server Pro부터 `5.0.3` 환경 변수의 브랜드명이 다음에서 변경되었습니다. `SHARELATEX_*` 에서 `OVERLEAF_*`.

만약 다음을 사용 중이라면 `4.x` 버전(또는 그 이전)이라면 변수 접두사가 그에 맞게 지정되었는지 확인해 주세요(예: `SHARELATEX_SITE_URL` 대신에 `OVERLEAF_SITE_URL`)
{% endhint %}

수평 확장을 설정하려면 상당한 노력이 필요합니다. 수평 확장을 고려할 것을 권장합니다. **오직** 일정 규모에 도달했을 때. 예를 들어, 총 사용자 1,000명의 Server Pro 설치는 4코어 프로세서 2개와 시스템 메모리 32GB를 갖춘 단일 서버를 사용해 성공적으로 구축되었습니다. 자세한 권장 사항은 [하드웨어 요구 사항](/on-premises/ko/getting-started/requirements/hardware-requirements.md) 문서를 참조하세요.

수평 확장을 사용하는 Server Pro 배포에는 로드 밸런서와 S3 호환 스토리지 백엔드 같은 외부 구성 요소 집합이 포함됩니다.

이 문서를 기반으로 구성 오류로 인해 발생했을 수 있는 Server Pro 컨테이너의 오류를 문제 해결하는 데 도움을 드릴 수 있으며 일반적인 조언을 제공할 수 있습니다. 안타깝게도 타사 애플리케이션/시스템 구성에 대한 지원은 제공할 수 없습니다.

외부 구성 요소를 제공하기 위해 하드웨어/소프트웨어에 특화된 기술 문제를 해결하는 것은 당사의 지원 약관에 포함되지 않습니다.

### 요구 사항

#### 외부 중앙 데이터 저장소

Server Pro의 데이터 저장소는 네 가지 데이터 저장소로 나눌 수 있습니다:

* **MongoDB**

  * 대부분의 데이터는 MongoDB에 지속 저장됩니다.
  * 우리는 로컬 인스턴스 또는 다음과 같은 외부 인스턴스 중 하나를 지원합니다. [MongoDB](https://www.mongodb.com/atlas) Atlas(AWS 인프라에서 실행되는 완전 관리형 MongoDB 서비스).<br>

  **참고:** 안타깝게도 현재 CosmoDB/DocumentDB와 같은 MongoDB 호환 데이터베이스에 대한 공식 지원은 없습니다. 이들로 Server Pro를 테스트하지 않았기 때문입니다. 호환 데이터베이스로 Server Pro를 배포하는 것은 **가능할 수** 있지만, 공식적으로는 MongoDB를 사용하는 배포만 지원합니다.<br>
* **Redis**

  * Redis는 MongoDB에 기록되기 전의 대기 중인 문서 업데이트와 같은 임시 데이터를 저장합니다.
  * Redis는 서로 다른 서비스 간에 문서 업데이트를 전달하고, 특정 프로젝트의 상태 변경을 편집기에 알리는 데 사용됩니다.
  * Redis는 사용자 세션을 저장하는 데 사용됩니다.
  * 우리는 로컬 인스턴스 또는 외부 인스턴스 중 하나를 지원합니다.<br>

  **참고:** 안타깝게도 현재 KeyDB/Valkey와 같은 Redis 호환 키/값 저장소에 대한 공식 지원은 없습니다. 이들로 Server Pro를 테스트하지 않았기 때문입니다. 호환 저장소로 Server Pro를 배포하는 것은 **가능할 수** 가능할 수<br>
* **프로젝트 파일 및 히스토리 파일**

  * 편집할 수 없는 프로젝트 파일은 MongoDB 외부에 저장됩니다.

    새로운 프로젝트 히스토리 시스템(Server Pro 3.5 이후)도 히스토리를 MongoDB 외부에 저장합니다.
  * 소규모 단일 인스턴스의 경우 로컬 파일 시스템(로컬 SSD, NFS 또는 EBS로 백업될 수 있음) 또는 [S3 호환 데이터 저장 시스템](/on-premises/ko/configuration/overleaf-toolkit/s3.md).
  * 에 대하여 수평 확장을 위해서는 **오직** S3 호환 데이터 저장 시스템을 지원합니다.<br>

  **중요:** NFS/Amazon EFS/Amazon EBS는 **아니** 수평 확장을 위해 지원됩니다. 자세한 내용은 [하드웨어 스토리지](/on-premises/ko/getting-started/requirements/hardware-requirements.md#storage) Server Pro에서 스토리지 확장에 대한 요구 사항 섹션을 참조하세요.
* **임시 파일**
  * LaTeX 컴파일은 최적의 성능을 위해 빠른 로컬 디스크에서 실행되어야 합니다. 컴파일 결과는 지속 저장하거나 백업할 필요가 없습니다.
  * 새 파일 업로드의 버퍼링과 프로젝트 zip 파일 생성도 로컬 디스크를 사용하는 것이 유리합니다.

{% hint style="danger" %}
로컬 디스크 사용을 강력히 권장합니다. NFS나 EBS와 같은 네트워크 디스크를 사용하면 예상치 못한 컴파일 오류 및 기타 성능 문제가 발생할 수 있습니다.
{% endhint %}

#### **Git-bridge**

{% hint style="info" %}
Git-bridge는 버전 4.0.1부터 Server Pro에서 사용할 수 있습니다.
{% endhint %}

git 저장소는 디스크에 로컬로 저장됩니다. 복제 옵션은 제공되지 않습니다. Git-bridge는 **단일 인스턴스**로 실행되어야 합니다. 최적의 성능을 위해 git-bridge 데이터에는 로컬 디스크를 사용하는 것을 권장합니다. git-bridge 데이터 디스크는 정기적으로 백업해야 합니다.

수평 확장을 위한 데이터 저장소에는 다음이 필요합니다:

* 모든 Server Pro 인스턴스에서 접근 가능한 중앙 MongoDB 인스턴스
* 모든 Server Pro 인스턴스에서 접근 가능한 중앙 Redis 인스턴스
* 프로젝트 및 히스토리 파일을 위한 중앙 S3 호환 스토리지 백엔드
* 각 인스턴스의 임시 파일용 로컬 디스크
* git-bridge 데이터를 위한 git-bridge 컨테이너를 호스팅하는 인스턴스의 로컬 디스크

#### 로드 밸런서 요구 사항

* **고정 라우팅**, 예를 들어 쿠키 사용

  이 요구 사항은 다음 구성 요소에서 비롯됩니다:

  * Server Pro의 실시간 편집 기능은 XHR 폴링을 대체 수단으로 사용하는 WebSocket을 사용합니다. 각 편집 세션은 서버 측에 로컬 상태를 가지며, 특정 편집 세션의 요청은 항상 동일한 Server Pro 인스턴스로 라우팅되어야 합니다. 협업 기능은 Redis를 사용합니다 [Pub/Sub](https://redis.io/docs/latest/develop/interact/pubsub/) 를 사용해 여러 Server Pro 인스턴스 간에 업데이트를 공유합니다.
  * LaTeX 컴파일은 성능 향상을 위해 출력과 컴파일 캐시를 로컬에 유지합니다. 한 Server Pro 인스턴스에 컴파일 요청을 보내면, 이후의 PDF/로그 다운로드 요청은 동일한 Server Pro 인스턴스로 라우팅되어야 합니다.
* **긴 요청 타임아웃** 큰 LaTeX 문서의 컴파일을 지원하기 위해
* **WebSocket 지원** 최적의 성능을 위해
* **50MB의 POST 페이로드 크기**
* **유지 연결 타임아웃** 은 Server Pro 유지 연결 타임아웃보다 낮아야 합니다.

  Server Pro의 유지 연결 타임아웃은 환경 변수 `NGINX_KEEPALIVE_TIMEOUT`. 기본값은 65초입니다.

  기본값에서는 로드 밸런서의 60초 유지 연결 타임아웃이 동작합니다.

  다음과 같이 `NGINX_KEEPALIVE_TIMEOUT=120`을 사용하면 로드 밸런서는 115초를 선택할 수 있습니다.
* **클라이언트 IP**

  요청 헤더를 설정하세요 `X-Forwarded-For` 를 클라이언트 IP로.
* 다음일 때 **SSL 종료**

  로드 밸런서는 요청 헤더 `X-Forwarded-Proto: https`.

<details>

<summary>HAProxy 구성 예시</summary>

```
global
  group haproxy
  user haproxy

  # 자세한 로그 기록
  log stdout format raw local0 debug

defaults
  mode                    http
  option                  httpchk HEAD /status
  http-check              expect status 200
  default-server          check

  # 자세한 로그 기록
  log                     global
  option                  httplog

  # 고정된 백엔드가 다운된 경우 다른 백엔드로 재라우팅
  option                  redispatch 1
  # 이 재시도는 HTTP 상태 500 응답이 아니라 TCP 연결 오류에 대한 것입니다
  retries                 3

  # 24시간 비활동 후 고정 세션 -- 컴파일 출력은 24시간 후 삭제됩니다
  cookie                  server-pro-ha insert maxidle 24h

  # 1분 동안 어떤 백엔드든 연결을 시도한 다음 503을 반환
  timeout queue           1m
  # Server Pro 인스턴스에 15초의 시작 시간을 부여
  timeout connect         15s

  # 매우 느린 클라이언트의 요청을 중단합니다(요청을 읽는 동안 1분의 비활성 허용)
  timeout client          1m

  # 느린 컴파일을 허용 -- clsi의 하드코딩된 제한은 10분입니다
  timeout server          10m

  # 23시간 후 편집기를 연결 해제 -- 어제 마지막 사용 시점보다 1시간 앞
  timeout tunnel          23h

  # 참고: haproxy의 keepalive 동작은 Server Pro의 기본 keepalive 설정과 잘 작동합니다.
  #       Haproxy가 백그라운드에서 연결을 정리하고 필요할 때 요청을 재라우팅합니다.

listen server-pro-ha-http
  bind :80
  http-request redirect scheme https unless { ssl_fc }

listen server-pro-ha-https
  bind :443 ssl crt /etc/ssl/certs/ssl-key-and-certificate-bundle.pem

  # 애플리케이션에 우리가 https 뒤에 있음을 알립니다
  http-request set-header X-Forwarded-Proto https

  # 애플리케이션에 실제 클라이언트 ip를 알립니다
  option forwardfor

  # https://hstspreload.org/#deployment-recommendations 참조
  http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload;"

  # git 트래픽을 git-bridge의 형제 컨테이너로 라우팅
  use-server server-pro-ha-1 if { path_beg /git/ }

  # 디버깅
  http-response add-header X-Served-By %s
  stats enable
  stats uri /haproxy

  server server-pro-ha-1 198.18.1.1:80 cookie server-pro-ha-1
  server server-pro-ha-2 198.18.1.2:80 cookie server-pro-ha-2
  server server-pro-ha-3 198.18.1.3:80 cookie server-pro-ha-3
```

</details>

#### Server Pro 구성

**비밀 값**

Server Pro 인스턴스들은 공유 비밀 값에 대해 일치해야 합니다:

* `WEB_API_PASSWORD` (웹 API 인증)
* `STAGING_PASSWORD` 그리고 `V1_HISTORY_PASSWORD` 동일한 값(히스토리 인증)
* `CRYPTO_RANDOM` (세션 쿠키용)
* `OT_JWT_AUTH_KEY` (히스토리 인증)

이 모든 비밀 값은 각각 고유한 값으로 구성되어야 하며 인스턴스 간에 공유되어야 합니다.

구성되지 않은 상태에서 사용자 요청이 다른 Server Pro 인스턴스로 라우팅되면, 요청이 인증 검사를 통과하지 못해 로그인 페이지로 자주 리다이렉트되거나 UI에서의 작업이 예상치 못한 방식으로 실패할 수 있습니다.

구성되지 않은 경우 Server Pro는 다음의 32바이트 무작위 값에 기반하여 각 비밀 값에 대해 새로운 무작위 값을 사용합니다. `/dev/urandom` (256비트 난수).

{% code overflow="wrap" %}

```bash
# https://github.com/overleaf/overleaf/blob/45ca0f796c679103efd305ddbef28073c4a5de32/server-ce/init_scripts/00_regen_sharelatex_secrets.sh#L14
dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 -w 0 | rev | cut -b 2- | rev | tr -d '\n+/'
```

{% endcode %}

**MongoDB**

지정 `OVERLEAF_MONGO_URL` (`SHARELATEX_MONGO_URL` 버전 `4.x` 및 그 이전)에서 중앙 MongoDB 인스턴스를 가리킵니다.

**Redis**

지정 `OVERLEAF_REDIS_HOST` (`SHARELATEX_REDIS_HOST` 버전 `4.x` 및 그 이전) 그리고 `REDIS_HOST` 를 중앙 Redis 인스턴스로 가리킵니다.

**프로젝트 및 히스토리 파일용 S3 호환 스토리지**

다음에 대한 문서를 참조하세요. [S3 호환 스토리지](/on-premises/ko/configuration/overleaf-toolkit/s3.md) 자세한 내용은

**임시 파일**

로의 로컬 SSD 기본 바인드 마운트는 `/var/lib/overleaf` (`/var/lib/sharelatex` 버전 `4.x` 및 그 이전)면 충분합니다. 반드시 다음을 가리키도록 하세요. `SANDBOXED_COMPILES_HOST_DIR` 를 호스트의 마운트 지점으로.

{% hint style="danger" %}
로컬 디스크 사용을 강력히 권장합니다. NFS나 EBS와 같은 네트워크 디스크를 사용하면 예상치 못한 컴파일 오류 및 기타 성능 문제가 발생할 수 있습니다.
{% endhint %}

**프록시 구성**

* 설정하세요 `OVERLEAF_BEHIND_PROXY=true` (`SHARELATEX_BEHIND_PROXY` 버전 `4.x` 및 그 이전) 정확한 클라이언트 IP를 위해.
* 설정하세요 `TRUSTED_PROXY_IPS` 을 로드 밸런서의 IP로 설정합니다(여러 CIDR을 쉼표로 구분하여 지정할 수 있습니다).

**Git-bridge 통합**

{% hint style="info" %}
Git-bridge는 버전 4.0.1부터 Server Pro에서 사용할 수 있습니다.
{% endhint %}

git-bridge 컨테이너는 들어오는 git 요청을 처리하기 위해 Server Pro 형제 컨테이너가 필요합니다. 이 형제 컨테이너는 일반 사용자 트래픽도 처리할 수 있습니다. 샘플 구성에서는 첫 번째 인스턴스가 git-bridge의 형제 컨테이너로 동작하지만, 실제로는 어떤 인스턴스든 그 역할을 할 수 있습니다.

왜 하나의 Server Pro 컨테이너를 git-bridge의 형제로 지정해야 할까요? Server Pro는 히스토리 서비스용 다운로드 URL을 git-bridge에 제공합니다. 이 히스토리 URL이 git-bridge 컨테이너에서 접근 가능하도록 구성해야 합니다.

Server Pro 컨테이너 구성:

* 설정하세요 `GIT_BRIDGE_ENABLED` 에서 `'true'`
* 설정하세요 `GIT_BRIDGE_HOST` 에서 `<git-bridge 컨테이너 이름>` 예: `git-bridge`
* 설정하세요 `GIT_BRIDGE_PORT` 에서 `8000`
* 설정하세요 `V1_HISTORY_URL` 에서 `http://<server-pro 형제 컨테이너 이름>:3100/api`.

  참고: 이는 git-bridge 컨테이너를 위한 형제 컨테이너에서만 필요합니다. 다른 인스턴스는 기본값인 localhost URL을 사용할 수 있습니다.

git-bridge 컨테이너 구성:

* 설정하세요 `GIT_BRIDGE_API_BASE_URL` 에서 `http://<server-pro 형제 컨테이너 이름>/api/v0`, 예: `http://server-pro-ha-1/api/v0`
* 설정하세요 `GIT_BRIDGE_OAUTH2_SERVER` 에서 `http://<server-pro 형제 컨테이너 이름>`, 예: `http://server-pro-ha-1`
* 설정하세요 `GIT_BRIDGE_POSTBACK_BASE_URL` 에서 `http://<git-bridge 컨테이너 이름>:8000`, 예: `http://git-bridge:8000`
* 설정하세요 `GIT_BRIDGE_ROOT_DIR` bind-mount된 git-bridge 데이터 디스크를 가리키도록, 예: `/data/git-bridge`

<details>

<summary>docker-compose.yml 구성 예시</summary>

다음 구성은 독립형 설정을 보여줍니다. 데모가 작동하려면 유효한 SSL 키/인증서를 제공하고 `OVERLEAF_SITE_URL` (`SHARELATEX_SITE_URL` 버전 `4.x` 및 그 이전). 실제 설정의 경우, 주석에 적힌 대로 더미 비밀 값을 실제 비밀 값으로 바꿔야 합니다. 실제 설정에서는 개별 컨테이너를 전용 노드로 옮기고 IP 주소를 로컬 네트워크 설정에 맞게 조정해야 합니다.

```yaml
version: '2.2'

# 실제 수평 확장 설정: 원하는 네트워크를 선택하고 구성의 IP를 바꾸세요.
networks:
    default:
        ipam:
            config:
                # 이 서브넷은 벤치마킹에 사용되는 예약된 서브넷의 일부입니다
                # https://tools.ietf.org/html/rfc2544
                # 전체 서브넷은 198.18.0.0/15입니다
                # lb와 db에 198.18.0.0/24 사용
                # server-pro에 198.18.1.0/24 사용
                # 임시 컨테이너에 198.18.0.128/25 사용
                - gateway: 198.18.0.1
                  ip_range: 198.18.0.128/25
                  subnet: 198.18.0.0/23

services:
    # 실제 수평 확장 설정: haproxy를 별도의 호스트에서 Docker 밖에서 실행하세요.
    lb:
        image: haproxy:2.6
        container_name: lb
        user: root
        logging:
            driver: local
            options:
                max-size: 10g
                max-file: '100'
        volumes:
            - ./haproxy.conf:/usr/local/etc/haproxy/haproxy.cfg
            # $ cat certificate.pem key.pem > ssl-key-and-certificate-bundle.pem
            - /path/to/ssl-key-and-certificate-bundle.pem:/etc/ssl/certs/ssl-key-and-certificate-bundle.pem
        # "ports"의 대안: docker-proxy 오버헤드를 피하기 위해 호스트 네트워크를 사용
        network_mode: host

        # "network_mode: host"의 대안: 네트워크 격리를 위해 docker-proxy 사용
        # ports:
        #     - "80:80"
        #     - "443:443"
        # networks:
        #     default:
        #         ipv4_address: 198.18.0.2

        # 실제 수평 확장 설정: 다른 호스트에서 실행되므로 이 항목들을 제거하세요.
        depends_on:
            server-pro-ha-1:
                condition: service_started
            server-pro-ha-2:
                condition: service_started
            server-pro-ha-3:
                condition: service_started

    # 실제 수평 확장 설정: server-pro-ha-1 옆에서 이 컨테이너를 실행하세요.
    # Server Pro 4.0부터.
    git-bridge:
        restart: always
        # 태그는 `server-pro-ha-1` 컨테이너 태그와 일치해야 합니다.
        image: quay.io/sharelatex/git-bridge:4.0.1
        volumes:
            # 실제 수평 확장 설정: /data/git-bridge를 전용 로컬 SSD로 지정하세요.
            - ~/git_bridge_data:/data/git-bridge
        container_name: git-bridge
        environment:
            GIT_BRIDGE_API_BASE_URL: "http://server-pro-ha-1/api/v0"
            GIT_BRIDGE_OAUTH2_SERVER: "http://server-pro-ha-1"
            GIT_BRIDGE_POSTBACK_BASE_URL: "http://198.18.0.6:8000"
            GIT_BRIDGE_ROOT_DIR: "/data/git-bridge"
        user: root
        command: ["/server-pro-start.sh"]

        # 실제 수평 확장 설정: 호스트 198.18.0.6에서 실행하고 포트를 노출하세요
        # ports:
        #     - "8000:8000"
        networks:
            default:
                ipv4_address: 198.18.0.6

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    server-pro-ha-1: &server-pro-ha-config
        restart: always
        image: quay.io/sharelatex/sharelatex-pro:4.0.1
        container_name: server-pro-ha-1
        hostname: server-pro-ha-1
        depends_on:
            # 실제 수평 확장 설정: 이 항목은 유지하세요.
            git-bridge:
                condition: service_started

            # 실제 수평 확장 설정: 아래의 항목들은 다른 호스트에서 실행되므로 제거하세요.
            mongo:
                condition: service_healthy
            redis:
                condition: service_started
            minio:
                condition: service_started
            mongo_replica_set_setup:
                condition: service_completed_successfully
            minio_setup:
                condition: service_completed_successfully
        stop_grace_period: 60s
        volumes:
            - /tmp/scratch-disk1:/var/lib/sharelatex
            - /var/run/docker.sock:/var/run/docker.sock
        environment: &server-pro-ha-environment
            # 실제 수평 확장 설정: 도메인/앱 이름을 직접 제공하세요.
            OVERLEAF_SITE_URL: 'https://overleaf.example.com'
            OVERLEAF_APP_NAME: Server Pro Horizontal Scaling Demo

            OVERLEAF_MONGO_URL: mongodb://198.18.0.3/sharelatex
            OVERLEAF_REDIS_HOST: 198.18.0.4
            REDIS_HOST: 198.18.0.4

            ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file'
            EMAIL_CONFIRMATION_DISABLED: 'true'

            SANDBOXED_COMPILES: 'true'
            SANDBOXED_COMPILES_SIBLING_CONTAINERS: 'true'
            SANDBOXED_COMPILES_HOST_DIR: '/tmp/scratch-disk1/data/compiles'

            # S3
            # 실제 수평 확장 설정: 보안이 확보된 자격 증명을 선택하세요.
            OVERLEAF_FILESTORE_BACKEND: s3
            OVERLEAF_FILESTORE_USER_FILES_BUCKET_NAME: overleaf-user-files
            OVERLEAF_FILESTORE_TEMPLATE_FILES_BUCKET_NAME: overleaf-template-files
            OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID: OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID
            OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY: OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY
            OVERLEAF_FILESTORE_S3_ENDPOINT: http://198.18.0.5:9000
            OVERLEAF_FILESTORE_S3_PATH_STYLE: 'true'
            OVERLEAF_FILESTORE_S3_REGION: ''

            OVERLEAF_HISTORY_BACKEND: "s3"
            OVERLEAF_HISTORY_PROJECT_BLOBS_BUCKET: "overleaf-project-blobs"
            OVERLEAF_HISTORY_CHUNKS_BUCKET: "overleaf-chunks"
            OVERLEAF_HISTORY_S3_ACCESS_KEY_ID: "OVERLEAF_HISTORY_S3_ACCESS_KEY_ID"
            OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY: "OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY"
            OVERLEAF_HISTORY_S3_ENDPOINT: http://198.18.0.5:9000
            OVERLEAF_HISTORY_S3_PATH_STYLE: 'true'
            OVERLEAF_HISTORY_S3_REGION: ''
            # /S3

            # git-bridge
            GIT_BRIDGE_ENABLED: 'true'
            GIT_BRIDGE_HOST: 198.18.0.6
            GIT_BRIDGE_PORT: 8000
            # git-bridge의 형제 인스턴스에서만 필요함
            V1_HISTORY_URL: "http://server-pro-ha-1:3100/api"
            # /git-bridge

            # 수평 확장
            # 실제 수평 확장 설정: 보안이 확보된 자격 증명을 선택하세요.
            WEB_API_PASSWORD: WEB_API_PASSWORD
            STAGING_PASSWORD: V1_HISTORY_PASSWORD
            V1_HISTORY_PASSWORD: V1_HISTORY_PASSWORD
            CRYPTO_RANDOM: CRYPTO_RANDOM
            OT_JWT_AUTH_KEY: OT_JWT_AUTH_KEY
            OVERLEAF_BEHIND_PROXY: 'true'
            # 실제 수평 확장 설정: 로드 밸런서의 IP
            TRUSTED_PROXY_IPS: 198.18.0.1,198.18.0.2
            # /수평 확장

        # 실제 수평 확장 설정: 호스트 198.18.1.1에서 실행하고 포트를 노출
        # ports:
        #     - "80:80"
        networks:
            default:
                ipv4_address: 198.18.1.1

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    server-pro-ha-2:
        <<: *server-pro-ha-config
        hostname: server-pro-ha-2
        container_name: server-pro-ha-2
        volumes:
            - /tmp/scratch-disk2:/var/lib/sharelatex
            - /var/run/docker.sock:/var/run/docker.sock
        environment:
            <<: *server-pro-ha-environment
            SANDBOXED_COMPILES_HOST_DIR: '/tmp/scratch-disk2/data/compiles'
            V1_HISTORY_URL: "http://localhost:3100/api"

        # 실제 수평 확장 설정: 호스트 198.18.1.2에서 실행하고 포트를 노출
        # ports:
        #     - "80:80"
        networks:
            default:
                ipv4_address: 198.18.1.2

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    server-pro-ha-3:
        <<: *server-pro-ha-config
        hostname: server-pro-ha-3
        container_name: server-pro-ha-3
        volumes:
            - /tmp/scratch-disk3:/var/lib/sharelatex
            - /var/run/docker.sock:/var/run/docker.sock
        environment:
            <<: *server-pro-ha-environment
            SANDBOXED_COMPILES_HOST_DIR: '/tmp/scratch-disk3/data/compiles'
            V1_HISTORY_URL: "http://localhost:3100/api"

        # 실제 수평 확장 설정: 호스트 198.18.1.3에서 실행하고 포트를 노출
        # ports:
        #     - "80:80"
        networks:
            default:
                ipv4_address: 198.18.1.3

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    minio:
        image: minio/minio:RELEASE.2023-05-18T00-05-36Z
        container_name: minio
        command: server /data
        volumes:
            # 실제 수평 확장 설정: 여러 디스크로 minio를 실행하려면 minio 문서를 참조하세요.
            - ~/minio_data:/data
        environment:
            # 실제 수평 확장 설정: 보안이 확보된 자격 증명을 선택하세요.
            MINIO_ROOT_USER: MINIO_ROOT_USER
            MINIO_ROOT_PASSWORD: MINIO_ROOT_PASSWORD

        # 실제 수평 확장 설정: 호스트 198.18.0.5에서 실행하고 포트를 노출
        # ports:
        #     - "9000:9000"
        networks:
            default:
                ipv4_address: 198.18.0.5

    # 실제 수평 확장 설정: 이 설정은 별도의 호스트에서 한 번만 실행하세요.
    minio_setup:
        depends_on:
            - minio
        image: minio/mc:RELEASE.2023-05-18T16-59-00Z
        entrypoint: sh
        명령:
            - '-c'
            # 실제 수평 확장 설정: 보안이 확보된 자격 증명을 선택하세요.
            - |
                mc alias set s3 http://198.18.0.5:9000 MINIO_ROOT_USER MINIO_ROOT_PASSWORD \
                || sleep 10 && \
                mc alias set s3 http://198.18.0.5:9000 MINIO_ROOT_USER MINIO_ROOT_PASSWORD \
                || sleep 10 && \
                mc alias set s3 http://198.18.0.5:9000 MINIO_ROOT_USER MINIO_ROOT_PASSWORD \
                || sleep 10 && \
                mc alias set s3 http://198.18.0.5:9000 MINIO_ROOT_USER MINIO_ROOT_PASSWORD

                mc mb --ignore-existing s3/overleaf-user-files
                mc mb --ignore-existing s3/overleaf-template-files
                mc admin user add s3 \\
                  OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID \\
                  OVERLEAF_FILESTORE_S3_SECRET_ACCESS_KEY

                mc mb --ignore-existing s3/overleaf-project-blobs
                mc mb --ignore-existing s3/overleaf-chunks
                mc admin user add s3 \\
                  OVERLEAF_HISTORY_S3_ACCESS_KEY_ID \\
                  OVERLEAF_HISTORY_S3_SECRET_ACCESS_KEY

                echo '
                  {
                    "Version": "2012-10-17",
                    "Statement": [
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:ListBucket"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-user-files"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:PutObject",
                          "s3:GetObject",
                          "s3:DeleteObject"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-user-files/*"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:ListBucket"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-template-files"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:PutObject",
                          "s3:GetObject",
                          "s3:DeleteObject"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-template-files/*"
                      }
                    ]
                  }' > policy-filestore.json

                echo '
                  {
                    "Version": "2012-10-17",
                    "Statement": [
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:ListBucket"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-project-blobs"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:PutObject",
                          "s3:GetObject",
                          "s3:DeleteObject"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-project-blobs/*"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:ListBucket"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-chunks"
                      },
                      {
                        "Effect": "Allow",
                        "Action": [
                          "s3:PutObject",
                          "s3:GetObject",
                          "s3:DeleteObject"
                        ],
                        "Resource": "arn:aws:s3:::overleaf-chunks/*"
                      }
                    ]
                  }' > policy-history.json

                # 이전 섹션의 정책 내용을 policy-filestore.json에 넣으세요
                # 알림: 버킷 이름을 그에 맞게 바꾸세요.
                mc admin policy create s3 overleaf-filestore policy-filestore.json
                mc admin policy attach s3 overleaf-filestore \\
                  --user=OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID || true

                mc admin policy create s3 overleaf-history policy-history.json
                mc admin policy attach s3 overleaf-history \\
                  --user=OVERLEAF_HISTORY_S3_ACCESS_KEY_ID || true

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    mongo:
        restart: always
        image: mongo:4.4
        container_name: mongo
        command: "--replSet overleaf"
        expose:
            - 27017
        volumes:
            - ~/mongo_data:/data/db
        healthcheck:
            test: echo 'db.stats().ok' | mongo localhost:27017/test --quiet
            interval: 10s
            timeout: 10s
            retries: 5

        # 실제 수평 확장 설정: 호스트 198.18.0.3에서 실행하고 포트를 노출
        # ports:
        #     - "27017:27017"
        networks:
            default:
                ipv4_address: 198.18.0.3

    mongo_replica_set_setup:
        image: mongo:4.4
        entrypoint: sh
        depends_on:
            mongo:
                condition: service_healthy
        명령:
            - '-c'
            - |
                mongo 198.18.0.3 --eval "rs.initiate({ _id: \"overleaf\", members: [ { _id: 0, host: \"198.18.0.3:27017\" } ] })"

    # 실제 수평 확장 설정: 이 컨테이너를 별도의 호스트에서 실행하세요.
    redis:
        restart: always
        image: redis:6.2
        container_name: redis
        expose:
            - 6379
        volumes:
            - ~/redis_data:/data

        # 실제 수평 확장 설정: 호스트 198.18.0.4에서 실행하고 포트를 노출
        # ports:
        #     - "6379:6379"
        networks:
            default:
                ipv4_address: 198.18.0.4
```

</details>

#### 하드웨어

수평 확장에 참여하는 모든 Server Pro 인스턴스에 동일한 하드웨어 사양을 사용하는 것을 권장합니다.

에 대한 일반 권장 사항은 [하드웨어 사양](/on-premises/ko/getting-started/requirements/hardware-requirements.md) 이 Server Pro 인스턴스에 적용됩니다.

#### Server Pro 업그레이드

업그레이드 과정의 일부로, Server Pro는 자동으로 데이터베이스 마이그레이션을 실행합니다. 이 마이그레이션은 **아니** 여러 인스턴스에서 병렬로 실행되도록 설계되었습니다.

실제 웹 애플리케이션이 시작되기 전에 마이그레이션이 완료되어야 합니다. 로그에서 다음 항목이 있는지 확인하거나 `마이그레이션 완료` 를 찾거나 애플리케이션이 트래픽을 수락할 때까지 기다릴 수 있습니다.

업그레이드 절차는 다음과 같습니다:

1. 점검 시간을 예약합니다
2. Server Pro의 모든 인스턴스를 중지합니다
3. 다음에 설명된 대로 일관된 백업을 수행합니다 [문서](/on-premises/ko/maintenance/data-and-backups.md#performing-a-consistent-backup)
4. 새 버전으로 Server Pro의 단일 인스턴스를 시작합니다
5. 새 인스턴스가 예상대로 작동하는지 검증합니다
6. 새 버전으로 다른 인스턴스들을 시작합니다


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/on-premises/ko/maintenance/horizontal-scaling.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
