diff --git a/.gitignore b/.gitignore index e69de29..c97a88e 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +*.retry diff --git a/CLAUDE.md b/CLAUDE.md index 052eb8c..c16b1f7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,15 +17,17 @@ Infrastructure as Code and runbooks for Phytron's server infrastructure. Global ``` ansible/ # Global settings & configuration for all servers - hosts.ini # Inventory: all existing and planned servers with IPs - # (one group per host, group name == hostname) - group_vars/all.yml # Defaults shared by all hosts - group_vars/.yml # Per-host variables + hosts.ini # Inventory: all existing and planned servers with IPs. + # One group per host; group names use underscores + # (phy_z_srv_git), host aliases the real hostnames + # (phy-z-srv-git ansible_host=) + group_vars/all.yml # Defaults shared by all hosts (incl. ansible_user/port) + group_vars/.yml # Per-host overrides ONLY — no copies of all.yml values + group_vars/secrets.yml # ansible-vault encrypted secrets — never commit plaintext run.yml # Main playbook playbooks/ # Utility playbooks (update.yml, shutdown.yml) roles/ # Custom roles (e.g. nextcloud) requirements.yml # External Galaxy roles (geerlingguy.*, ...) - vars/vault.yml # ansible-vault encrypted secrets — never commit plaintext justfile # Task runner: just run HOST, just reqs, just vault ACTION server// # Host-specific docs, scripts, files @@ -47,6 +49,7 @@ server// # Host-specific docs, scripts, files ## Conventions - Ansible commands run from `ansible/`, preferably via the `justfile` (e.g. `just run `). -- Secrets go into `ansible/vars/vault.yml`, encrypted with ansible-vault. Never commit plaintext secrets. +- Secrets go into `ansible/group_vars/secrets.yml`, encrypted with ansible-vault. Never commit plaintext secrets. +- SSH password authentication stays enabled for easy access (servers are not reachable from outside); exception: DMZ hosts like phy-z-dmz-sftp01 are key-only. - Dated documents (runbooks, assessments) use the `YYYYMMDD-.md` naming scheme. -- New servers get: an entry in `hosts.ini`, a `group_vars/.yml`, and a `server//` folder with a README. +- New servers get: an entry in `hosts.ini`, a `group_vars/.yml` (overrides only), and a `server//` folder with a README. diff --git a/README.md b/README.md index e69de29..4ace1c2 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,8 @@ +# infra-phytron + +Infrastructure as Code and runbooks for Phytron's server infrastructure. + +- `ansible/` — global configuration for all servers (inventory, group_vars, roles, playbooks). See [ansible/README.md](ansible/README.md). +- `server//` — per-server documentation, runbooks, scripts, and files. + +All servers are listed with their IPs in [`ansible/hosts.ini`](ansible/hosts.ini); each has a README under `server/`. diff --git a/ansible/.DS_Store b/ansible/.DS_Store deleted file mode 100644 index a8a155c..0000000 Binary files a/ansible/.DS_Store and /dev/null differ diff --git a/ansible/README.md b/ansible/README.md index 3c0c478..8e3b860 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -1,3 +1,20 @@ -# Buero Templates for used software deployments +# Ansible -In this repository I collect all ansible playbooks used during my work. +Global configuration for all Phytron servers. Run everything from this directory, preferably via `just`. + +## Layout + +- `hosts.ini` — inventory; one group per host (`phy_z_*`), host aliases match the real hostnames +- `group_vars/all.yml` — defaults for all hosts; `group_vars/.yml` holds per-host overrides only +- `group_vars/secrets.yml` — ansible-vault encrypted secrets +- `run.yml` — main playbook; `playbooks/` — utilities (update, shutdown) +- `roles/` — custom roles; external roles come from `requirements.yml` + +## Usage + +```sh +just reqs # install Galaxy role requirements +just run [ARGS] # run run.yml against one host, e.g. just run phy_z_srv_cloud +just compose # docker compose tasks only (--tags compose) +just vault edit # edit encrypted secrets (encrypt/decrypt/edit) +``` diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index ecb2be2..473c89f 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -1,4 +1,8 @@ --- +# connection settings (identical for all hosts) +ansible_user: sbxadmin +ansible_port: 22 + # generic settings main_username: sbxadmin main_groupname: "{{ main_username }}" diff --git a/ansible/group_vars/phy-z-dmz-sftp01.yml b/ansible/group_vars/phy-z-dmz-sftp01.yml deleted file mode 100644 index 07e4fdf..0000000 --- a/ansible/group_vars/phy-z-dmz-sftp01.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# generic settings -main_username: sbxadmin -main_groupname: "{{ main_username }}" -main_uid: "1000" -main_gid: "{{ main_uid }}" - -# weareinteractive.environment -environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } - -global_env_vars: - - "PUID={{ main_uid }}" - - "PGID={{ main_gid }}" - - "TZ={{ ntp_timezone }}" - -# geerlingguy.ntp -ntp_timezone: "Europe/Berlin" - -# geerlingguy.nfs -#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] - -# geerlingguy.security -security_ssh_port: 22 -security_ssh_password_authentication: "yes" -security_ssh_permit_root_login: "no" -security_ssh_usedns: "no" -security_ssh_permit_empty_password: "no" -security_ssh_challenge_response_auth: "no" -security_ssh_gss_api_authentication: "no" -security_ssh_x11_forwarding: "no" -security_ssh_allowed_users: - - "{{ main_username }}" -security_ssh_allowed_groups: [] -security_sudoers_passwordless: - - "{{ main_username }}" -security_autoupdate_enabled: true -security_autoupdate_blacklist: [] -security_autoupdate_reboot: reboot -security_autoupdate_reboot_time: "03:00" -security_autoupdate_mail_to: "service@softbox.de" -security_autoupdate_mail_on_error: true -security_fail2ban_enabled: true -security_fail2ban_custom_configuration_template: "jail.local.j2" diff --git a/ansible/group_vars/phy-z-srv-cloud.yml b/ansible/group_vars/phy-z-srv-cloud.yml deleted file mode 100644 index 334e05a..0000000 --- a/ansible/group_vars/phy-z-srv-cloud.yml +++ /dev/null @@ -1,47 +0,0 @@ -# generic settings -main_username: sbxadmin -main_groupname: "{{ main_username }}" -main_uid: "1000" -main_gid: "{{ main_uid }}" - -# weareinteractive.environment -environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } - -global_env_vars: - - "PUID={{ main_uid }}" - - "PGID={{ main_gid }}" - - "TZ={{ ntp_timezone }}" - -# geerlingguy.ntp -ntp_timezone: "Europe/Berlin" - -# geerlingguy.nfs -#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] - -# geerlingguy.security -security_ssh_port: 22 -security_ssh_password_authentication: "yes" -security_ssh_permit_root_login: "no" -security_ssh_usedns: "no" -security_ssh_permit_empty_password: "no" -security_ssh_challenge_response_auth: "no" -security_ssh_gss_api_authentication: "no" -security_ssh_x11_forwarding: "no" -security_ssh_allowed_users: - - "{{ main_username }}" -security_ssh_allowed_groups: [] -security_sudoers_passwordless: - - "{{ main_username }}" -security_autoupdate_enabled: true -security_autoupdate_blacklist: [] -security_autoupdate_reboot: reboot -security_autoupdate_reboot_time: "03:00" -security_autoupdate_mail_to: "service@softbox.de" -security_autoupdate_mail_on_error: true -security_fail2ban_enabled: true -security_fail2ban_custom_configuration_template: "jail.local.j2" - -#cloud.phytron.de -hostname: cloud -php_version: 8.2 -domain_base: "phytron.de" diff --git a/ansible/group_vars/phy-z-srv-git.yml b/ansible/group_vars/phy-z-srv-git.yml deleted file mode 100644 index 07e4fdf..0000000 --- a/ansible/group_vars/phy-z-srv-git.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# generic settings -main_username: sbxadmin -main_groupname: "{{ main_username }}" -main_uid: "1000" -main_gid: "{{ main_uid }}" - -# weareinteractive.environment -environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } - -global_env_vars: - - "PUID={{ main_uid }}" - - "PGID={{ main_gid }}" - - "TZ={{ ntp_timezone }}" - -# geerlingguy.ntp -ntp_timezone: "Europe/Berlin" - -# geerlingguy.nfs -#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] - -# geerlingguy.security -security_ssh_port: 22 -security_ssh_password_authentication: "yes" -security_ssh_permit_root_login: "no" -security_ssh_usedns: "no" -security_ssh_permit_empty_password: "no" -security_ssh_challenge_response_auth: "no" -security_ssh_gss_api_authentication: "no" -security_ssh_x11_forwarding: "no" -security_ssh_allowed_users: - - "{{ main_username }}" -security_ssh_allowed_groups: [] -security_sudoers_passwordless: - - "{{ main_username }}" -security_autoupdate_enabled: true -security_autoupdate_blacklist: [] -security_autoupdate_reboot: reboot -security_autoupdate_reboot_time: "03:00" -security_autoupdate_mail_to: "service@softbox.de" -security_autoupdate_mail_on_error: true -security_fail2ban_enabled: true -security_fail2ban_custom_configuration_template: "jail.local.j2" diff --git a/ansible/group_vars/phy-z-srv-gpu01.yml b/ansible/group_vars/phy-z-srv-gpu01.yml deleted file mode 100644 index 07e4fdf..0000000 --- a/ansible/group_vars/phy-z-srv-gpu01.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# generic settings -main_username: sbxadmin -main_groupname: "{{ main_username }}" -main_uid: "1000" -main_gid: "{{ main_uid }}" - -# weareinteractive.environment -environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } - -global_env_vars: - - "PUID={{ main_uid }}" - - "PGID={{ main_gid }}" - - "TZ={{ ntp_timezone }}" - -# geerlingguy.ntp -ntp_timezone: "Europe/Berlin" - -# geerlingguy.nfs -#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] - -# geerlingguy.security -security_ssh_port: 22 -security_ssh_password_authentication: "yes" -security_ssh_permit_root_login: "no" -security_ssh_usedns: "no" -security_ssh_permit_empty_password: "no" -security_ssh_challenge_response_auth: "no" -security_ssh_gss_api_authentication: "no" -security_ssh_x11_forwarding: "no" -security_ssh_allowed_users: - - "{{ main_username }}" -security_ssh_allowed_groups: [] -security_sudoers_passwordless: - - "{{ main_username }}" -security_autoupdate_enabled: true -security_autoupdate_blacklist: [] -security_autoupdate_reboot: reboot -security_autoupdate_reboot_time: "03:00" -security_autoupdate_mail_to: "service@softbox.de" -security_autoupdate_mail_on_error: true -security_fail2ban_enabled: true -security_fail2ban_custom_configuration_template: "jail.local.j2" diff --git a/ansible/group_vars/phy-z-srv-jira.yml b/ansible/group_vars/phy-z-srv-jira.yml deleted file mode 100644 index 07e4fdf..0000000 --- a/ansible/group_vars/phy-z-srv-jira.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# generic settings -main_username: sbxadmin -main_groupname: "{{ main_username }}" -main_uid: "1000" -main_gid: "{{ main_uid }}" - -# weareinteractive.environment -environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } - -global_env_vars: - - "PUID={{ main_uid }}" - - "PGID={{ main_gid }}" - - "TZ={{ ntp_timezone }}" - -# geerlingguy.ntp -ntp_timezone: "Europe/Berlin" - -# geerlingguy.nfs -#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] - -# geerlingguy.security -security_ssh_port: 22 -security_ssh_password_authentication: "yes" -security_ssh_permit_root_login: "no" -security_ssh_usedns: "no" -security_ssh_permit_empty_password: "no" -security_ssh_challenge_response_auth: "no" -security_ssh_gss_api_authentication: "no" -security_ssh_x11_forwarding: "no" -security_ssh_allowed_users: - - "{{ main_username }}" -security_ssh_allowed_groups: [] -security_sudoers_passwordless: - - "{{ main_username }}" -security_autoupdate_enabled: true -security_autoupdate_blacklist: [] -security_autoupdate_reboot: reboot -security_autoupdate_reboot_time: "03:00" -security_autoupdate_mail_to: "service@softbox.de" -security_autoupdate_mail_on_error: true -security_fail2ban_enabled: true -security_fail2ban_custom_configuration_template: "jail.local.j2" diff --git a/ansible/group_vars/phy_z_dmz_sftp01.yml b/ansible/group_vars/phy_z_dmz_sftp01.yml new file mode 100644 index 0000000..cf5b1a1 --- /dev/null +++ b/ansible/group_vars/phy_z_dmz_sftp01.yml @@ -0,0 +1,5 @@ +--- +# overrides of group_vars/all.yml + +# geerlingguy.security — DMZ host: no SSH password login, keys only +security_ssh_password_authentication: "no" diff --git a/ansible/group_vars/phy_z_srv_cloud.yml b/ansible/group_vars/phy_z_srv_cloud.yml new file mode 100644 index 0000000..8b2cc23 --- /dev/null +++ b/ansible/group_vars/phy_z_srv_cloud.yml @@ -0,0 +1,4 @@ +#cloud.phytron.de +hostname: cloud +php_version: 8.2 +domain_base: "phytron.de" diff --git a/ansible/group_vars/phy_z_srv_git.yml b/ansible/group_vars/phy_z_srv_git.yml new file mode 100644 index 0000000..cd21505 --- /dev/null +++ b/ansible/group_vars/phy_z_srv_git.yml @@ -0,0 +1,2 @@ +--- + diff --git a/ansible/group_vars/phy_z_srv_gpu01.yml b/ansible/group_vars/phy_z_srv_gpu01.yml new file mode 100644 index 0000000..cd21505 --- /dev/null +++ b/ansible/group_vars/phy_z_srv_gpu01.yml @@ -0,0 +1,2 @@ +--- + diff --git a/ansible/group_vars/phy_z_srv_jira.yml b/ansible/group_vars/phy_z_srv_jira.yml new file mode 100644 index 0000000..cd21505 --- /dev/null +++ b/ansible/group_vars/phy_z_srv_jira.yml @@ -0,0 +1,2 @@ +--- + diff --git a/ansible/vars/vault.yml b/ansible/group_vars/secrets.yml similarity index 100% rename from ansible/vars/vault.yml rename to ansible/group_vars/secrets.yml diff --git a/ansible/hosts.ini b/ansible/hosts.ini index 5c9fa08..6f99166 100644 --- a/ansible/hosts.ini +++ b/ansible/hosts.ini @@ -1,15 +1,14 @@ -[phy-z-srv-jira] -192.168.66.41 ansible_user=sbxadmin ansible_port=22 +[phy_z_srv_jira] +phy-z-srv-jira ansible_host=192.168.66.41 -[phy-z-srv-cloud] -192.168.66.66 ansible_user=sbxadmin ansible_port=22 +[phy_z_srv_cloud] +phy-z-srv-cloud ansible_host=192.168.66.66 -[phy-z-srv-git] -192.168.66.67 ansible_user=sbxadmin ansible_port=22 +[phy_z_srv_git] +phy-z-srv-git ansible_host=192.168.66.67 -[phy-z-dmz-sftp01] -192.168.66.68 ansible_user=sbxadmin ansible_port=22 - -[phy-z-srv-gpu01] -192.168.66.69 ansible_user=sbxadmin ansible_port=22 +[phy_z_dmz_sftp01] +phy-z-dmz-sftp01 ansible_host=192.168.66.68 +[phy_z_srv_gpu01] +phy-z-srv-gpu01 ansible_host=192.168.66.69 diff --git a/ansible/run.yml b/ansible/run.yml index 96a82cf..be9ef07 100644 --- a/ansible/run.yml +++ b/ansible/run.yml @@ -1,25 +1,8 @@ --- -#- hosts: owncloud -# become: yes -# vars_files: -# - "vars/vault.yml" -# -# pre_tasks: -# - name: Update apt cache. -# apt: -# update_cache: true -# cache_valid_time: 3600 -# when: ansible_os_family == 'Debian' -# -# roles: -# - role: geerlingguy.security -# #- role: geerlingguy.ntp ## NEEDED? -# - role: owncloud - -- hosts: nextcloud +- hosts: phy_z_srv_cloud become: yes vars_files: - - "vars/vault.yml" + - "group_vars/secrets.yml" pre_tasks: - name: Update apt cache. @@ -35,10 +18,10 @@ tags: mail -- hosts: sftp +- hosts: phy_z_dmz_sftp01 become: yes vars_files: - - "vars/vault.yml" + - "group_vars/secrets.yml" pre_tasks: - name: Update apt cache. diff --git a/server/phy-z-dmz-sftp01/README.md b/server/phy-z-dmz-sftp01/README.md index e69de29..afee3af 100644 --- a/server/phy-z-dmz-sftp01/README.md +++ b/server/phy-z-dmz-sftp01/README.md @@ -0,0 +1,18 @@ +# phy-z-dmz-sftp01 + +SFTP server in the DMZ for file exchange with external partners. + +| | | +| - | - | +| IP | 192.168.66.68 | +| Ansible group | `phy_z_dmz_sftp01` | +| Status | configured | + +## Services + +- SFTP access for external users +- SSH password authentication is disabled (key-only), see `ansible/group_vars/phy_z_dmz_sftp01.yml` + +## Runbooks + +- [Add a new SFTP user](manuals/20260204-add-new-user.md) diff --git a/server/phy-z-srv-cloud/README.md b/server/phy-z-srv-cloud/README.md new file mode 100644 index 0000000..22e0c08 --- /dev/null +++ b/server/phy-z-srv-cloud/README.md @@ -0,0 +1,18 @@ +# phy-z-srv-cloud + +Nextcloud server (`cloud.phytron.de`) for file sync and sharing. + +| | | +| - | - | +| IP | 192.168.66.66 | +| Ansible group | `phy_z_srv_cloud` | +| Status | configured | + +## Services + +- Nextcloud on Apache/MySQL/PHP 8.2, deployed via the `nextcloud` Ansible role +- Mail (SMTP) configured via the `smtp_nextcloud` role (`--tags mail`) + +## Runbooks + +none yet diff --git a/server/phy-z-srv-git/README.md b/server/phy-z-srv-git/README.md index e69de29..8cb8e9e 100644 --- a/server/phy-z-srv-git/README.md +++ b/server/phy-z-srv-git/README.md @@ -0,0 +1,17 @@ +# phy-z-srv-git + +Git hosting server for internal repositories. + +| | | +| - | - | +| IP | 192.168.66.67 | +| Ansible group | `phy_z_srv_git` | +| Status | configured | + +## Services + + + +## Runbooks + +none yet diff --git a/server/phy-z-srv-gpu01/README.md b/server/phy-z-srv-gpu01/README.md index e69de29..2817013 100644 --- a/server/phy-z-srv-gpu01/README.md +++ b/server/phy-z-srv-gpu01/README.md @@ -0,0 +1,24 @@ +# phy-z-srv-gpu01 + +GPU server for AI/ML workloads. Hardware is ordered/assessed; OS setup and configuration are the next step. + +| | | +| - | - | +| IP | 192.168.66.69 (planned) | +| Ansible group | `phy_z_srv_gpu01` | +| Status | planned — not yet configured | + +## Hardware + +HPE ProLiant DL380 Gen12, 2× Intel Xeon 6714P (8-core, 4.0 GHz), 128 GB RAM, +NVIDIA RTX PRO 6000 96 GB, 2× 960 GB NVMe SSD, redundant PSU — full BOM in [HW.md](HW.md). + +## Documents + +- [Hardware assessment (2026-07-06)](20260706-hardware-assessment.md) +- [Software assessment (2026-07-06)](20260706-software-assessment.md) +- [Deep dive (2026-07-07)](20260707-deep-dive.md) + +## Runbooks + +none yet diff --git a/server/phy-z-srv-jira/README.md b/server/phy-z-srv-jira/README.md new file mode 100644 index 0000000..622eeee --- /dev/null +++ b/server/phy-z-srv-jira/README.md @@ -0,0 +1,17 @@ +# phy-z-srv-jira + +Atlassian Jira server for project and issue tracking. + +| | | +| - | - | +| IP | 192.168.66.41 | +| Ansible group | `phy_z_srv_jira` | +| Status | configured | + +## Services + + + +## Runbooks + +none yet