This template allows deploying a forgejo en either Scaleway or Hetzner (untested) without much knowledge about them. It DOES require knowledge about Terragrunt and ansible. A wizard of sorts is provided but it will not guarantee success without some knowledge about the underlying technology.
194 lines
5.4 KiB
YAML
194 lines
5.4 KiB
YAML
---
|
|
# System preparation tasks
|
|
|
|
- name: Update apt cache
|
|
ansible.builtin.apt:
|
|
update_cache: yes
|
|
cache_valid_time: 3600
|
|
become: yes
|
|
|
|
- name: Upgrade all packages
|
|
ansible.builtin.apt:
|
|
upgrade: safe
|
|
become: yes
|
|
tags:
|
|
- upgrade
|
|
|
|
- name: Install system packages
|
|
ansible.builtin.apt:
|
|
name: "{{ system_packages }}"
|
|
state: present
|
|
become: yes
|
|
|
|
- name: Check if Forgejo group exists
|
|
ansible.builtin.getent:
|
|
database: group
|
|
key: "{{ forgejo_group }}"
|
|
register: forgejo_group_check
|
|
ignore_errors: yes
|
|
become: yes
|
|
|
|
- name: Create Forgejo system group
|
|
ansible.builtin.group:
|
|
name: "{{ forgejo_group }}"
|
|
gid: "{{ forgejo_gid }}"
|
|
system: yes
|
|
state: present
|
|
become: yes
|
|
when: forgejo_group_check.failed | default(false)
|
|
|
|
- name: Ensure Forgejo group exists (if already created with different GID)
|
|
ansible.builtin.group:
|
|
name: "{{ forgejo_group }}"
|
|
system: yes
|
|
state: present
|
|
become: yes
|
|
when: not (forgejo_group_check.failed | default(false))
|
|
|
|
- name: Check if Forgejo user exists
|
|
ansible.builtin.getent:
|
|
database: passwd
|
|
key: "{{ forgejo_user }}"
|
|
register: forgejo_user_check
|
|
ignore_errors: yes
|
|
become: yes
|
|
|
|
- name: Create Forgejo system user
|
|
ansible.builtin.user:
|
|
name: "{{ forgejo_user }}"
|
|
uid: "{{ forgejo_uid }}"
|
|
group: "{{ forgejo_group }}"
|
|
system: yes
|
|
shell: /bin/bash
|
|
home: "{{ forgejo_base_path }}"
|
|
create_home: no
|
|
state: present
|
|
become: yes
|
|
when: forgejo_user_check.failed | default(false)
|
|
|
|
- name: Ensure Forgejo user exists (if already created with different UID)
|
|
ansible.builtin.user:
|
|
name: "{{ forgejo_user }}"
|
|
group: "{{ forgejo_group }}"
|
|
system: yes
|
|
shell: /bin/bash
|
|
home: "{{ forgejo_base_path }}"
|
|
create_home: no
|
|
state: present
|
|
become: yes
|
|
when: not (forgejo_user_check.failed | default(false))
|
|
|
|
- name: Create Forgejo directory structure
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: "{{ forgejo_user }}"
|
|
group: "{{ forgejo_group }}"
|
|
mode: '0755'
|
|
become: yes
|
|
loop:
|
|
- "{{ forgejo_base_path }}"
|
|
- "{{ forgejo_data_path }}"
|
|
- "{{ forgejo_config_path }}"
|
|
- "{{ forgejo_custom_path }}"
|
|
- "{{ forgejo_backup_path }}"
|
|
- "{{ forgejo_data_path }}/git"
|
|
- "{{ forgejo_data_path }}/attachments"
|
|
- "{{ forgejo_data_path }}/lfs"
|
|
- "{{ forgejo_data_path }}/avatars"
|
|
|
|
- name: Configure system limits for Forgejo
|
|
ansible.builtin.pam_limits:
|
|
domain: "{{ forgejo_user }}"
|
|
limit_type: "{{ item.limit_type }}"
|
|
limit_item: "{{ item.limit_item }}"
|
|
value: "{{ item.value }}"
|
|
become: yes
|
|
loop:
|
|
- { limit_type: 'soft', limit_item: 'nofile', value: '65535' }
|
|
- { limit_type: 'hard', limit_item: 'nofile', value: '65535' }
|
|
- { limit_type: 'soft', limit_item: 'nproc', value: '65535' }
|
|
- { limit_type: 'hard', limit_item: 'nproc', value: '65535' }
|
|
|
|
- name: Configure kernel parameters
|
|
ansible.builtin.sysctl:
|
|
name: "{{ item.name }}"
|
|
value: "{{ item.value }}"
|
|
state: present
|
|
reload: yes
|
|
become: yes
|
|
loop:
|
|
- { name: 'net.core.somaxconn', value: '1024' }
|
|
- { name: 'net.ipv4.tcp_max_syn_backlog', value: '2048' }
|
|
- { name: 'net.ipv4.ip_forward', value: '1' }
|
|
- { name: 'vm.swappiness', value: '10' }
|
|
- { name: 'fs.file-max', value: '65535' }
|
|
|
|
# NOTE: UFW firewall configuration is handled by ufw.yml
|
|
# We only set up minimal rules here for Docker access during deployment
|
|
# The full secure configuration (Tailscale-only SSH) is applied in ufw.yml
|
|
|
|
- name: Install UFW
|
|
ansible.builtin.apt:
|
|
name: ufw
|
|
state: present
|
|
become: yes
|
|
when: ansible_os_family == "Debian"
|
|
|
|
- name: Allow Docker network to access host services
|
|
community.general.ufw:
|
|
rule: allow
|
|
from_ip: 172.16.0.0/12
|
|
comment: "Allow Docker containers to access host services (PostgreSQL, etc.)"
|
|
become: yes
|
|
when: ansible_os_family == "Debian"
|
|
|
|
- name: Set timezone to UTC
|
|
community.general.timezone:
|
|
name: UTC
|
|
become: yes
|
|
|
|
- name: Enable automatic security updates
|
|
ansible.builtin.apt:
|
|
name: unattended-upgrades
|
|
state: present
|
|
become: yes
|
|
|
|
- name: Configure unattended upgrades
|
|
ansible.builtin.copy:
|
|
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
|
content: |
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"${distro_id}:${distro_codename}-security";
|
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
|
};
|
|
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
|
mode: '0644'
|
|
become: yes
|
|
|
|
- name: Ensure SSH is properly configured
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: "{{ item.regexp }}"
|
|
line: "{{ item.line }}"
|
|
state: present
|
|
validate: '/usr/sbin/sshd -t -f %s'
|
|
become: yes
|
|
loop:
|
|
- { regexp: '^PermitRootLogin', line: 'PermitRootLogin prohibit-password' }
|
|
- { regexp: '^PasswordAuthentication', line: 'PasswordAuthentication no' }
|
|
- { regexp: '^PubkeyAuthentication', line: 'PubkeyAuthentication yes' }
|
|
notify: Restart sshd
|
|
when: ansible_connection != 'local'
|
|
|
|
- name: Create systemd service for sshd
|
|
ansible.builtin.systemd:
|
|
name: sshd
|
|
enabled: yes
|
|
state: started
|
|
become: yes
|
|
when: ansible_connection != 'local'
|