commit a992112d954995d964cbd9860219d431d7a7ae58 Author: Первов Артем Date: Thu Apr 16 11:53:55 2026 +0300 Add initial setup for pgAdmin 4 with Docker and Nginx Proxy Manager - Created .env.example for environment variable configuration. - Added .gitignore to exclude sensitive files. - Introduced config_local.py for pgAdmin settings. - Added docker-compose.portainer.yml for service orchestration. - Created Dockerfile for custom image building. - Added README.md with setup instructions and usage guidelines. - Included servers.json as a template for PostgreSQL server connections. diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5a74133 --- /dev/null +++ b/.env.example @@ -0,0 +1,14 @@ +TZ=Europe/Moscow + +PGADMIN_DEFAULT_EMAIL=admin@example.com +PGADMIN_DEFAULT_PASSWORD=change-this-password +PGADMIN_PUBLISHED_PORT=5050 +PGADMIN_VOLUME_NAME=pgadmin_data + +PGADMIN_CONFIG_SERVER_MODE=True +PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=True +PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True +PGADMIN_CONFIG_UPGRADE_CHECK_ENABLED=False + +NPM_NETWORK=npm_proxy +PGADMIN_DOMAIN=pgadmin.example.com diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7396f50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +.env.local +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..415ad52 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM dpage/pgadmin4:latest + +COPY config_local.py /pgadmin4/config_local.py +COPY servers.json /pgadmin4/servers.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c0bc8b --- /dev/null +++ b/README.md @@ -0,0 +1,201 @@ +# pgAdmin 4 for Portainer + Nginx Proxy Manager + +Этот репозиторий подготовлен для развертывания `pgAdmin 4` как отдельного веб-сервиса: + +- через `Portainer` как stack; +- через `Nginx Proxy Manager` как reverse proxy; +- с постоянным хранением данных в Docker volume; +- с отдельным файлом `servers.json` для преднастройки подключений к PostgreSQL. + +## Что лежит в репозитории + +- `docker-compose.portainer.yml` - основной stack-файл для Portainer; +- `Dockerfile` - опциональный Dockerfile, если позже захочешь собирать свой образ; +- `.env.example` - шаблон переменных окружения; +- `config_local.py` - настройки pgAdmin для корректной работы за reverse proxy; +- `servers.json` - список преднастроенных серверов PostgreSQL; +- `.gitignore` - чтобы случайно не закоммитить секреты из `.env`. + +## 1. Подготовка + +Файл `.env.example` используй как шаблон значений. + +Есть два способа: + +- локально скопировать `.env.example` в `.env`; +- или ввести эти же значения вручную в переменные stack'а в `Portainer`. + +Минимально нужно поменять: + +- `PGADMIN_DEFAULT_EMAIL` +- `PGADMIN_DEFAULT_PASSWORD` +- `PGADMIN_DOMAIN` +- `NPM_NETWORK` + +Пример: + +```env +TZ=Europe/Moscow +PGADMIN_DEFAULT_EMAIL=admin@your-domain.com +PGADMIN_DEFAULT_PASSWORD=super-strong-password +PGADMIN_PUBLISHED_PORT=5050 +PGADMIN_VOLUME_NAME=pgadmin_data +PGADMIN_CONFIG_SERVER_MODE=True +PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=True +PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True +PGADMIN_CONFIG_UPGRADE_CHECK_ENABLED=False +NPM_NETWORK=npm_proxy +PGADMIN_DOMAIN=pgadmin.example.com +``` + +## 2. Подготовка сети для Nginx Proxy Manager + +Очень важно, чтобы контейнер с `pgAdmin` и контейнер `Nginx Proxy Manager` находились в одной Docker-сети. + +Этот вариант настройки предполагает, что `Portainer`, `pgAdmin` и `Nginx Proxy Manager` работают на одном Docker host. + +Если у тебя у NPM уже есть внешняя сеть, используй ее имя в `.env` через `NPM_NETWORK`. + +Если такой сети еще нет, создай ее на Docker host: + +```bash +docker network create npm_proxy +``` + +Если Nginx Proxy Manager уже работает, проверь имя его сети и подставь именно его. + +Также убедись, что сам контейнер `Nginx Proxy Manager` подключен к этой же внешней сети. + +## 3. Настройка списка БД в `servers.json` + +По умолчанию файл пустой: + +```json +{ + "Servers": {} +} +``` + +Если хочешь, чтобы после первого входа серверы уже были добавлены в интерфейс `pgAdmin`, заполни `servers.json`. + +Пример: + +```json +{ + "Servers": { + "1": { + "Name": "Production", + "Group": "Servers", + "Host": "postgres-prod", + "Port": 5432, + "MaintenanceDB": "postgres", + "Username": "postgres", + "SSLMode": "prefer" + }, + "2": { + "Name": "Staging", + "Group": "Servers", + "Host": "postgres-stage", + "Port": 5432, + "MaintenanceDB": "postgres", + "Username": "postgres", + "SSLMode": "prefer" + } + } +} +``` + +Важно: + +- `Host` должен быть доступен из контейнера `pgAdmin`; +- если PostgreSQL-контейнеры живут в Docker, они тоже должны быть в общей сети или быть доступны по IP/DNS; +- пароли подключений лучше не хранить в репозитории. + +## 4. Деплой через Portainer + +Есть два нормальных варианта. + +### Вариант A. Через Git-репозиторий + +1. Закоммить файлы этого репозитория в свой Git. +2. В `Portainer` открой `Stacks`. +3. Нажми `Add stack`. +4. Выбери `Repository`. +5. Укажи URL репозитория. +6. В поле compose file path укажи `docker-compose.portainer.yml`. +7. Добавь stack environment variables по значениям из `.env.example`. +8. Нажми `Deploy the stack`. + +### Вариант B. Через Web editor + +1. Открой `Stacks`. +2. Нажми `Add stack`. +3. Вставь содержимое `docker-compose.portainer.yml`. +4. Ниже заполни stack environment variables из `.env.example`. +5. Нажми `Deploy the stack`. + +## 5. Проверка после старта + +После развертывания проверь: + +- контейнер `pgadmin` в статусе `running`; +- healthcheck стал `healthy`; +- локально сервис открывается по `http://IP_СЕРВЕРА:5050`, если ты оставил `PGADMIN_PUBLISHED_PORT=5050`. + +Если страница не открывается: + +- посмотри логи контейнера в Portainer; +- проверь, что внешний volume создался; +- проверь, что сеть `NPM_NETWORK` существует; +- проверь, что пароль и email заданы. + +## 6. Настройка в Nginx Proxy Manager + +Когда контейнер уже поднят: + +Перед этим проверь, что DNS-запись домена из `PGADMIN_DOMAIN` указывает на сервер, где работает `Nginx Proxy Manager`. + +1. Открой `Nginx Proxy Manager`. +2. Перейди в `Proxy Hosts`. +3. Нажми `Add Proxy Host`. +4. В `Domain Names` укажи значение из `PGADMIN_DOMAIN`. +5. `Scheme`: `http`. +6. `Forward Hostname / IP`: `pgadmin`. +7. `Forward Port`: `80`. +8. Включи `Websockets Support`. +9. Во вкладке `SSL` выпусти `Let's Encrypt` сертификат. +10. Включи `Force SSL`. + +Если NPM не видит хост `pgadmin`, почти всегда проблема в том, что контейнеры не находятся в одной внешней Docker-сети. + +Если `Nginx Proxy Manager` у тебя находится на другом сервере, не используй `pgadmin` как upstream. В этом случае: + +- оставь опубликованный порт `PGADMIN_PUBLISHED_PORT`; +- в NPM укажи IP Docker host; +- `Forward Port` поставь равным `PGADMIN_PUBLISHED_PORT`. + +## 7. Первый вход в pgAdmin + +После настройки proxy: + +1. Открой `https://PGADMIN_DOMAIN`. +2. Войди под `PGADMIN_DEFAULT_EMAIL`. +3. Используй `PGADMIN_DEFAULT_PASSWORD`. +4. Если в `servers.json` были добавлены серверы, они появятся автоматически. +5. Если их нет, добавь подключения вручную через интерфейс. + +## 8. Как обновлять + +Если используешь `image: dpage/pgadmin4:latest`, обновление простое: + +1. В `Portainer` открой stack. +2. Нажми `Pull and redeploy`. + +Если позже захочешь перейти на собственную сборку, можно использовать `Dockerfile`, но для первого запуска через Portainer обычно стабильнее и проще использовать официальный образ, как в текущем `docker-compose.portainer.yml`. + +## 9. Полезные замечания + +- `pgAdmin` хранит пользовательские настройки и сохраненные серверы в volume `pgadmin_data`. +- Если удалить volume, настройки и сохраненные подключения будут потеряны. +- `servers.json` импортируется как исходная преднастройка, но дальше рабочее состояние живет уже в данных `pgAdmin`. +- Если меняешь `servers.json` после первого запуска, иногда проще удалить volume и развернуть заново, чем ждать повторного импорта. diff --git a/config_local.py b/config_local.py new file mode 100644 index 0000000..4b01e33 --- /dev/null +++ b/config_local.py @@ -0,0 +1,12 @@ +PROXY_X_FOR_COUNT = 1 +PROXY_X_PROTO_COUNT = 1 +PROXY_X_HOST_COUNT = 1 +PROXY_X_PORT_COUNT = 1 +PROXY_X_PREFIX_COUNT = 0 + +UPGRADE_CHECK_ENABLED = False +CHECK_SUPPORTED_BROWSER = False +ENHANCED_COOKIE_PROTECTION = True + +SESSION_EXPIRATION_TIME = 12 * 60 * 60 +MAX_SESSION_IDLE_TIME = 60 * 60 diff --git a/docker-compose.portainer.yml b/docker-compose.portainer.yml new file mode 100644 index 0000000..8a93223 --- /dev/null +++ b/docker-compose.portainer.yml @@ -0,0 +1,38 @@ +services: + pgadmin: + image: dpage/pgadmin4:latest + restart: unless-stopped + environment: + TZ: ${TZ:-UTC} + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} + PGADMIN_LISTEN_PORT: 80 + PGADMIN_CONFIG_SERVER_MODE: ${PGADMIN_CONFIG_SERVER_MODE:-True} + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: ${PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED:-True} + PGADMIN_CONFIG_UPGRADE_CHECK_ENABLED: ${PGADMIN_CONFIG_UPGRADE_CHECK_ENABLED:-False} + PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION: ${PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION:-True} + volumes: + - pgadmin_data:/var/lib/pgadmin + - ./config_local.py:/pgadmin4/config_local.py:ro + - ./servers.json:/pgadmin4/servers.json:ro + expose: + - "${PGADMIN_PUBLISHED_PORT:-5050}:80" + healthcheck: + test: ["CMD-SHELL", "python3 -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:80/misc/ping').read()\""] + interval: 30s + timeout: 10s + retries: 5 + start_period: 40s + networks: + proxy: + external: true + +networks: + internal: + driver: bridge + proxy: + external: true + +volumes: + pgadmin_data: + name: ${PGADMIN_VOLUME_NAME:-pgadmin_data} diff --git a/servers.json b/servers.json new file mode 100644 index 0000000..8cb84b6 --- /dev/null +++ b/servers.json @@ -0,0 +1,3 @@ +{ + "Servers": {} +}