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

- 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:
2025-11-09 14:46:15 +01:00
parent 85c369e846
commit 36ef2a1e2c
1366 changed files with 104925 additions and 28719 deletions

View File

@@ -0,0 +1,82 @@
---
- name: Check for existing Traefik containers
shell: docker ps -a --filter "name=traefik" --format "{{ '{{' }}.ID{{ '}}' }}"
register: existing_traefik_containers
changed_when: false
failed_when: false
- name: Stop and remove existing Traefik containers
shell: docker stop {{ item }} && docker rm {{ item }}
loop: "{{ existing_traefik_containers.stdout_lines }}"
when: existing_traefik_containers.stdout_lines | length > 0
ignore_errors: yes
- name: Check if ports 80 and 443 are in use
shell: |
if sudo ss -tlnp 'sport = :80' 2>/dev/null | grep -q LISTEN; then
echo "port_80_in_use"
fi
if sudo ss -tlnp 'sport = :443' 2>/dev/null | grep -q LISTEN; then
echo "port_443_in_use"
fi
register: port_check
changed_when: false
failed_when: false
- name: Display port status
debug:
msg:
- "Port 80 status: {{ 'IN USE' if 'port_80_in_use' in port_check.stdout else 'FREE' }}"
- "Port 443 status: {{ 'IN USE' if 'port_443_in_use' in port_check.stdout else 'FREE' }}"
- "Note: docker-proxy listening on ports is normal when Traefik container is running"
- name: Warn if ports are blocked by non-docker processes
debug:
msg: "WARNING: Ports 80/443 appear to be in use. This may prevent Traefik from starting. Check with: sudo ss -tlnp 'sport = :80'"
when: ('port_80_in_use' in port_check.stdout or 'port_443_in_use' in port_check.stdout) and existing_traefik_containers.stdout_lines | length == 0
- name: Check if acme.json exists
stat:
path: "{{ traefik_stack_path }}/acme.json"
register: acme_json_stat
- name: Remove acme.json if it's a directory (should be a file)
shell: |
if [ -d "{{ traefik_stack_path }}/acme.json" ]; then
rm -rf "{{ traefik_stack_path }}/acme.json"
fi
become: yes
when: acme_json_stat.stat.exists and acme_json_stat.stat.isdir
- name: Ensure Traefik acme.json exists and has correct permissions
file:
path: "{{ traefik_stack_path }}/acme.json"
state: touch
mode: '0600'
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
become: yes
when: not acme_json_stat.stat.exists or (acme_json_stat.stat.exists and acme_json_stat.stat.isdir)
- name: Deploy Traefik stack
community.docker.docker_compose_v2:
project_src: "{{ traefik_stack_path }}"
state: present
pull: always
register: traefik_compose_result
- name: Check Traefik container status
shell: |
docker compose -f {{ traefik_stack_path }}/docker-compose.yml ps traefik | grep -Eiq "Up|running"
register: traefik_state
changed_when: false
until: traefik_state.rc == 0
retries: "{{ ((traefik_wait_timeout | int) + (traefik_wait_interval | int) - 1) // (traefik_wait_interval | int) }}"
delay: "{{ traefik_wait_interval | int }}"
failed_when: traefik_state.rc != 0
when: not ansible_check_mode
- name: Record Traefik deployment facts
set_fact:
traefik_stack_changed: "{{ traefik_compose_result.changed | default(false) }}"
traefik_log_hint: ""

View File

@@ -0,0 +1,135 @@
---
# Check Traefik Logs and ACME Challenge Status
- name: Check if Traefik stack directory exists
ansible.builtin.stat:
path: "{{ traefik_stack_path }}"
register: traefik_stack_exists
- name: Fail if Traefik stack directory does not exist
ansible.builtin.fail:
msg: "Traefik stack directory not found at {{ traefik_stack_path }}"
when: not traefik_stack_exists.stat.exists
- name: Get recent Traefik logs
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose logs {{ traefik_container_name }} --tail={{ traefik_logs_tail | default(100) }} 2>&1
register: traefik_logs
changed_when: false
failed_when: false
- name: Check for ACME challenge errors in container logs
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose logs {{ traefik_container_name }} 2>&1 | grep -iE "acme.*challenge|Cannot retrieve.*ACME" | tail -{{ traefik_logs_error_tail | default(20) }} || echo "No ACME challenge errors found in recent logs"
register: acme_errors
changed_when: false
failed_when: false
- name: Check for ACME challenge errors in log file
ansible.builtin.shell: |
tail -n {{ traefik_logs_tail | default(100) }} {{ traefik_stack_path }}/logs/traefik.log 2>/dev/null | grep -iE "acme.*challenge|Cannot retrieve.*ACME" | tail -{{ traefik_logs_error_tail | default(20) }} || echo "No ACME challenge errors found in log file"
register: acme_errors_file
changed_when: false
failed_when: false
ignore_errors: yes
- name: Get logs from last N minutes
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose logs {{ traefik_container_name }} --since {{ traefik_logs_since_minutes | default(10) }}m 2>&1 | tail -{{ traefik_logs_recent_tail | default(50) }}
register: recent_logs
changed_when: false
failed_when: false
when: traefik_logs_since_minutes is defined
- name: Count ACME challenge errors in last hour
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose logs {{ traefik_container_name }} --since 1h 2>&1 | grep -c "Cannot retrieve.*ACME challenge" || echo "0"
register: acme_error_count
changed_when: false
failed_when: false
- name: Display ACME challenge error summary
ansible.builtin.debug:
msg: |
========================================
Traefik ACME Challenge Status
========================================
ACME Errors (last hour): {{ acme_error_count.stdout }}
========================================
{% if acme_error_count.stdout | int > 0 %}
⚠️ ACME challenge errors still occurring
{% else %}
✅ No ACME challenge errors in the last hour!
{% endif %}
when: traefik_show_status | default(true) | bool
- name: Display ACME challenge errors from container logs
ansible.builtin.debug:
msg: |
========================================
ACME Challenge Errors (Container Logs):
========================================
{{ acme_errors.stdout }}
========================================
when: traefik_show_status | default(true) | bool
- name: Display ACME challenge errors from log file
ansible.builtin.debug:
msg: |
========================================
ACME Challenge Errors (Log File):
========================================
{{ acme_errors_file.stdout }}
========================================
when: traefik_show_status | default(true) | bool
- name: Display recent Traefik logs
ansible.builtin.debug:
msg: |
========================================
Recent Traefik Logs (last {{ traefik_logs_since_minutes | default(10) }} minutes):
========================================
{{ recent_logs.stdout | default('No recent logs') }}
========================================
when:
- traefik_logs_since_minutes is defined
- traefik_show_status | default(true) | bool
- name: Display all Traefik logs
ansible.builtin.debug:
msg: |
========================================
Traefik Container Logs (last {{ traefik_logs_tail | default(100) }} lines):
========================================
{{ traefik_logs.stdout | default('No logs available') }}
========================================
when:
- traefik_show_all_logs | default(false) | bool
- traefik_show_status | default(true) | bool
- name: Display final summary
ansible.builtin.debug:
msg: |
========================================
Summary
========================================
{% if acme_error_count.stdout | int == 0 %}
✅ SUCCESS: No ACME challenge errors in the last hour!
The Traefik configuration fix appears to be working. Monitor the logs
for the next certificate renewal attempt (usually hourly) to confirm.
{% else %}
⚠️ WARNING: {{ acme_error_count.stdout }} ACME challenge errors found in the last hour.
The errors may be from before the configuration fix was applied.
Monitor the logs for the next certificate renewal attempt to see if
the errors have stopped.
{% endif %}
========================================
when: traefik_show_status | default(true) | bool

View File

@@ -1,23 +0,0 @@
---
- name: Deploy Traefik stack
community.docker.docker_compose_v2:
project_src: "{{ traefik_stack_path }}"
state: present
pull: always
register: traefik_compose_result
- name: Check Traefik container status
shell: |
docker compose -f {{ traefik_stack_path }}/docker-compose.yml ps traefik | grep -Eiq "Up|running"
register: traefik_state
changed_when: false
until: traefik_state.rc == 0
retries: "{{ ((traefik_wait_timeout | int) + (traefik_wait_interval | int) - 1) // (traefik_wait_interval | int) }}"
delay: "{{ traefik_wait_interval | int }}"
failed_when: traefik_state.rc != 0
when: not ansible_check_mode
- name: Record Traefik deployment facts
set_fact:
traefik_stack_changed: "{{ traefik_compose_result.changed | default(false) }}"
traefik_log_hint: ""

View File

@@ -0,0 +1,113 @@
---
# Restart and Recreate Traefik Container Tasks
# Supports both restart (force-recreate) and full recreate (down + up)
- name: Check if Traefik stack directory exists
ansible.builtin.stat:
path: "{{ traefik_stack_path }}"
register: traefik_stack_exists
- name: Fail if Traefik stack directory does not exist
ansible.builtin.fail:
msg: "Traefik stack directory not found at {{ traefik_stack_path }}"
when: not traefik_stack_exists.stat.exists
- name: Check Traefik container status before restart
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose ps {{ traefik_container_name }} --format json
register: traefik_status_before
changed_when: false
failed_when: false
- name: Display Traefik status before restart
ansible.builtin.debug:
msg: |
================================================================================
Traefik Container Status (Before Restart):
{{ traefik_status_before.stdout | default('Container not found or Docker not running') }}
================================================================================
when: traefik_show_status | default(true) | bool
- name: Recreate Traefik container to apply new configuration
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose up -d --force-recreate {{ traefik_container_name }}
register: traefik_restart
changed_when: traefik_restart.rc == 0
when: traefik_restart_action | default('restart') == 'restart'
notify: wait for traefik
- name: Stop and remove Traefik container (full recreate)
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose down {{ traefik_container_name }}
register: traefik_down
changed_when: traefik_down.rc == 0
when: traefik_restart_action | default('restart') == 'recreate'
- name: Create new Traefik container with updated configuration (full recreate)
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose up -d {{ traefik_container_name }}
register: traefik_up
changed_when: traefik_up.rc == 0
when: traefik_restart_action | default('restart') == 'recreate'
notify: wait for traefik
- name: Wait for Traefik to be ready
ansible.builtin.wait_for:
timeout: "{{ traefik_restart_wait_timeout | default(30) }}"
changed_when: false
- name: Check Traefik container status after restart
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose ps {{ traefik_container_name }} --format json
register: traefik_status_after
changed_when: false
failed_when: false
- name: Check Traefik health endpoint
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose exec -T {{ traefik_container_name }} traefik healthcheck --ping 2>&1 || echo "HEALTH_CHECK_FAILED"
register: traefik_health
ignore_errors: yes
changed_when: false
when: traefik_check_health | default(true) | bool
- name: Check if ACME challenge router is in labels (for recreate action)
ansible.builtin.shell: |
cd {{ traefik_stack_path }}
docker compose ps {{ traefik_container_name }} --format json | jq -r '.[0].Labels' | grep -i 'acme-challenge' || echo "NO_ACME_ROUTER"
register: acme_router_check
changed_when: false
failed_when: false
when: traefik_restart_action | default('restart') == 'recreate'
- name: Display final status
ansible.builtin.debug:
msg: |
========================================
Traefik Restart Summary
========================================
Action: {{ traefik_restart_action | default('restart') | upper }}
Container Status: {% if 'State":"running' in (traefik_status_after.stdout | default('')) %}✅ RUNNING{% else %}❌ NOT RUNNING{% endif %}
{% if traefik_check_health | default(true) | bool %}
Health Check: {% if 'HEALTH_CHECK_FAILED' not in (traefik_health.stdout | default('')) %}✅ HEALTHY{% else %}❌ UNHEALTHY or TIMEOUT{% endif %}
{% endif %}
{% if traefik_restart_action | default('restart') == 'recreate' %}
ACME Challenge Router: {% if 'NO_ACME_ROUTER' in acme_router_check.stdout %}✅ REMOVED (correct!){% else %}⚠️ Still present in labels{% endif %}
{% endif %}
Restart Action: {% if (traefik_restart.changed | default(false)) or (traefik_up.changed | default(false)) %}🔄 Container restarted{% else %} No restart needed{% endif %}
========================================
{% if 'State":"running' in (traefik_status_after.stdout | default('')) %}
✅ Traefik is running!
{% else %}
❌ Traefik is not running. Check logs for details:
docker logs {{ traefik_container_name }}
{% endif %}
========================================
when: traefik_show_status | default(true) | bool