commit 3e9668bad5f4f7456b19941c7bb7a57407b28dc7 Author: Javier Feliz Date: Sun Jul 6 12:05:05 2025 -0400 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..c22ba94 --- /dev/null +++ b/README.md @@ -0,0 +1,150 @@ +# Ansible Starter Kit + +Easy way for my homies to start up an ansible project for their homelab or local machine. + +# Prerequisites + +The ideal setup for a homelab is to have: + +- The same username/password in all vms/hosts so you don't have to type a different password for each host +- SSH key auth on each host so you don't have to type a password at all + +# Ansible basics + +I'll explain the basic units of an ansible project. For this example we're going to assume you want to mount +an NFS share in all your hosts. + +From bottom to top we have: + +## Tasks + +A task is the lowest unit in an ansible project. + +A task could be: + +- Creating a directory +- Installing an os package (curl, docker, nfs-common, etc) +- Starting a docker container + +### Examples + +```yml +- name: Add SSH key for remote user + ansible.posix.authorized_key: + user: javi + state: present + key: "{{ lookup('file', '/home/javi/.ssh/homelab_keypair_ed25519.pub') }}" +``` + +```yml +- name: Ensure NFS client is installed + ansible.builtin.package: + name: nfs-common + state: present + become: true +``` + +## Role + +A role is a self contained, re-usable unit that will give a meaningful result. Think of it like a class in a program. + +Roles have a list of tasks, as well as variables and files associated with those tasks. All contained in a folder. + +A role can look like: + +``` +roles/ + portainer/ + ├── defaults/ + │ └── main.yml # Default variables + ├── files/ + │ └── ... # Static files to be copied (e.g., configs, scripts) + ├── handlers/ + │ └── main.yml # Handlers (e.g., service restart) + ├── meta/ + │ └── main.yml # Role metadata (e.g., dependencies) + ├── tasks/ + │ └── main.yml # Main list of tasks to execute + ├── templates/ + │ └── ... # Jinja2 templates + ├── vars/ + │ └── main.yml # Non-overridable variables + └── README.md # Optional: Document what this role does + sshkey/ + ├── defaults/ + │ └── main.yml # Default variables + ├── files/ + │ └── ... # Static files to be copied (e.g., configs, scripts) + ├── handlers/ + │ └── main.yml # Handlers (e.g., service restart) + ├── meta/ + │ └── main.yml # Role metadata (e.g., dependencies) + ├── tasks/ + │ └── main.yml # Main list of tasks to execute + ├── templates/ + │ └── ... # Jinja2 templates + ├── vars/ + │ └── main.yml # Non-overridable variables + └── README.md # Optional: Document what this role does + +``` + +However, only the `defaults` and `tasks` subfolders and subsequent `main.yml` are required. Everything else is optional. + +A role can be: + +- Mounting a share +- Deploying a docker container with all its requirements like a database and mapped volumes + +# Playbook + +A playbook combines roles and task to create a final state in a host or group of hosts. + +A playbook can be: + +- Make sure all your hosts have sshkey auth, portainer, docker and an nfs share mounted. +- Deploy a suite of apps to a host or multiple hosts + +## Example + +```yml +--- +- name: Deploy apps to apps-1 node + hosts: apps + become: true + roles: + - role: apps/kan + vars: + port: 7070 + - role: apps/memos + vars: + port: 7071 + - role: apps/vaultwarden + vars: + port: 7072 + - role: apps/erugo + vars: + port: 7073 + - role: apps/tianji + vars: + port: 7074 + - role: apps/stirling-pdf o + vars: + port: 7075 + - role: apps/dumbware-todo + vars: + port: 7076 + pin: 8989 + - role: apps/dumbware-drop + vars: + port: 7077 + pin: "8989" +``` + +# Setup + +1. Clone this repo +2. Run `setup.sh` to set up the vault password and become password +3. Set up your hosts in `hosts.yml` +4. Start making your roles and playbooks + diff --git a/ansible.cfg b/ansible.cfg new file mode 100755 index 0000000..5b1a6e3 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = hosts.yml +roles_path = ./roles +vault_password_file = ~/.ansible-test diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100755 index 0000000..cd5cd56 --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,18 @@ +project_root: "{{ inventory_dir }}" # Useful hack for easier file paths +# Postgres +# If you have a main database instance all your +# services will use (which you should), put +# the info here so it's accessible to all +# your playbooks. +pg_host: 10.89.0.102 +pg_port: 5432 +pg_user: postgres +pg_password: password +# Sudo password for your servers +ansible_become_pass: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 35613633643566323866643465383731343764616539353330366339616433316565306637363062 + 6334333432303337643963616435333165303834333237320a636531363761383736356665613164 + 30616465666565383663626336383764636363303061363731653536313061386333666638326236 + 6264646466383539370a323961613564616665383435303161306163303038633864653631376665 + 3263 diff --git a/hosts.yml b/hosts.yml new file mode 100755 index 0000000..5ea82ad --- /dev/null +++ b/hosts.yml @@ -0,0 +1,11 @@ +--- +all: + children: + servers: + hosts: + proxpox_server_1: + ansible_host: 10.89.0.13 + vms: + hosts: + vm_1: + ansible_host: 10.89.0.101 diff --git a/playbooks/example.yml b/playbooks/example.yml new file mode 100644 index 0000000..d0cce9d --- /dev/null +++ b/playbooks/example.yml @@ -0,0 +1,6 @@ +--- +- name: Example playbook + hosts: vms + become: true + roles: + - role: server/sshkey \ No newline at end of file diff --git a/roles/server/ftp/defaults/main.yml b/roles/server/ftp/defaults/main.yml new file mode 100755 index 0000000..e69de29 diff --git a/roles/server/ftp/tasks/main.yml b/roles/server/ftp/tasks/main.yml new file mode 100755 index 0000000..a710115 --- /dev/null +++ b/roles/server/ftp/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: Update apt cache + ansible.builtin.apt: + update_cache: true + +- name: Install proftpd package + ansible.builtin.apt: + name: proftpd + state: present + +- name: Ensure proftpd is enabled and started + ansible.builtin.service: + name: proftpd + state: started + enabled: true + become: true + +- name: Allow FTP through UFW firewall (if UFW is enabled) + community.general.ufw: + rule: allow + port: 21 + proto: tcp + ignore_errors: false \ No newline at end of file diff --git a/roles/server/sshkey/defaults/main.yml b/roles/server/sshkey/defaults/main.yml new file mode 100755 index 0000000..e69de29 diff --git a/roles/server/sshkey/tasks/main.yml b/roles/server/sshkey/tasks/main.yml new file mode 100755 index 0000000..fbb2fa0 --- /dev/null +++ b/roles/server/sshkey/tasks/main.yml @@ -0,0 +1,6 @@ +--- +- name: Add SSH key for remote user + ansible.posix.authorized_key: + user: javi + state: present + key: "{{ lookup('file', '/home/javi/.ssh/homelab_keypair_ed25519.pub') }}" \ No newline at end of file diff --git a/roles/server/webmin/defaults/main.yml b/roles/server/webmin/defaults/main.yml new file mode 100755 index 0000000..3dfd68b --- /dev/null +++ b/roles/server/webmin/defaults/main.yml @@ -0,0 +1,8 @@ +# roles/webmin/defaults/main.yml +webmin_repo_url: https://download.webmin.com +webmin_dist: stable +webmin_section: contrib + +# Optional HTTP auth +webmin_auth_user: javi +webmin_auth_pass: password diff --git a/roles/server/webmin/tasks/main.yml b/roles/server/webmin/tasks/main.yml new file mode 100755 index 0000000..fa4d5a8 --- /dev/null +++ b/roles/server/webmin/tasks/main.yml @@ -0,0 +1,66 @@ +--- +- name: Remove any old/malformed Webmin sources list + ansible.builtin.file: + path: /etc/apt/sources.list.d/webmin.list + state: absent + +- name: Remove any old Webmin keyring + ansible.builtin.file: + path: /usr/share/keyrings/webmin-archive-keyring.gpg + state: absent + +- name: Install Webmin GPG key into its own keyring + ansible.builtin.apt_key: + url: https://download.webmin.com/developers-key.asc + keyring: /usr/share/keyrings/webmin-archive-keyring.gpg + state: present + +- name: Add Webmin APT repository + ansible.builtin.apt_repository: + filename: webmin + repo: >- + deb [signed-by=/usr/share/keyrings/webmin-archive-keyring.gpg] + https://download.webmin.com/download/repository + sarge contrib + state: present + +- name: Ensure apt prerequisites are installed + ansible.builtin.apt: + name: + - curl + - gnupg + - apt-transport-https + - ca-certificates + state: present + update_cache: true + +- name: Configure APT HTTP auth for Webmin + when: webmin_auth_user is defined and webmin_auth_pass is defined + ansible.builtin.copy: + dest: /etc/apt/auth.conf.d/webmin.conf + mode: '0600' + content: | + machine {{ webmin_repo_url | regex_replace('^https?://','') }} + login {{ webmin_auth_user }} + password {{ webmin_auth_pass }} + +- name: Remove old Webmin preference file + ansible.builtin.file: + path: /etc/apt/preferences.d/webmin-stable-package-priority + state: absent + +- name: Refresh apt cache + ansible.builtin.apt: + update_cache: true + +- name: Install Webmin + ansible.builtin.apt: + name: + - webmin + state: present + +- name: Ensure Webmin service is enabled & started + ansible.builtin.service: + name: webmin + state: started + enabled: true diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..726b131 --- /dev/null +++ b/setup.sh @@ -0,0 +1,28 @@ +echo "**Deleting .git so you can start your own repo" +rm -rf .git +echo "***Ansible vault password***" +echo "This is used to encrypt/descrypt secrets in your vault" +echo "We'll save it to a file in ~/.[file name] so it doesn't have to be typed every time" +echo +read -p "File name (no . prefix): " ansible_vault_pass_filename +read -s -p "Password: " ansible_vault_pass + +echo $ansible_vault_pass >~/.$ansible_vault_pass_filename +echo "vault_password_file = ~/.$ansible_vault_pass_filename" >>ansible.cfg + +echo +echo + +echo "***Ansible become password***" +echo "A lot of actions need sudo. This password will be stored in group_vars/all.yml encrypted" +read -s -p "Password: " ansible_become_pass +echo "# Sudo password for your servers" >>./group_vars/all.yml +ansible-vault encrypt_string "$ansible_become_pass" --name 'ansible_become_pass' >>./group_vars/all.yml + +echo +echo + +echo "Setup complete" +echo "You can delete setup.sh since running it again would cause issues" +echo "Config for vault password was output to ./ansible.cfg" +echo "Config for sudo (become) password was output to ./group_vars/all.yml"