Шаблон для управления личной облачной инфраструктурой через Ansible + Docker Compose + Forgejo Actions.
┌─────────────────────────────────────────────────────────────┐
│ Git-репозиторий │
│ (Forgejo / GitHub) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Playbooks │ │ Roles │ │ Inventory│ │ Workflows │ │
│ │ .yml │ │ .yml │ │ .yml │ │ .yml │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────────┘ │
└──────────────────────┬──────────────────────────────────────┘
│ CI/CD (Forgejo Actions)
▼
┌─────────────────────────────────────────────────────────────┐
│ Ansible Runner Container │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ SSH CA (временные ключи) │ │
│ │ Ansible Vault (зашифрованные секреты) │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────┬──────────────────┬───────────────────┬───────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ VM 1 │ │ VM 2 │ │ VPN 1-3 │
│ (хост) │ │ (хост) │ │ (Xray VPN) │
│ ┌──────┐ │ │ ┌──────────┐ │ └──────────────┘
│ │Docker│ │ │ │Docker │ │
│ │ Apps │ │ │ │ Apps │ │
│ └──────┘ │ │ └──────────┘ │
└──────────┘ └──────────────┘
| Компонент | Назначение |
|---|---|
| Ansible Playbooks | Автоматизация: инициализация VMs, обновление, деплой приложений, DNS, VPN, SSL |
| Ansible Roles | Переиспользуемые модули: пользователи, SSH, UFW, Docker, Xray, DNS |
| Static Inventory | Описание хостов (VMs, VPN-серверы) и их групп |
| Host Vars / Group Vars | Переменные для хостов (SSL paths, UFW порты) и групп (пользователи, DNS) |
| Docker Compose Apps | Определения приложений (service.yaml), копируются на хосты в /opt/<app>/ |
| Forgejo Actions CI/CD | Workflows: деплой, обновление VMs, выпуск сертификатов, DNS-синхронизация |
| Ansible Vault | Шифрование секретов (API ключи, пароли) |
| SSH CA | Выпуск временных SSH-сертификатов для безопасного доступа к хостам |
# Клонировать репозиторий
git clone <your-repo-url> cloud
cd cloud
# Создать SSH CA (Certificate Authority)
ssh-keygen -t ed25519 -f vault_ca -N ""
# Создать пароль для Ansible Vault
echo "your-vault-password" > vault_pass.txt
# Настроить виртуальное окружение Python
python3 -m venv .venv
source .venv/bin/activate
pip install ansible hvac requests passlibОтредактируйте ansible/inventory/static.yml — укажите свои хосты и IP-адреса:
all:
children:
vm:
hosts:
my_server:
ansible_host: 1.2.3.4
xray_vpn:
hosts:
vpn_01:
ansible_host: 5.6.7.8
dns:
hosts:
localhost:
ansible_connection: local./vm_init.sh
# Выберите playbook "vm_init"
# Укажите IP и root-пароль нового сервераPlaybook выполнит:
base_packages— обновление пакетов, установка утилитusers— создание пользователей, добавление SSH-ключейsudoers— настройка sudo (NOPASSWD для git, пароль для админов)ssh_hardening— настройка SSH (только ключи/CA, AllowUsers)
./vm_init.sh
# Выберите playbook "vm_update"
# Укажите хост или группу (или all для всех)Playbook выполнит:
- Обновление пакетов
- Управление пользователями
- SSH-безопасность
- UFW firewall
- Установка Docker
- Обновление SSL-сертификатов
Создайте директорию приложения в ansible/files/<host_name>/<app_name>/ с docker-compose.yaml:
# ansible/files/my_server/my_app/docker-compose.yaml
services:
my_app:
image: nginx:alpine
container_name: my_app
ports:
- "8080:80"
volumes:
- ./data:/usr/share/nginx/htmlЗапустите деплой:
./vm_init.sh # выберите "deploy_compose", укажите хостПосле настройки Forgejo-сервера, добавьте secrets в репозиторий:
CA_PRIVATE_KEY— содержимоеvault_caANSIBLE_VAULT_PASSWORD— пароль от vaultDNS_API_KEY— API-ключ для DNS-провайдера
Workflows:
- Build Ansible Image — сборка Docker-образа с Ansible
- Deploy Apps — ручной запуск деплоя выбранных приложений
- Update VMs — ручное обновление выбранных хостов
- Certificates — ежемесячное обновление SSL (Let's Encrypt)
- DNS — синхронизация DNS-записей при пуше в master
| Роль | Назначение | Параметры |
|---|---|---|
base_packages |
Обновление APT, установка базовых пакетов (curl, htop, qemu-guest-agent, etc.) | base_packages_list — список пакетов |
users |
Создание/управление пользователями, добавление SSH-ключей | managed_users — список пользователей с именем, shell, ssh_keys, sudo, sudo_password_hash |
sudoers |
Настройка правил sudo (NOPASSWD для сервисных пользователей) | managed_users — флаги sudo, sudo_nopasswd |
ssh_hardening |
Настройка SSHD: только ключи/CA, AllowUsers, отключение root-логина | managed_users — список разрешённых пользователей; SSH CA public key |
ufw |
Настройка файрвола: deny по-умолчанию, разрешённые порты | ufw_allowed_ports (22, 80, 443 + extra), ufw_extra_ports |
geerlingguy.docker |
Установка Docker Engine и Docker Compose (через galaxy) | (стандартные параметры роли) |
vm_update_ssl |
Размещение SSL-сертификатов из переменных окружения | FULLCHAIN_PEM, KEY_PEM из env/секретов |
xray_vpn |
Установка и настройка Xray VPN (VLESS + REALITY) | xray_config — конфигурация inbound/outbound |
netangels_dns |
Управление DNS-зонами и записями через NetAngels API | dns_zones, vault_netangels_api_key |
# 1. Добавить хост в inventory/static.yml
# 2. Создать host_vars/<hostname>/infra-ssl.yml при необходимости
# 3. Создать ansible/files/<hostname>/ для приложений
# 4. Запустить инициализацию:
./vm_init.sh # vm_init, указать IP нового хоста
# 5. После инициализации — обновление:
./vm_init.sh # vm_update, указать хост# 1. Создать директорию приложения:
mkdir -p ansible/files/my_server/my_new_app
# 2. Создать docker-compose.yaml:
cat > ansible/files/my_server/my_new_app/docker-compose.yaml << 'EOF'
services:
my_new_app:
image: nginx:alpine
container_name: my_new_app
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
EOF
# 3. Создать файлы конфигурации (если нужно):
mkdir -p ansible/files/my_server/my_new_app/html
echo "<h1>Hello from template!</h1>" > ansible/files/my_server/my_new_app/html/index.html
# 4. Закоммитить и запустить деплой:
git add ansible/files/my_server/my_new_app/
git commit -m "Add my_new_app"
./vm_init.sh # deploy_compose# 1. Создать inventory с группой xray_vpn
# 2. Определить переменные в group_vars/all/xray_vpn_vars.yml (зашифровать vault)
# 3. Запустить установку:
./vm_init.sh # xray_vpn_setup, указать хост# 1. Описать зоны и записи в group_vars/dns/main.yml
# 2. Установить API-ключ в переменную окружения:
export VAULT_DNS_API_KEY="your-api-key"
# 3. Запустить синхронизацию:
ansible-playbook ansible/playbooks/dns.yml \
-i ansible/inventory \
-e "vault_dns_api_key=${VAULT_DNS_API_KEY}"# 1. Инициализация VM
./vm_init.sh # vm_init
# 2. Первое обновление (установка Docker, настройка UFW)
./vm_init.sh # vm_update
# 3. Деплой приложений
./vm_init.sh # deploy_compose
# 4. Настройка VPN (если нужно)
./vm_init.sh # xray_vpn_setup
# 5. Настройка DNS (если нужно)
export VAULT_DNS_API_KEY="..."
ansible-playbook ansible/playbooks/dns.yml -i ansible/inventorycloud/
├── ansible/ # Инфраструктура как код
│ ├── playbooks/ # Плейбуки Ansible
│ │ ├── vm_init.yml # Первичная настройка VM
│ │ ├── vm_update.yml # Обновление VM
│ │ ├── deploy_compose.yml # Деплой Docker-приложений
│ │ ├── dns.yml # Управление DNS
│ │ ├── xray_vpn_setup.yml # Установка Xray VPN
│ │ ├── _deploy_app.yml # (included) Логика деплоя одного приложения
│ │ └── _dns_records.yml # (included) Логика управления DNS-записями
│ ├── roles/ # Переиспользуемые роли
│ │ ├── base_packages/ # APT-пакеты
│ │ ├── users/ # Пользователи и SSH-ключи
│ │ ├── sudoers/ # SUDO-правила
│ │ ├── ssh_hardening/ # SSH-безопасность
│ │ ├── ufw/ # Файрвол
│ │ ├── vm_update_ssl/ # SSL-сертификаты
│ │ ├── xray_vpn/ # Xray VPN
│ │ └── netangels_dns/ # DNS API
│ ├── inventory/ # Инвентарь и переменные
│ │ ├── static.yml # Определения хостов
│ │ ├── group_vars/ # Переменные групп (all, dns)
│ │ ├── host_vars/ # Переменные хостов
│ │ └── ansible.cfg # Конфигурация Ansible
│ └── files/ # Конфигурации приложений
│ ├── <host_01>/ # Приложения для хоста 1
│ │ └── <app_name>/ # docker-compose.yaml + конфиги
│ └── <host_02>/ # Приложения для хоста 2
├── docker/ # Docker build-контексты
│ ├── ansible/ # Dockerfile для Ansible Runner
│ └── acme/ # ACME-клиент для Let's Encrypt
├── .forgejo/workflows/ # CI/CD pipelines (Forgejo Actions)
├── vm_init.sh # Интерактивный запуск плейбуков
└── README.md # Этот файл
- Локально: Python 3, Ansible, ssh-keygen
- На хостах: Ubuntu/Debian, доступ по SSH
- Для CI/CD: Forgejo или GitHub с Actions
- Для DNS: NetAngels API (или заменить на своего провайдера)
- Для SSL: Let's Encrypt + DNS-01 challenge
- SSH-доступ через временные сертификаты (CA), а не статические ключи
- Секреты зашифрованы Ansible Vault
.envфайлы иvault_pass.txtв.gitignore- UFW: default deny, открыты только необходимые порты
- SSH: только key/CA аутентификация, AllowUsers, отключён root