diff --git a/README.md b/README.md index 310b8ef..57ddebb 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,118 @@ # mates-ansible -Ansible playbooky pro nasazení a správu home infrastruktury. -Vychází z tvých existujících setupů v `/home/mates/docker/`. +Ansible role a playbooky pro přípravu nového serveru a nasazení home infrastruktury. + +## 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: + 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//`) +- ✅ 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@ + +# Over Docker bez sudo +docker ps + +# Nasad sluzby z docker-services +git clone http://: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 ``` -playbooks/ -├── bootstrap-server.yml # Úvodní setup serveru (deploy user, SSH, UFW, fail2ban) -├── deploy-services.yml # Nasaď Docker služby -├── update-services.yml # Update všech služeb -└── security-hardening.yml # Sysctl, auditd, auto-updates +mates-ansible/ +├── README.md +├── ansible.cfg +├── inventory.example.yml +├── 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 -Všechny playbooky mají komentáře v češtině. Detailní postupy najdeš v Jotty knowledge base. +Detailní postupy najdeš v Jotty knowledge base. ## Licence diff --git a/group_vars/all.yml.example b/group_vars/all.yml.example index cff6ee0..575ac3f 100644 --- a/group_vars/all.yml.example +++ b/group_vars/all.yml.example @@ -2,11 +2,34 @@ # Spolecne promenne pro vsechny playbooky # Zkopiruj na group_vars/all.yml a dopln -# Docker -docker_user: deploy -docker_uid: 1000 -docker_gid: 1000 -docker_install_compose_plugin: true +# ============================================ +# DEPLOY USER (UID 1000) +# ============================================ +deploy_user: deploy +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/) services_to_deploy: @@ -25,11 +48,27 @@ services_to_deploy: - speedtest - 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_password: changeme -# Gitea admin (po instalaci) gitea_admin_user: admin gitea_admin_password: changeme gitea_admin_email: admin@example.com diff --git a/playbooks/prepare-new-server.yml b/playbooks/prepare-new-server.yml new file mode 100644 index 0000000..ca2f6f5 --- /dev/null +++ b/playbooks/prepare-new-server.yml @@ -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// + + Dalsi kroky: + 1. SSH jako deploy: ssh deploy@ + 2. Klonuj docker services: git clone http://: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 diff --git a/roles/common/defaults/main.yml b/roles/common/defaults/main.yml new file mode 100644 index 0000000..0f23bce --- /dev/null +++ b/roles/common/defaults/main.yml @@ -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 diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..fdb270b --- /dev/null +++ b/roles/common/tasks/main.yml @@ -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 diff --git a/roles/deploy-user/defaults/main.yml b/roles/deploy-user/defaults/main.yml new file mode 100644 index 0000000..7973f43 --- /dev/null +++ b/roles/deploy-user/defaults/main.yml @@ -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 diff --git a/roles/deploy-user/tasks/main.yml b/roles/deploy-user/tasks/main.yml new file mode 100644 index 0000000..9674825 --- /dev/null +++ b/roles/deploy-user/tasks/main.yml @@ -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 diff --git a/roles/directories/defaults/main.yml b/roles/directories/defaults/main.yml new file mode 100644 index 0000000..6bd1c9e --- /dev/null +++ b/roles/directories/defaults/main.yml @@ -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" diff --git a/roles/directories/tasks/main.yml b/roles/directories/tasks/main.yml new file mode 100644 index 0000000..0ee0bb7 --- /dev/null +++ b/roles/directories/tasks/main.yml @@ -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 }}" diff --git a/roles/docker/defaults/main.yml b/roles/docker/defaults/main.yml new file mode 100644 index 0000000..36c416f --- /dev/null +++ b/roles/docker/defaults/main.yml @@ -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 diff --git a/roles/docker/handlers/main.yml b/roles/docker/handlers/main.yml new file mode 100644 index 0000000..37b5807 --- /dev/null +++ b/roles/docker/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart docker + ansible.builtin.systemd: + name: docker + state: restarted diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml new file mode 100644 index 0000000..46739aa --- /dev/null +++ b/roles/docker/tasks/main.yml @@ -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 }}" diff --git a/roles/firewall/defaults/main.yml b/roles/firewall/defaults/main.yml new file mode 100644 index 0000000..f154a0f --- /dev/null +++ b/roles/firewall/defaults/main.yml @@ -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" } diff --git a/roles/firewall/tasks/main.yml b/roles/firewall/tasks/main.yml new file mode 100644 index 0000000..675372a --- /dev/null +++ b/roles/firewall/tasks/main.yml @@ -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 diff --git a/roles/ssh-keys/defaults/main.yml b/roles/ssh-keys/defaults/main.yml new file mode 100644 index 0000000..7dedac0 --- /dev/null +++ b/roles/ssh-keys/defaults/main.yml @@ -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: [] diff --git a/roles/ssh-keys/tasks/main.yml b/roles/ssh-keys/tasks/main.yml new file mode 100644 index 0000000..e66276d --- /dev/null +++ b/roles/ssh-keys/tasks/main.yml @@ -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 }}"