# Как настроить репликацию БД Swarmica?
# Симптомы

Можно ли настроить репликацию базы Swarmica для аналитики или резервного копирования?

# Решение

Да, Swarmica использует Postgres в качестве СУБД, который поддерживает репликацию.

Чтобы  включить репликацию, необходимо выполнить  шаги на основном сервере и на реплике, описанные ниже.

### Настройка основного сервера Swarmica

1\. Создайте файл `/root/swarmica/pg_hba.conf` со следующим содержимым (замените REPLICA\_IP на IP адрес сервера реплики):

```txt
local   all             all                                     trust
host    all             all             127.0.0.1/32            trust
host    all             all             ::1/128                 trust
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust
host    replication     all             REPLICA_IP/32           scram-sha-256
host all all all scram-sha-256
```

2\. Отредактируйте` /root/swarmica/docker-compose.yml`, добавив монтирование `pg_hba.conf `в раздел `volumes` и передав необходимые настройки сервера postgres через команды `-c`:

```yaml
postgres:
  image: postgres:14.2-bullseye
  container_name: swarmica-postgres
  shm_size: 8gb
  command: postgres -N 300 -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c wal_keep_size=512MB -c work_mem=8MB -c temp_buffers=16MB -c shared_buffers=8GB -c track_activity_query_size=16384 -c max_wal_size=4GB -c checkpoint_timeout=10min
  restart: always
  volumes:
    - swarmica_postgres_data:/var/lib/postgresql/data:Z
    - swarmica_postgres_data_backups:/backups:z
    - ./pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf
  env_file:
    - .env
  ports:
    - "54321:5432"
```

:::danger
**ВНИМАНИЕ!** Для репликации на другом сервере необходимо сделать порт 5432 контейнера postgres доступным на сервере. Это повышает уязвимость сервера к внешним атакам, поэтому рекомендуется принять все возможные меры защиты, такие как:

*   Изменение адреса порта (в примере выше - 54321)
*   Ограничение доступа к порту средствами файрвола на сервере
*   Ограничение доступа к порту средствами внешнего файрвола / NATа / WAF / NGFW
:::

3\. Перезагрузите сервисы:

```bash
cd /root/swarmica
docker compose down
docker compose up -d
```

4\. Разрешите репликацию для учетной записи, которую будете использовать на реплике:

```txt
docker exec -it swarmica-postgres psql -U ... ...
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'replicator_insecure_password';
SELECT pg_create_physical_replication_slot('replication_slot');
```

:::danger
**ВНИМАНИЕ!** Обязательно замените **replicator** и **replicator\_insecure\_password** на собственные, более защищенные имя пользователя и пароль
:::

### Настройка реплики

Здесь приводится пример настройки реплики внутри Docker контейнера на другом физическом/виртуальном сервере, вы можете применять аналогичные настройки в любом варианте установки Postgres.

1\. Установите `docker.io` и `docker-compose-v2` пакеты:

```bash
apt-get update
apt-get install docker.io docker-compose-v2
```

2\. Создайте папку для конфигурационных файлов:

```txt
mkdir replica
cd replica
```

3\. Создайте `.env `файл с параметрами подключения Postgres:

```txt
# Master host connection configuration
POSTGRES_MASTER_HOST=my-swarmica-host.tld
POSTGRES_MASTER_PORT=54321
POSTGRES_MASTER_DB=swarmica_app
POSTGRES_MASTER_USER=replicator
POSTGRES_MASTER_PASSWORD=replicator_insecure_password

# Replica host configuration
POSTGRES_HOST=postgres
POSTGRES_USER=replicator
POSTGRES_PASS=repplicator_insecure_password
POSTGRES_PORT=5432
```

4\. Создайте `docker-compose.yml `файл со следующим содержимым:

```yaml
volumes:
  postgres_data: {}

services:
  postgres:
    image: postgres:14.2-bullseye
    restart: always
    container_name: swarmica-postgres
    shm_size: 1gb
    environment:
      PGPASSWORD: $POSTGRES_MASTER_PASSWORD
    command: |
      gosu postgres bash -c "
      if [ ! -s /var/lib/postgresql/data/postgresql.conf ]; then
        pg_basebackup -h $POSTGRES_MASTER_HOST -p $POSTGRES_MASTER_PORT -U $POSTGRES_MASTER_USER -D /var/lib/postgresql/data -R -v --slot=replication_slot;
      fi
      chmod 700 /var/lib/postgresql/data/
      postgres -N 1024 -c hot_standby=on
      "
    volumes:
      - postgres_data:/var/lib/postgresql/data:Z
    env_file:
      - .env
```

5\. Скачайте образы и запустите сервис реплики:

```bash
docker compose pull
docker compose up -d
```

6\. После этого репликация дожна начаться автоматически:

```txt
root@pg-replica:~/replica# docker logs -f swarmica-postgres
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 20/22000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: write-ahead log end point: 20/22000B88
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: renaming backup_manifest.tmp to backup_manifest
pg_basebackup: base backup completed
2025-12-11 12:54:07.181 UTC [1] LOG:  starting PostgreSQL 14.2 (Debian 14.2-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
2025-12-11 12:54:07.181 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2025-12-11 12:54:07.181 UTC [1] LOG:  listening on IPv6 address "::", port 5432
2025-12-11 12:54:07.191 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2025-12-11 12:54:07.201 UTC [14] LOG:  database system was interrupted; last known up at 2025-12-11 12:53:56 UTC
2025-12-11 12:54:07.461 UTC [14] LOG:  entering standby mode
2025-12-11 12:54:07.468 UTC [14] LOG:  redo starts at 20/22000028
2025-12-11 12:54:07.471 UTC [14] LOG:  consistent recovery state reached at 20/22000B88
2025-12-11 12:54:07.472 UTC [1] LOG:  database system is ready to accept read-only connections
2025-12-11 12:54:07.798 UTC [18] LOG:  started streaming WAL from primary at 20/23000000 on timeline 1
```