128 lines
3.2 KiB
YAML
128 lines
3.2 KiB
YAML
---
|
|
# Disable cloud-init so it never regenerates SSH keys or resets config on reboot
|
|
- name: Disable cloud-init
|
|
ansible.builtin.file:
|
|
path: /etc/cloud/cloud-init.disabled
|
|
state: touch
|
|
mode: "0644"
|
|
|
|
- name: Find active cloud-init services
|
|
ansible.builtin.shell: systemctl list-unit-files 'cloud-*' --no-legend | awk '{print $1}'
|
|
register: cloud_init_services
|
|
changed_when: false
|
|
|
|
- name: Stop cloud-init services
|
|
ansible.builtin.service:
|
|
name: "{{ item }}"
|
|
state: stopped
|
|
enabled: false
|
|
loop: "{{ cloud_init_services.stdout_lines }}"
|
|
when: cloud_init_services.stdout_lines | length > 0
|
|
|
|
# Set the hostname to match our inventory name
|
|
- name: Set hostname
|
|
ansible.builtin.hostname:
|
|
name: "{{ server_hostname }}"
|
|
|
|
# Update /etc/hosts to include the new hostname
|
|
- name: Update /etc/hosts with hostname
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/hosts
|
|
regexp: '^127\.0\.1\.1'
|
|
line: "127.0.1.1 {{ server_hostname }}.{{ domain }} {{ server_hostname }}"
|
|
state: present
|
|
|
|
# Refresh apt cache before installing anything
|
|
- name: Update apt cache
|
|
ansible.builtin.apt:
|
|
update_cache: true
|
|
cache_valid_time: 3600
|
|
|
|
# Upgrade all installed packages to latest
|
|
- name: Upgrade all packages
|
|
ansible.builtin.apt:
|
|
upgrade: dist
|
|
autoremove: true
|
|
|
|
# Install essential tools and security packages
|
|
- name: Install base packages
|
|
ansible.builtin.apt:
|
|
name:
|
|
- curl
|
|
- git
|
|
- htop
|
|
- rsync
|
|
- ufw
|
|
- fail2ban
|
|
- unattended-upgrades
|
|
- apt-listchanges
|
|
state: present
|
|
|
|
# Allow SSH before enabling the firewall (don't lock ourselves out)
|
|
- name: UFW — allow SSH
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "22"
|
|
proto: tcp
|
|
|
|
# Allow HTTP for Caddy
|
|
- name: UFW — allow HTTP
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "80"
|
|
proto: tcp
|
|
|
|
# Allow HTTPS for Caddy
|
|
- name: UFW — allow HTTPS
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "443"
|
|
proto: tcp
|
|
|
|
# Allow Gitea SSH
|
|
- name: UFW — allow Gitea SSH
|
|
community.general.ufw:
|
|
rule: allow
|
|
port: "2222"
|
|
proto: tcp
|
|
|
|
# Default deny incoming, allow outgoing, then enable
|
|
- name: UFW — enable with default deny incoming
|
|
community.general.ufw:
|
|
state: enabled
|
|
default: deny
|
|
direction: incoming
|
|
|
|
- name: UFW — default allow outgoing
|
|
community.general.ufw:
|
|
default: allow
|
|
direction: outgoing
|
|
|
|
# Enable automatic security updates
|
|
- name: Enable unattended-upgrades
|
|
ansible.builtin.copy:
|
|
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
|
content: |
|
|
APT::Periodic::Update-Package-Lists "1";
|
|
APT::Periodic::Unattended-Upgrade "1";
|
|
APT::Periodic::AutocleanInterval "7";
|
|
mode: "0644"
|
|
|
|
# Disable root password login — key-only auth
|
|
- name: Disable SSH password authentication
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: '^#?PasswordAuthentication'
|
|
line: 'PasswordAuthentication no'
|
|
state: present
|
|
notify: Restart sshd
|
|
|
|
# Disable root login via password (permit key-based only)
|
|
- name: Set SSH to permit root login with key only
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: '^#?PermitRootLogin'
|
|
line: 'PermitRootLogin prohibit-password'
|
|
state: present
|
|
notify: Restart sshd
|