feat: prepare-new-server playbook + role struktura

playbook prepare-new-server.yml:
- update systemu
- deploy user (UID 1000, heslo zamknuto)
- SSH klic pro deploy uzivatele
- adresarova struktura (/home/deploy/{docker,scripts,backups,logs,...})
- Docker Engine + Compose plugin (bez sudo)
- UFW firewall (22, 80, 443)
- fail2ban
- overeni docker bez sudo

Role (kazda v samostatnem adresari):
- common: update, base packages, timezone
- deploy-user: vytvoreni usera UID 1000
- ssh-keys: authorized_keys deployment
- firewall: UFW konfigurace
- docker: Docker Engine + Compose + daemon.json
- directories: /home/deploy/{docker/<sluzba>,backups,scripts,logs}

Pouziti:
  ansible-playbook -i inventory.yml playbooks/prepare-new-server.yml
This commit is contained in:
2026-08-01 20:02:19 +02:00
parent da9003aef8
commit ec2f1d639c
16 changed files with 638 additions and 15 deletions
+105 -8
View File
@@ -1,21 +1,118 @@
# mates-ansible # mates-ansible
Ansible playbooky pro nasazení a správu home infrastruktury. Ansible role a playbooky pro přípravu nového serveru a nasazení home infrastruktury.
Vychází z tvých existujících setupů v `/home/mates/docker/`.
## Playbooky
| Playbook | Účel |
|---|---|
| `prepare-new-server.yml` | Kompletní příprava nového serveru (od nuly) |
| `deploy-services.yml` | Nasaď Docker služby z `mates-docker-services/` |
| `update-services.yml` | Update všech služeb (`docker compose pull && up -d`) |
| `security-hardening.yml` | Sysctl, auditd, auto-updates |
## Quickstart pro nový server
### 1. Příprava inventory
```bash
cp inventory.example.yml inventory.yml
nano inventory.yml # nastavit IP a SSH klíč
```
### 2. Přidání svého SSH klíče
```bash
# Verejny klic z Macu
cat ~/.ssh/id_ed25519.pub
# Pridej do group_vars/all.yml:
deploy_ssh_public_keys:
- "ssh-ed25519 AAAAC3Nz... hermes@mac"
```
### 3. První připojení (s heslem)
```yaml
# inventory.yml - pro prvni pripojeni (jeste pred SSH klicem)
homeservers:
hosts:
novy-server:
ansible_host: <server-ip>
ansible_user: ubuntu # nebo root
ansible_ssh_pass: heslo # POZOR: jen docasne
ansible_become_pass: heslo # POZOR: jen docasne
```
### 4. Spuštění playbooku
```bash
ansible-playbook -i inventory.yml playbooks/prepare-new-server.yml
```
Playbook provede:
- ✅ Update systému (apt)
- ✅ Vytvoří `deploy` usera (UID 1000) bez hesla
- ✅ Nastaví SSH klíč pro `deploy`
- ✅ Vytvoří adresářovou strukturu (`/home/deploy/docker/<sluzba>/`)
- ✅ Nainstaluje Docker Engine + Compose plugin
- ✅ Přidá `deploy` do `docker` group (docker bez sudo)
- ✅ Nastaví UFW firewall (povoleno 22, 80, 443)
- ✅ Nainstaluje fail2ban
### 5. Po dokončení
```bash
# Prihlas se jako deploy
ssh deploy@<server-ip>
# Over Docker bez sudo
docker ps
# Nasad sluzby z docker-services
git clone http://<server-ip>:3000/mates/mates-docker-services.git
cd mates-docker-services/portainer
cp .env.example .env
docker compose up -d
```
## Role
| Role | Účel |
|---|---|
| `common` | Update systému, base packages, timezone |
| `deploy-user` | Vytvoření `deploy` usera (UID 1000) |
| `ssh-keys` | Nasazení authorized_keys |
| `firewall` | UFW konfigurace |
| `docker` | Docker Engine + Compose + user v docker group |
| `directories` | `/home/deploy/{docker,scripts,backups,logs,...}` |
## Struktura ## Struktura
``` ```
playbooks/ mates-ansible/
├── bootstrap-server.yml # Úvodní setup serveru (deploy user, SSH, UFW, fail2ban) ├── README.md
├── deploy-services.yml # Nasaď Docker služby ├── ansible.cfg
├── update-services.yml # Update všech služeb ├── inventory.example.yml
── security-hardening.yml # Sysctl, auditd, auto-updates ── group_vars/all.yml.example
├── playbooks/
│ ├── prepare-new-server.yml
│ ├── deploy-services.yml
│ ├── update-services.yml
│ └── security-hardening.yml
├── roles/
│ ├── common/
│ ├── deploy-user/
│ ├── ssh-keys/
│ ├── firewall/
│ ├── docker/
│ └── directories/
└── requirements.yml
``` ```
## Detailní návody ## Detailní návody
Všechny playbooky mají komentáře v češtině. Detailní postupy najdeš v Jotty knowledge base. Detailní postupy najdeš v Jotty knowledge base.
## Licence ## Licence
+46 -7
View File
@@ -2,11 +2,34 @@
# Spolecne promenne pro vsechny playbooky # Spolecne promenne pro vsechny playbooky
# Zkopiruj na group_vars/all.yml a dopln # Zkopiruj na group_vars/all.yml a dopln
# Docker # ============================================
docker_user: deploy # DEPLOY USER (UID 1000)
docker_uid: 1000 # ============================================
docker_gid: 1000 deploy_user: deploy
docker_install_compose_plugin: true deploy_uid: 1000
deploy_groups:
- docker
- sudo
- adm
- systemd-journal
# Verejne SSH klice pro deploy uzivatele
# Pridej sve klice (verejnou cast z `cat ~/.ssh/id_ed25519.pub`)
deploy_ssh_public_keys:
- "ssh-ed25519 AAAAC3Nz... hermes@mac" # <-- nahrad svym klicem
# ============================================
# DOCKER
# ============================================
docker_compose_version: "v2.27.0"
docker_daemon_config:
log-driver: json-file
log-opts:
max-size: "10m"
max-file: "3"
storage-driver: overlay2
live-restore: true
userland-proxy: false
# Sluzby k nasazeni (seznam nazvu adresaru v docker-services/) # Sluzby k nasazeni (seznam nazvu adresaru v docker-services/)
services_to_deploy: services_to_deploy:
@@ -25,11 +48,27 @@ services_to_deploy:
- speedtest - speedtest
- watchtower - watchtower
# NPM admin (po prvnim loginu zmenit) # ============================================
# NETWORK / FIREWALL
# ============================================
ssh_port: 22
allowed_ports:
- { port: 22, proto: tcp, comment: "SSH" }
- { port: 80, proto: tcp, comment: "HTTP" }
- { port: 443, proto: tcp, comment: "HTTPS" }
# ============================================
# SECURITY (fail2ban)
# ============================================
fail2ban_maxretry: 5
fail2ban_bantime: 3600
# ============================================
# SLUZBY (credentials po prvnim spusteni)
# ============================================
npm_default_email: admin@example.com npm_default_email: admin@example.com
npm_default_password: changeme npm_default_password: changeme
# Gitea admin (po instalaci)
gitea_admin_user: admin gitea_admin_user: admin
gitea_admin_password: changeme gitea_admin_password: changeme
gitea_admin_email: admin@example.com gitea_admin_email: admin@example.com
+124
View File
@@ -0,0 +1,124 @@
---
# Playbook: prepare-new-server.yml
#
# Kompletni priprava noveho Ubuntu serveru:
# 1. Update systemu (apt)
# 2. Deploy user (UID 1000, heslo zamknuto)
# 3. SSH klice (pro deploy uzivatele)
# 4. Adresarova struktura (/home/deploy/docker, ...)
# 5. Docker Engine + Compose plugin
# 6. Deploy user v docker group (docker bez sudo)
# 7. UFW firewall (povoleno SSH, HTTP, HTTPS)
# 8. fail2ban
#
# Pouziti:
# # 1. Nastavit inventory.yml a pridat svuj verejny klic do group_vars/all.yml
# # 2. ansible-playbook -i inventory.yml playbooks/prepare-new-server.yml
#
# Co playbook predpoklada:
# - Server ma Ubuntu 22.04 nebo 24.04 LTS
# - Pristup pres SSH s heslem (root nebo sudo user) pro ansible_become
# - V inventory.yml je nastaven ansible_host, ansible_user (s sudo prava)
#
- name: Priprav novy Ubuntu server
hosts: homeservers
become: true
gather_facts: true
vars:
# Default pro prepare-new-server.yml - lze prepsat v inventory
ssh_port: 22
fail2ban_maxretry: 5
fail2ban_bantime: 3600 # 1 hodina
pre_tasks:
- name: Varovani pred spustenim
ansible.builtin.pause:
prompt: |
============================================
PRIPRAVA NOVEHO SERVERU
Tento playbook:
- updatuje system
- vytvori deploy usera (UID 1000)
- nahraje SSH klice
- nainstaluje Docker + Compose
- vytvori adresarovou strukturu
- nastavi firewall
SSH pristup bude fungovat pro deploy usera s tvym verejnym klicem.
Pokud se neco pokazi, pripoj se pres puvodniho usera (z inventory).
Pokracovat? (Enter = ano, Ctrl+C = prerusit)
============================================
when: confirm_run | default(true) | bool
roles:
- role: common
tags: [common, base]
- role: deploy-user
tags: [user, deploy]
- role: ssh-keys
tags: [ssh, keys]
- role: firewall
tags: [firewall, ufw]
- role: docker
tags: [docker]
- role: directories
tags: [directories, docker]
post_tasks:
- name: Nainstaluj fail2ban
ansible.builtin.apt:
name:
- fail2ban
state: present
update_cache: true
- name: Nastav fail2ban jail pro SSH
ansible.builtin.copy:
dest: /etc/fail2ban/jail.local
content: |
[DEFAULT]
bantime = {{ fail2ban_bantime }}
findtime = 10m
maxretry = {{ fail2ban_maxretry }}
[sshd]
enabled = true
port = {{ ssh_port }}
filter = sshd
logpath = /var/log/auth.log
maxretry = {{ fail2ban_maxretry }}
mode: "0644"
notify: Restart fail2ban
- name: Aktivuj fail2ban
ansible.builtin.systemd:
name: fail2ban
state: started
enabled: true
- name: Vypis stav serveru
ansible.builtin.debug:
msg: |
============================================
SERVER PRIPRAVEN
SSH pristup: deploy@{{ ansible_host | default(inventory_hostname) }}:{{ ssh_port }}
Docker: docker --version (bez sudo)
Sluzby: /home/{{ deploy_user }}/docker/<sluzba>/
Dalsi kroky:
1. SSH jako deploy: ssh deploy@<server-ip>
2. Klonuj docker services: git clone http://<server-ip>:3000/mates/mates-docker-services.git
3. Nasaď Portainer: cd docker/portainer && docker compose up -d
============================================
handlers:
- name: Restart fail2ban
ansible.builtin.systemd:
name: fail2ban
state: restarted
+30
View File
@@ -0,0 +1,30 @@
---
# Společné proměnné pro common roli
deploy_user: deploy
deploy_uid: 1000
deploy_group: docker
deploy_groups:
- docker
- sudo
- adm
- systemd-journal
timezone: Europe/Prague
# Balíky co se instalují vždy
base_packages:
- curl
- wget
- git
- vim
- htop
- ca-certificates
- gnupg
- lsb-release
- apt-transport-https
- bash-completion
- software-properties-common
- unzip
- zip
- rsync
- net-tools
+26
View File
@@ -0,0 +1,26 @@
---
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Upgrade vsech baliku
ansible.builtin.apt:
upgrade: dist
update_cache: true
autoremove: true
- name: Instalace zakladnich baliku
ansible.builtin.apt:
name: "{{ base_packages }}"
state: present
update_cache: true
- name: Nastav timezone
community.general.timezone:
name: "{{ timezone }}"
- name: Over ze hostname je spravne
ansible.builtin.hostname:
name: "{{ inventory_hostname }}"
when: inventory_hostname is defined
+12
View File
@@ -0,0 +1,12 @@
---
# Proměnné pro deploy-user roli
deploy_user: deploy
deploy_uid: 1000
deploy_home: "/home/{{ deploy_user }}"
deploy_groups:
- docker
- sudo
- adm
- systemd-journal
deploy_shell: /bin/bash
deploy_password_locked: true # heslo zamknuto, jen SSH klic
+41
View File
@@ -0,0 +1,41 @@
---
- name: Vytvor skupiny pro deploy uzivatele
ansible.builtin.group:
name: "{{ item }}"
state: present
loop: "{{ deploy_groups }}"
- name: Vytvor deploy uzivatele (UID {{ deploy_uid }})
ansible.builtin.user:
name: "{{ deploy_user }}"
uid: "{{ deploy_uid }}"
group: "{{ deploy_groups[0] }}"
groups: "{{ deploy_groups | join(',') }}"
shell: "{{ deploy_shell }}"
create_home: true
home: "{{ deploy_home }}"
password: "!"
update_password: always
append: true
- name: Uzamkni heslo deploy uzivatele
ansible.builtin.command: passwd -l {{ deploy_user }}
changed_when: false
- name: Vytvor .ssh adresar pro deploy uzivatele
ansible.builtin.file:
path: "{{ deploy_home }}/.ssh"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: "0700"
- name: Vytvor authorized_keys soubor
ansible.builtin.file:
path: "{{ deploy_home }}/.ssh/authorized_keys"
state: touch
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: "0600"
modification_time: preserve
access_time: preserve
+42
View File
@@ -0,0 +1,42 @@
---
# Proměnné pro directories roli
deploy_user: deploy
deploy_home: "/home/{{ deploy_user }}"
# Zakladni adresarova struktura
base_directories:
- path: "{{ deploy_home }}/docker"
description: "Docker sluzby (kazda v samostatne slozce)"
mode: "0755"
- path: "{{ deploy_home }}/docker-services-repo"
description: "Git repo s docker-compose sablonami (klonovane)"
mode: "0755"
- path: "{{ deploy_home }}/backups"
description: "Lokalni zalohy Docker dat (pred rsync na NAS)"
mode: "0750"
- path: "{{ deploy_home }}/scripts"
description: "Vlastni bash skripty"
mode: "0755"
- path: "{{ deploy_home }}/logs"
description: "Logy serveru (mimo system log)"
mode: "0755"
- path: "{{ deploy_home }}/.local/bin"
description: "Uzivatelske binarky (Hermes atd.)"
mode: "0755"
# Podadresare pro Docker stack
docker_subdirs:
- "{{ deploy_home }}/docker/portainer"
- "{{ deploy_home }}/docker/nginx-proxy-manager"
- "{{ deploy_home }}/docker/vaultwarden"
- "{{ deploy_home }}/docker/gitea"
- "{{ deploy_home }}/docker/jotty"
- "{{ deploy_home }}/docker/nextcloud"
- "{{ deploy_home }}/docker/rustdesk"
- "{{ deploy_home }}/docker/audiobookshelf"
- "{{ deploy_home }}/docker/calibre-web"
- "{{ deploy_home }}/docker/plex"
- "{{ deploy_home }}/docker/erugo"
- "{{ deploy_home }}/docker/jswiki"
- "{{ deploy_home }}/docker/speedtest"
- "{{ deploy_home }}/docker/watchtower"
+27
View File
@@ -0,0 +1,27 @@
---
- name: Vytvor zakladni adresare
ansible.builtin.file:
path: "{{ item.path }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: "{{ item.mode }}"
loop: "{{ base_directories }}"
- name: Vytvor podadresare pro Docker sluzby
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: "0755"
loop: "{{ docker_subdirs }}"
- name: Vytvor .gitkeep v prazdnych docker podadresarich
ansible.builtin.file:
path: "{{ item }}/.gitkeep"
state: touch
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: "0644"
loop: "{{ docker_subdirs }}"
+14
View File
@@ -0,0 +1,14 @@
---
# Proměnné pro docker roli
deploy_user: deploy
docker_compose_version: "v2.27.0"
# Docker daemon nastaveni
docker_daemon_config:
log-driver: json-file
log-opts:
max-size: "10m"
max-file: "3"
storage-driver: overlay2
live-restore: true
userland-proxy: false
+5
View File
@@ -0,0 +1,5 @@
---
- name: Restart docker
ansible.builtin.systemd:
name: docker
state: restarted
+89
View File
@@ -0,0 +1,89 @@
---
- name: Nainstaluj prerekvizity pro Docker
ansible.builtin.apt:
name:
- ca-certificates
- curl
- gnupg
state: present
update_cache: true
- name: Vytvor adresar pro Docker GPG klic
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: "0755"
- name: Stahn Docker GPG klic
ansible.builtin.get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: "0644"
force: true
- name: Pridej Docker repo
ansible.builtin.apt_repository:
repo: >-
deb [arch={{ ansible_architecture | replace('x86_64', 'amd64') | replace('aarch64', 'arm64') }}
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu
{{ ansible_distribution_release }} stable
filename: docker
state: present
update_cache: true
- name: Nainstaluj Docker Engine a Compose plugin
ansible.builtin.apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: present
update_cache: true
- name: Over ze Docker bezi
ansible.builtin.systemd:
name: docker
state: started
enabled: true
- name: Nastav docker daemon.json
ansible.builtin.copy:
content: "{{ docker_daemon_config | to_nice_json }}"
dest: /etc/docker/daemon.json
owner: root
group: root
mode: "0644"
notify: Restart docker
- name: Pridej deploy uzivatele do docker group (docker bez sudo)
ansible.builtin.user:
name: "{{ deploy_user }}"
groups: docker
append: true
- name: Over docker verze
ansible.builtin.command: docker --version
register: docker_version_output
changed_when: false
- ansible.builtin.debug:
msg: "Docker nainstalovan: {{ docker_version_output.stdout }}"
- name: Over docker compose verze
ansible.builtin.command: docker compose version
register: docker_compose_output
changed_when: false
- ansible.builtin.debug:
msg: "Docker Compose: {{ docker_compose_output.stdout }}"
- name: Test docker bez sudo
ansible.builtin.command: docker ps
become: true
become_user: "{{ deploy_user }}"
changed_when: false
register: docker_ps_test
failed_when: docker_ps_test.rc != 0
- ansible.builtin.debug:
msg: "Docker bez sudo funguje pro {{ deploy_user }}"
+8
View File
@@ -0,0 +1,8 @@
---
# Proměnné pro firewall roli
ssh_port: 22
# Dalsi porty co chces povolit (pro servery)
allowed_ports:
- { port: 80, proto: tcp, comment: "HTTP" }
- { port: 443, proto: tcp, comment: "HTTPS" }
- { port: "{{ ssh_port }}", proto: tcp, comment: "SSH" }
+32
View File
@@ -0,0 +1,32 @@
---
- name: Nainstaluj UFW
ansible.builtin.apt:
name: ufw
state: present
update_cache: true
- name: Reset UFW na default
community.general.ufw:
state: reset
- name: UFW default - deny incoming
community.general.ufw:
direction: incoming
policy: deny
- name: UFW default - allow outgoing
community.general.ufw:
direction: outgoing
policy: allow
- name: Povol porty pres UFW
community.general.ufw:
rule: allow
port: "{{ item.port }}"
proto: "{{ item.proto }}"
comment: "{{ item.comment }}"
loop: "{{ allowed_ports }}"
- name: Aktivuj UFW
community.general.ufw:
state: enabled
+14
View File
@@ -0,0 +1,14 @@
---
# Proměnné pro ssh-keys roli
deploy_user: deploy
deploy_home: "/home/{{ deploy_user }}"
ssh_key_path: "{{ deploy_home }}/.ssh/authorized_keys"
ssh_key_owner: "{{ deploy_user }}"
ssh_key_group: "{{ deploy_user }}"
ssh_key_mode: "0600"
# Verejne klice pro deploy uzivatele (nastav v inventory.yml)
# deploy_ssh_public_keys:
# - "ssh-ed25519 AAAAC3Nz... hermes@mac"
# - "ssh-rsa AAAAB3... backup@server"
deploy_ssh_public_keys: []
+23
View File
@@ -0,0 +1,23 @@
---
- name: Over ze deploy_ssh_public_keys je nastaveno
ansible.builtin.assert:
that:
- deploy_ssh_public_keys is defined
- deploy_ssh_public_keys | length > 0
fail_msg: "deploy_ssh_public_keys neni nastaven. Pridej ho do group_vars/all.yml nebo inventory."
- name: Nastav authorized_keys pro deploy uzivatele
ansible.posix.authorized_key:
user: "{{ deploy_user }}"
state: present
key: "{{ item }}"
exclusive: false # neprepisuj existujici klice
loop: "{{ deploy_ssh_public_keys }}"
when: deploy_ssh_public_keys | length > 0
- name: Nastav spravna opravneni na authorized_keys
ansible.builtin.file:
path: "{{ ssh_key_path }}"
owner: "{{ ssh_key_owner }}"
group: "{{ ssh_key_group }}"
mode: "{{ ssh_key_mode }}"