fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
- Remove middleware reference from Gitea Traefik labels (caused routing issues) - Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s) - Add explicit service reference in Traefik labels - Fix intermittent 504 timeouts by improving PostgreSQL connection handling Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
350
deployment/ansible/playbooks/initial-server-setup.yml
Normal file
350
deployment/ansible/playbooks/initial-server-setup.yml
Normal file
@@ -0,0 +1,350 @@
|
||||
---
|
||||
- name: Initial Server Setup - Debian 13 (Trixie)
|
||||
hosts: production
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
# User configuration
|
||||
deploy_user: "{{ ansible_user | default('deploy') }}"
|
||||
deploy_user_groups: ['sudo'] # docker group added after Docker installation
|
||||
|
||||
# SSH configuration
|
||||
ssh_key_only_auth: false # Set to true AFTER SSH keys are properly configured
|
||||
ssh_disable_root_login: false # Set to true after deploy user is configured
|
||||
|
||||
# Firewall configuration
|
||||
firewall_enable: false # Set to true after initial setup is complete
|
||||
firewall_ports:
|
||||
- { port: 22, proto: 'tcp', comment: 'SSH' }
|
||||
- { port: 80, proto: 'tcp', comment: 'HTTP' }
|
||||
- { port: 443, proto: 'tcp', comment: 'HTTPS' }
|
||||
- { port: 51820, proto: 'udp', comment: 'WireGuard' }
|
||||
|
||||
# System packages
|
||||
system_base_packages:
|
||||
- curl
|
||||
- wget
|
||||
- git
|
||||
- vim
|
||||
- sudo
|
||||
- ufw
|
||||
- fail2ban
|
||||
- rsync
|
||||
|
||||
tasks:
|
||||
- name: Display system information
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Distribution: {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
- "Hostname: {{ ansible_hostname }}"
|
||||
- "Deploy User: {{ deploy_user }}"
|
||||
|
||||
# ========================================
|
||||
# 1. System Updates
|
||||
# ========================================
|
||||
|
||||
- name: Check and wait for apt locks to be released
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
for lock in /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock; do
|
||||
if [ -f "$lock" ]; then
|
||||
echo "Waiting for lock: $lock"
|
||||
count=0
|
||||
while [ -f "$lock" ] && [ $count -lt 60 ]; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
if [ -f "$lock" ]; then
|
||||
echo "Warning: Lock still exists after 60s: $lock"
|
||||
else
|
||||
echo "Lock released: $lock"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
timeout: 70
|
||||
|
||||
- name: Update apt cache
|
||||
ansible.builtin.shell:
|
||||
cmd: timeout 300 apt-get update -qq
|
||||
environment:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
APT_LISTCHANGES_FRONTEND: none
|
||||
register: apt_update_result
|
||||
changed_when: apt_update_result.rc == 0
|
||||
failed_when: apt_update_result.rc != 0
|
||||
timeout: 300
|
||||
|
||||
- name: Display apt update result
|
||||
ansible.builtin.debug:
|
||||
msg: "apt update completed successfully"
|
||||
when: apt_update_result.rc == 0
|
||||
|
||||
- name: Show packages to be upgraded
|
||||
ansible.builtin.command:
|
||||
cmd: apt list --upgradable 2>/dev/null | tail -n +2 | wc -l
|
||||
register: packages_to_upgrade
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display upgrade information
|
||||
ansible.builtin.debug:
|
||||
msg: "Packages to upgrade: {{ packages_to_upgrade.stdout | default('0') | trim }}"
|
||||
|
||||
- name: Upgrade system packages
|
||||
ansible.builtin.shell:
|
||||
cmd: timeout 600 apt-get upgrade -y -qq && apt-get autoremove -y -qq
|
||||
environment:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
APT_LISTCHANGES_FRONTEND: none
|
||||
register: apt_upgrade_result
|
||||
changed_when: apt_upgrade_result.rc == 0
|
||||
failed_when: apt_upgrade_result.rc != 0
|
||||
timeout: 600
|
||||
|
||||
- name: Display apt upgrade result
|
||||
ansible.builtin.debug:
|
||||
msg: "apt upgrade completed: {{ 'Packages upgraded' if apt_upgrade_result.rc == 0 else 'Failed' }}"
|
||||
when: apt_upgrade_result.rc is defined
|
||||
|
||||
# ========================================
|
||||
# 2. Install Base Packages
|
||||
# ========================================
|
||||
|
||||
- name: Install base packages
|
||||
ansible.builtin.shell:
|
||||
cmd: timeout 300 apt-get install -y -qq {{ system_base_packages | join(' ') }}
|
||||
environment:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
APT_LISTCHANGES_FRONTEND: none
|
||||
register: apt_install_result
|
||||
changed_when: apt_install_result.rc == 0
|
||||
failed_when: apt_install_result.rc != 0
|
||||
timeout: 300
|
||||
|
||||
- name: Display apt install result
|
||||
ansible.builtin.debug:
|
||||
msg: "apt install completed: {{ 'Packages installed/updated' if apt_install_result.rc == 0 else 'Failed' }}"
|
||||
when: apt_install_result.rc is defined
|
||||
|
||||
# ========================================
|
||||
# 3. Create Deploy User
|
||||
# ========================================
|
||||
|
||||
- name: Check if deploy user exists
|
||||
ansible.builtin.shell:
|
||||
cmd: timeout 5 getent passwd {{ deploy_user }} >/dev/null 2>&1 && echo "exists" || echo "not_found"
|
||||
register: deploy_user_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
timeout: 10
|
||||
|
||||
- name: Create deploy user
|
||||
ansible.builtin.user:
|
||||
name: "{{ deploy_user }}"
|
||||
groups: "{{ deploy_user_groups }}"
|
||||
append: yes
|
||||
shell: /bin/bash
|
||||
create_home: yes
|
||||
when:
|
||||
- "'not_found' in deploy_user_check.stdout"
|
||||
- deploy_user != 'root'
|
||||
|
||||
- name: Ensure deploy user has sudo access
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/sudoers.d/deploy
|
||||
line: "{{ deploy_user }} ALL=(ALL) NOPASSWD: ALL"
|
||||
create: yes
|
||||
validate: 'visudo -cf %s'
|
||||
mode: '0440'
|
||||
when: deploy_user != 'root'
|
||||
|
||||
# ========================================
|
||||
# 4. SSH Configuration
|
||||
# ========================================
|
||||
|
||||
- name: Get deploy user home directory
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
key: "{{ deploy_user }}"
|
||||
register: deploy_user_info
|
||||
when: deploy_user != 'root'
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Set deploy user home directory (root)
|
||||
ansible.builtin.set_fact:
|
||||
deploy_user_home: "/root"
|
||||
when: deploy_user == 'root'
|
||||
|
||||
- name: Set deploy user home directory (from getent)
|
||||
ansible.builtin.set_fact:
|
||||
deploy_user_home: "{{ deploy_user_info.ansible_facts.getent_passwd[deploy_user][4] }}"
|
||||
when:
|
||||
- deploy_user != 'root'
|
||||
- deploy_user_info.ansible_facts.getent_passwd[deploy_user] is defined
|
||||
|
||||
- name: Set deploy user home directory (fallback)
|
||||
ansible.builtin.set_fact:
|
||||
deploy_user_home: "/home/{{ deploy_user }}"
|
||||
when: deploy_user_home is not defined
|
||||
|
||||
- name: Ensure .ssh directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ deploy_user_home }}/.ssh"
|
||||
state: directory
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_user }}"
|
||||
mode: '0700'
|
||||
|
||||
- name: Add SSH public key from control node
|
||||
ansible.builtin.authorized_key:
|
||||
user: "{{ deploy_user }}"
|
||||
state: present
|
||||
key: "{{ lookup('file', ansible_ssh_private_key_file | default('~/.ssh/production') + '.pub') }}"
|
||||
when: ansible_ssh_private_key_file is defined
|
||||
|
||||
- name: Verify SSH key is configured before disabling password auth
|
||||
ansible.builtin.stat:
|
||||
path: "{{ deploy_user_home }}/.ssh/authorized_keys"
|
||||
register: ssh_key_file
|
||||
when: ssh_key_only_auth | bool
|
||||
|
||||
- name: Configure SSH key-only authentication
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
backup: yes
|
||||
loop:
|
||||
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
|
||||
- { regexp: '^#?PubkeyAuthentication', line: 'PubkeyAuthentication yes' }
|
||||
- { regexp: '^#?AuthorizedKeysFile', line: 'AuthorizedKeysFile .ssh/authorized_keys' }
|
||||
when:
|
||||
- ssh_key_only_auth | bool
|
||||
- ssh_key_file.stat.exists | default(false)
|
||||
notify: restart sshd
|
||||
|
||||
- name: Disable root login (optional)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^#?PermitRootLogin'
|
||||
line: 'PermitRootLogin no'
|
||||
backup: yes
|
||||
when: ssh_disable_root_login | bool
|
||||
notify: restart sshd
|
||||
|
||||
# ========================================
|
||||
# 5. Firewall Configuration
|
||||
# ========================================
|
||||
# WICHTIG: Firewall wird erst am Ende konfiguriert, um SSH-Verbindung nicht zu unterbrechen
|
||||
|
||||
- name: Check current UFW status
|
||||
ansible.builtin.command:
|
||||
cmd: ufw status | head -1
|
||||
register: ufw_current_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: firewall_enable | bool
|
||||
|
||||
- name: Display current firewall status
|
||||
ansible.builtin.debug:
|
||||
msg: "Current firewall status: {{ ufw_current_status.stdout | default('Unknown') }}"
|
||||
when: firewall_enable | bool and ufw_current_status is defined
|
||||
|
||||
- name: Ensure SSH port is allowed before configuring firewall
|
||||
ansible.builtin.command:
|
||||
cmd: ufw allow 22/tcp comment 'SSH - Allow before enabling firewall'
|
||||
when:
|
||||
- firewall_enable | bool
|
||||
- "'inactive' in (ufw_current_status.stdout | default(''))"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Reset UFW to defaults (only if inactive)
|
||||
ansible.builtin.command:
|
||||
cmd: ufw --force reset
|
||||
when:
|
||||
- firewall_enable | bool
|
||||
- "'inactive' in (ufw_current_status.stdout | default(''))"
|
||||
changed_when: false
|
||||
|
||||
- name: Set UFW default policies
|
||||
ansible.builtin.command:
|
||||
cmd: "ufw default {{ item.policy }} {{ item.direction }}"
|
||||
loop:
|
||||
- { policy: 'deny', direction: 'incoming' }
|
||||
- { policy: 'allow', direction: 'outgoing' }
|
||||
when:
|
||||
- firewall_enable | bool
|
||||
- "'inactive' in (ufw_current_status.stdout | default(''))"
|
||||
|
||||
- name: Allow firewall ports (ensure SSH is first)
|
||||
ansible.builtin.command:
|
||||
cmd: "ufw allow {{ item.port }}/{{ item.proto }} comment '{{ item.comment }}'"
|
||||
loop: "{{ firewall_ports }}"
|
||||
when:
|
||||
- firewall_enable | bool
|
||||
- "'inactive' in (ufw_current_status.stdout | default(''))"
|
||||
register: ufw_rules
|
||||
changed_when: ufw_rules.rc == 0
|
||||
|
||||
- name: Enable UFW (only if inactive)
|
||||
ansible.builtin.command:
|
||||
cmd: ufw --force enable
|
||||
when:
|
||||
- firewall_enable | bool
|
||||
- "'inactive' in (ufw_current_status.stdout | default(''))"
|
||||
|
||||
- name: Display UFW status
|
||||
ansible.builtin.command:
|
||||
cmd: ufw status verbose
|
||||
register: ufw_status
|
||||
changed_when: false
|
||||
|
||||
- name: Show UFW status
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ ufw_status.stdout_lines }}"
|
||||
|
||||
# ========================================
|
||||
# 6. Fail2ban Configuration
|
||||
# ========================================
|
||||
|
||||
- name: Ensure fail2ban is enabled and started
|
||||
ansible.builtin.systemd:
|
||||
name: fail2ban
|
||||
enabled: yes
|
||||
state: started
|
||||
when: "'fail2ban' in system_base_packages"
|
||||
|
||||
# ========================================
|
||||
# 7. System Configuration
|
||||
# ========================================
|
||||
|
||||
- name: Configure timezone
|
||||
ansible.builtin.timezone:
|
||||
name: Europe/Berlin
|
||||
|
||||
- name: Display setup summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "=========================================="
|
||||
- "Initial Server Setup Complete"
|
||||
- "=========================================="
|
||||
- "Deploy User: {{ deploy_user }}"
|
||||
- "SSH Key-only Auth: {{ ssh_key_only_auth }}"
|
||||
- "Firewall: {{ 'Enabled' if firewall_enable else 'Disabled' }}"
|
||||
- "Fail2ban: {{ 'Enabled' if 'fail2ban' in system_base_packages else 'Disabled' }}"
|
||||
- "=========================================="
|
||||
- "Next Steps:"
|
||||
- "1. Test SSH connection: ssh {{ deploy_user }}@{{ ansible_host }}"
|
||||
- "2. Install Docker: ansible-playbook playbooks/install-docker.yml"
|
||||
- "3. Deploy Infrastructure: ansible-playbook playbooks/setup-infrastructure.yml"
|
||||
- "=========================================="
|
||||
|
||||
handlers:
|
||||
- name: restart sshd
|
||||
ansible.builtin.systemd:
|
||||
name: sshd
|
||||
state: restarted
|
||||
|
||||
Reference in New Issue
Block a user