Compare commits

..

18 Commits

Author SHA1 Message Date
d88a9d6176 fix: playbook task already has access to inventory-level variables 2025-12-16 13:48:33 -05:00
c39463f4a7 feature: added a set of default path environment variables to be used as part of execution environment 2025-12-16 13:47:47 -05:00
474574860a fix: changed from dot notation to bracket notation for attr/meth access 2025-12-16 13:44:10 -05:00
645d815413 fix: removed some unnecessary escape characters, added title for installation section, added links to Gitea Wiki 2025-12-16 12:52:05 -05:00
3c3f7cbf1d fix: edited typos and added more exposition for the role scope section 2025-12-15 10:22:58 -05:00
e175e41810 Filled in role metadata and placed in dependencies 2025-12-15 10:12:08 -05:00
3040a6203d Added task for adding essential documentation on Ansible inventory file naming conventions 2025-12-15 10:10:45 -05:00
29bd8090be Rewrote README to reflect refactored and rewritten Ansible project, and essential information 2025-12-15 10:08:23 -05:00
40bbe62203 removed Podman post-installation handlers as containers will no longer be managed via Ansible 2025-12-07 21:35:53 -05:00
cb69a9b430 removed a list of container software due to separate repo handling this via Compose files 2025-12-07 21:34:43 -05:00
19f1681473 Added containers to software dictionary list 2025-12-01 21:11:39 -05:00
5e5dabff1a Added the creation of symbolic links to Nextcloud snap binaries for Nextcloud 2025-12-01 19:20:06 -05:00
d4aa128e4c Added configuration value related to setting default phone region for Nextcloud 2025-12-01 18:59:31 -05:00
512c7a82e5 Added default phone region for accepting phone numbers, and overwrote URLs for Nextcloud 2025-12-01 18:58:07 -05:00
6c4c3d0794 Added ClamAV and ClamAV SystemD daemon package installations 2025-11-30 14:54:25 -05:00
5a75942336 Created handler for podman installation that installs containers 2025-11-30 14:53:27 -05:00
dd463297dd Added TODOs for this handler 2025-11-30 14:52:09 -05:00
a1bc0ae727 Created systemd user unit service file for Aria2 2025-11-18 21:47:11 -05:00
11 changed files with 149 additions and 74 deletions

View File

@@ -1,25 +1,39 @@
# SUKAATO Ansible # SUKAATO Ansible
This repository is for automating the management of the configuration of, and the provisioning of software for, my virtual private servers using [Ansible](https://www.redhat.com/en/ansible-collaborative?intcmp=7015Y000003t7aWQAQ). This repository is especially useful for setting up the virtual private server(s) that is(/are) to host and serve my website(s). It is also meant to be useful for provisioning of software and the configuration of that software for personal or household LAN computers. This repository is for automating the management of the configuration of, and the provisioning of software for, my virtual private servers using [Ansible](https://www.redhat.com/en/ansible-collaborative?intcmp=7015Y000003t7aWQAQ). It's main purpose is to spin up the VPSs, create initial users and groups, import SSH or GPG keys, lock down SSH access or harden SSH, and then install and configure packages available to the given package manager of the operating system. The `bootstrap` role in here serves to abstract some of these tasks for our main playbook files.
## Installation and Use ## Variable Names and Their Scopes
All files with file extension `.example` must be converted to [YAML](https://yaml.org/) files that follow their semantics and naming (or follow the minimum bare "namespace" nesting for dictionaries or lists thereof) *prior* to executing any given [play or task](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html). For more on semantics and naming conventions see the [mini-documentation](#mini-documentation). To be able to make use of the Ansible playbooks, it is necessary to specify some variables in or at relevant scopes, though some may have some defaults. The relevant scopes variables are defined in, for our purposes, are:
> [!IMPORTANT] - Ansible **inventory scope**: corresponds to variables inside per-hostname files in `group_vars` or `host_vars` directories, or the inventory file itself, i.e. `hosts.ini` or `hosts.yml`. The inventory file has some enforced naming conventions to be covered later or elsewhere.
> Keep in mind files with the `.example` extension may also be present recursively under given [role](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html) directories (i.e., under path `${SUKAATO_ANSIBLE_PROJECT}/.ansible/roles/**/**/`). - Ansible **role scope**: corresponds to variables found in files inside the `defaults` / `vars` directory in a role directory, or variables found in files inside subdirectory `main` in either `defaults` or `vars` directory of that role directory. There are favored conventional directory structures within which these variables are specified in the aforementioned directories, to be covered later or elsewhere.
## Mini-Documentation Other variables that tend to have default definitions as is but that may be of interest are those found in Jinja templates of roles, in this case of the role `bootstrap`. Look through the `bootstrap` role's `templates` directory and you will discover them--most of them defined in role tasks or handlers that make reference to them. However, more information may be found elsewhere.
### Available Roles ### Inventory Scope
To surmise, the available or planned [roles](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html) are as follows (and are all found under `${SUKAATO_ANSIBLE_PROJECT}/.ansible/roles`): Herein are listed the relevant variables at or in the *inventory* scope. These must be specified for a specific inventory host or group, typically in their corresponding files under `group_vars` or `host_vars`. Some variables must take in a dictionary type to be valid. To save space, there will be more detail on what keys are required or optional for such dictionaries [elsewhere](https://git.sukaato.moe/admin/skato-ansible/wiki/Inventory-Scope) and not here.
role name | purpose name | type | value validity rule
---|--- ---|---|---
lockdown | creating initial `sudo`-capable user, disabling system/SSH root login, setting up key-based SSH authentication, transferring GPG keys, configuring environment, hardening system `fqdn` | `<str>` | fully qualified domain name
bootstrap | installing programming language and server/container packages, installing extra system managers and essential utilities, configuring and running servers/services/containers `vps_service` | `<dict{<str>:<str\|bool\|list>}>` | valid fields providing data for spinning up new VPS
postinstall | installing and configuring custom sets of packages, largely non-server related and not essential `groups` | `<dict{$group_name:<dict>}>` | fields/keys that are group names with data configuring that group
`users` | `<dict{$user_name:<dict>}>` | fields/keys that are user names with data configuring that user
`keywords` | `<list[<str>]>` | strings that describe the VPS, useful for applying tags if allowed by API
`custom_vars` | `<dict{<str>:<any>}>` | your own custom variables, though there are some reserved variable names for this namespace
### Role Scope
Herein are listed the relevant variables at or in the *role* scope. These must be specified for a set of role tasks expected to run in a playbook for the host specified for its play. Some variables must take in a dictionary type to be valid. To save space, there will be more detail on what keys are required or optional for such dictionaries [elsewhere](https://git.sukaato.moe/admin/skato-ansible/wiki/Role-Scope) and not here.
name | type | value validity rule
---|---|---
`software` | `<dict{<str>:<dict>}>` | valid fields providing data for software installations
`config` | `<dict{$software_name:<dict>}>` | software name fields providing data for configuring that software
## Installation
> **TBC** > **TBC**
> This README is yet unfinished. Check back later. > This README is yet unfinished and unverified. Check back later.

View File

@@ -2,7 +2,7 @@
--- ---
# vars file # vars file
custom_vars: custom_vars:
generality: shared:
ssh_authorized_keys: ssh_authorized_keys:
- sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIO0sbFLwfgSWpWwn4cy4cddKvV74efUMZVYTTjX2vnjAAAABHNzaDo= rika@hikiki - sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIO0sbFLwfgSWpWwn4cy4cddKvV74efUMZVYTTjX2vnjAAAABHNzaDo= rika@hikiki
- sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHJqHHMplgqm8yiq4Qwisk67p9+f9sLM8tIAzuw2qkwpAAAABHNzaDo= rika@hikiki - sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHJqHHMplgqm8yiq4Qwisk67p9+f9sLM8tIAzuw2qkwpAAAABHNzaDo= rika@hikiki
@@ -56,6 +56,7 @@ groups:
remote: remote:
group_name: remote group_name: remote
type: system type: system
id: ~
users: users:
# @NOTE key/field names MUST match value of 'username' key or field of its object # @NOTE key/field names MUST match value of 'username' key or field of its object
senpai: senpai:
@@ -81,8 +82,8 @@ users:
- sudo - sudo
- "{{ groups.remote.group_name }}" - "{{ groups.remote.group_name }}"
services: [sshd] services: [sshd]
ssh_authorized_keys: "{{ custom_vars.generality.ssh_authorized_keys }}" ssh_authorized_keys: "{{ custom_vars['shared']['ssh_authorized_keys'] }}"
ssh_private_key_paths: "{{ custom_vars.generality.ssh_private_key_paths }}" ssh_private_key_paths: "{{ custom_vars['shared']['ssh_private_key_paths'] }}"
ssh_private_key_path_pref: 0 ssh_private_key_path_pref: 0
gpg_keys: gpg_keys:
- id: 558041D5CF2AB23B # @NOTE professional - id: 558041D5CF2AB23B # @NOTE professional
@@ -128,8 +129,8 @@ users:
groups: groups:
- "{{ groups.remote.group_name }}" - "{{ groups.remote.group_name }}"
services: [proftpd,sftp,ftps] services: [proftpd,sftp,ftps]
ssh_authorized_keys: "{{ custom_vars.generality.ssh_authorized_keys }}" ssh_authorized_keys: "{{ custom_vars['shared']['ssh_authorized_keys'] }}"
ssh_private_key_paths: "{{ custom_vars.generality.ssh_private_key_paths }}" ssh_private_key_paths: "{{ custom_vars['shared']['ssh_private_key_paths'] }}"
ssh_private_key_path_pref: 0 ssh_private_key_path_pref: 0
gpg_keys: [] gpg_keys: []
gpg_keyid_pref: 0 gpg_keyid_pref: 0

6
init_env Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
SKATO_ANSIBLE_ROOT=$(dirname "$0")
set -o allexport
source "${SKATO_ANSIBLE_ROOT}/standard_paths"
set +o allexport

View File

@@ -13,7 +13,7 @@
private_ip: true private_ip: true
region: "{{ vps_service.region }}" region: "{{ vps_service.region }}"
root_pass: "{{ vps_service.password }}" root_pass: "{{ vps_service.password }}"
tags: "{{ hostvars[inventory_hostname].keywords }}" tags: "{{ keywords }}"
state: "{{ 'present' if vps_service.exists else 'absent' }}" state: "{{ 'present' if vps_service.exists else 'absent' }}"
tags: tags:
- vps_step - vps_step

View File

@@ -17,10 +17,6 @@
# @TODO see if setting below is necessary given use of reverse proxy # @TODO see if setting below is necessary given use of reverse proxy
- name: Set trusted domains - name: Set trusted domains
block: block:
- name: Set localhost as trusted domain
ansible.builtin.command:
cmd: "/snap/bin//snap/bin/nextcloud.occ config:system:set trusted_domains 0 --value='localhost'"
# @TODO see if setting below is necessary given use of reverse proxy
- name: Set FQDN as trusted domain - name: Set FQDN as trusted domain
ansible.builtin.command: ansible.builtin.command:
cmd: "/snap/bin//snap/bin/nextcloud.occ config:system:set trusted_domains 1 --value='cloud.{{ hostvars[inventory_hostname].fqdn }}'" cmd: "/snap/bin//snap/bin/nextcloud.occ config:system:set trusted_domains 1 --value='cloud.{{ hostvars[inventory_hostname].fqdn }}'"
@@ -28,6 +24,7 @@
- name: Set trusted reverse proxy addresses - name: Set trusted reverse proxy addresses
block: block:
- name: Set trusted reverse proxy IPv4 address based on hostname - name: Set trusted reverse proxy IPv4 address based on hostname
# @TODO create config.trusted_revproxy_ips data structure in bootstrap role's vars dir--may include loopback addresses
when: config.trusted_revproxy_ips.ipv4 is None or len(config.trusted_revproxy_ips.ipv4) < 1 when: config.trusted_revproxy_ips.ipv4 is None or len(config.trusted_revproxy_ips.ipv4) < 1
ansible.builtin.command: ansible.builtin.command:
argv: argv:
@@ -65,4 +62,44 @@
loop: "{{ config.trusted_revproxy_ips.ipv6 }}" loop: "{{ config.trusted_revproxy_ips.ipv6 }}"
loop_control: loop_control:
index_var: idx index_var: idx
# @TODO create task based on shell command `sudo /snap/bin/nextcloud.occ config:system:set default_phone_region --value="US"`
- name: Set default phone region
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- default_phone_region
- "--value={{ config.nextcloud.phone_region }}"
# @TODO create task based on shell command:
# `sudo /snap/bin/nextcloud.occ config:system:set overwrite.cli.url --value="https://cloud.{{ fqdn }}"` for Caddy task
- name: Set overwrite CLI URL
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- overwrite.cli.url
- "--value=cloud.{{ hostvars[inventory_hostname].fqdn }}"
# @TODO create task based on shell command `sudo /snap/bin/nextcloud.occ config:system:set overwriteprotocol --value="https"` for Caddy task
- name: Overwrite protocol
ansible.builtin.command:
argv:
- /snap/bin/nextcloud.occ
- "config:system:set"
- overwriteprotocol
- --value="https"
# @TODO create system-level bash alias for `/snap/bin/nextcloud.occ` command # @TODO create system-level bash alias for `/snap/bin/nextcloud.occ` command
- name: Get Nextcloud snap binaries
ansible.builtin.find:
paths:
- /snap/bin
patterns:
- nextcloud\..*
recurse: false
use_regex: true
register: nextcloud_snap_binaries
- name: Create symbolic links for Nextcloud snap binaries
ansible.builtin.file:
dest: "/usr/sbin/{{ item.path | basename }}"
src: "{{ item.path }}"
state: link
loop: "{{ nextcloud_snap_binaries.files }}"

View File

@@ -1,13 +0,0 @@
# SPDX-License-Identifier: MIT-0
---
# handlers file for bootstrap
- name: Pull podman images
listen: rsync
block:
- name: Pull container images via podman
containers.podman.podman_image:
name: "{{ item.value['name'] }}"
tag: "{{ item.value['tag'] | default('latest') }}"
state: present
notify: "{{ item.key }}"
loop: "{{ lookup('ansible.builtin.dict', software.containers) }}"

View File

@@ -1,12 +1,9 @@
#SPDX-License-Identifier: MIT-0 # SPDX-License-Identifier: MIT-0
galaxy_info: galaxy_info:
author: your name author: Alex Tavarez
description: your role description description: A role that aids in the deployment and bootstrapping of a new VPS.
company: your company (optional) company: SUKAATO
issue_tracker_url: https://git.sukaato.moe/admin/skato-ansible/issues
# If the issue tracker for your role is not on github, uncomment the
# next line and provide a value
# issue_tracker_url: http://example.com/issue/tracker
# Choose a valid license ID from https://spdx.org - some suggested licenses: # Choose a valid license ID from https://spdx.org - some suggested licenses:
# - BSD-3-Clause (default) # - BSD-3-Clause (default)
@@ -16,20 +13,13 @@ galaxy_info:
# - Apache-2.0 # - Apache-2.0
# - CC-BY-4.0 # - CC-BY-4.0
license: license (GPL-2.0-or-later, MIT, etc) license: license (GPL-2.0-or-later, MIT, etc)
min_ansible_version: "2.1"
galaxy_tags:
- sukaato
- vps
- server
- web
min_ansible_version: 2.1 dependencies:
- community.general
# If this a Container Enabled role, provide the minimum Ansible Container version. # - containers.podman
# min_ansible_container_version:
galaxy_tags: []
# List tags for your role here, one per line. A tag is a keyword that describes
# and categorizes the role. Users find roles by searching for tags. Be sure to
# remove the '[]' above, if you add tags to this list.
#
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
# Maximum 20 tags per role.
dependencies: []
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
# if you add dependencies to this list.

View File

@@ -0,0 +1,13 @@
[Unit]
Description=aria2 Daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/aria2c --conf-path={{ ansible_facts['user_dir'] }}/.config/aria2/aria2.conf
ExecReload=/usr/bin/kill -HUP $MAINPID
RestartSec=1min
Restart=on-failure
[Install]
WantedBy=default.target

View File

@@ -193,13 +193,14 @@ software:
proftpd-mod-crypto: proftpd-mod-crypto:
name: name:
apt: proftpd-mod-crypto apt: proftpd-mod-crypto
# proftpd-mod-ldap: # @TODO write configuration files and handler for below two package installations
# name: # based on:
# apt: proftpd-mod-ldap clamav:
# @TODO manually install the commented below on current active new VPS, then uncomment name:
# proftpd-mod-clamav: apt: clamav
# name: clamd:
# apt: proftpd-mod-clamav name:
apt: clamav-daemon
proftpd: proftpd:
name: name:
apt: proftpd apt: proftpd
@@ -211,7 +212,7 @@ software:
apt: rsync apt: rsync
# rclone: # rclone:
# name: # name:
# apt: rsync # apt: rclone
aria: aria:
name: name:
apt: aria2 apt: aria2
@@ -235,10 +236,6 @@ software:
- "nextcloud:ports.http=81" - "nextcloud:ports.http=81"
# @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-domains-configuration-8 # @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-domains-configuration-8
# @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-proxy-configuration-9 # @TODO see how to set these options: https://help.nextcloud.com/t/how-to-configure-nextcloud-snap/216036#p-649442-trusted-proxy-configuration-9
containers:
ariang:
name: https://docker.io/p3terx/ariang
tag: latest
links: links:
quartz: quartz:
name: quartz name: quartz
@@ -293,6 +290,7 @@ config:
username: admin username: admin
# @TODO change this password to ansible-vaulted actual choice password later # @TODO change this password to ansible-vaulted actual choice password later
password: password123 # @NOTE placeholder password: password123 # @NOTE placeholder
phone_region: US
aria: aria:
checksum: ~ checksum: ~
secret: ~ secret: ~

28
standard_paths Normal file
View File

@@ -0,0 +1,28 @@
# SKATO_ANSIBLE_ROOT=
# Relative directory paths for role templates/files
SKANSIBLE_ARIA="aria2"
SKANSIBLE_PROFTPD="proftpd"
SKANSIBLE_PROFTPD_CONFS="${SKANSIBLE_PROFTPD}/conf.d"
# @NOTE below 4 filepaths have filenames that must correspond to
# the filenames in role ProFTPd templates'/files' Display settings
SKANSIBLE_PROFTPD_CONFS_WELCOME="${SKANSIBLE_PROFTPD}/conf.d/WELCOME.txt"
SKANSIBLE_PROFTPD_CONFS_BANNER="${SKANSIBLE_PROFTPD}/conf.d/BANNER.txt"
SKANSIBLE_PROFTPD_CONFS_SUCCESS="${SKANSIBLE_PROFTPD}/conf.d/SUCCESS.txt"
SKANSIBLE_PROFTPD_CONFS_EXIT="${SKANSIBLE_PROFTPD}/conf.d/BYE.txt"
SKANSIBLE_SSHD_CONFS="sshd_config.d"
SKANSIBLE_SYSTEMD="systemd"
SKANSIBLE_SYSTEMD_USER_UNITS="${SKANSIBLE_SYSTEMD}/user"
SKANSIBLE_FAIL2BAN="fail2ban"
SKANSIBLE_FAIL2BAN_JAILS="${SKANSIBLE_FAIL2BAN}/jail.d"
SKANSIBLE_FAIL2BAN_FILTERS="${SKANSIBLE_FAIL2BAN}/filter.d"
SKANSIBLE_GITCONFIG_CONFS="gitconfig.d"
# @NOTE files in here must have extension "key" with IDs in
# "gpg_keys" inventory variable list as basenames.
SKANSIBLE_GPG="gnupg"
# @NOTE files in path below must have extensions "key" (private),
# "crt" (signed), or "pem" (public) with inventory host FQDN as basename
SKANSIBLE_SSL="ca-certificates"
# Other directories
SKANSIBLE_SECRETS="${SKATO_ANSIBLE_ROOT}/.secrets"

View File

@@ -3,6 +3,7 @@
#+language: en #+language: en
* PLANNED * PLANNED
** TODO [#A] Write documentation on the expected conventional names to be used in the inventory file
** TODO [#A] Rewrite dot notation usage of keys for accessing values in custom dictionary variables to bracket notation usage of keys across whole project ** TODO [#A] Rewrite dot notation usage of keys for accessing values in custom dictionary variables to bracket notation usage of keys across whole project
* IN PROGRESS * IN PROGRESS