refactor(roles/coolify): refactored coolify role

This commit is contained in:
ITQ
2026-03-19 14:41:51 +03:00
parent 8a9cc4a1ce
commit 81b623432c
12 changed files with 533 additions and 202 deletions
+32 -6
View File
@@ -1,32 +1,56 @@
--- ---
coolify_state: present # latest | present | absent # present - Install if missing, ensure running if already installed
# latest - Install if missing, update to latest if already installed
# absent - Uninstall Coolify (see coolify_remove_data_on_absent)
# stopped - Stop Coolify services without removing
coolify_state: present
coolify_remove_data_on_absent: false coolify_remove_data_on_absent: false
coolify_base_dir: /data/coolify coolify_base_dir: /data/coolify
coolify_docker_network: coolify coolify_owner: "9999"
coolify_http_port: 8000
coolify_owner: 9999
coolify_group: root coolify_group: root
coolify_compose_files: coolify_compose_files:
- docker-compose.yml - docker-compose.yml
- docker-compose.prod.yml - docker-compose.prod.yml
coolify_docker_network: coolify
# Used for health checks and cleanup
coolify_container_names: coolify_container_names:
- coolify - coolify
- coolify-db - coolify-db
- coolify-redis - coolify-redis
- coolify-realtime - coolify-realtime
coolify_registry_url: "ghcr.io"
coolify_image_tag: "latest"
# Auto-generated on first install if left empty
coolify_app_id: "" coolify_app_id: ""
coolify_app_name: "Coolify" coolify_app_name: "Coolify"
coolify_app_key: "" coolify_app_key: ""
coolify_app_env: "production"
coolify_app_port: 8000
coolify_php_memory_limit: "256M"
coolify_php_fpm_pm_control: "dynamic"
coolify_php_fpm_pm_start_servers: 1
coolify_php_fpm_pm_min_spare_servers: 1
coolify_php_fpm_pm_max_spare_servers: 10
coolify_db_username: "coolify" coolify_db_username: "coolify"
coolify_db_password: "" coolify_db_password: ""
coolify_db_database: "coolify"
coolify_redis_password: "" coolify_redis_password: ""
coolify_soketi_port: 6001
coolify_soketi_debug: "false"
# Auto-generated on first install if left empty
coolify_pusher_app_id: "" coolify_pusher_app_id: ""
coolify_pusher_app_key: "" coolify_pusher_app_key: ""
coolify_pusher_app_secret: "" coolify_pusher_app_secret: ""
@@ -35,4 +59,6 @@ coolify_root_username: ""
coolify_root_user_email: "" coolify_root_user_email: ""
coolify_root_user_password: "" coolify_root_user_password: ""
coolify_registry_url: "ghcr.io" coolify_health_retries: 20
coolify_health_delay: 15
coolify_compose_wait_timeout: 300
+57 -15
View File
@@ -1,5 +1,6 @@
--- ---
- name: Ensure source directory exists - name: Ensure source directory exists
become: true
ansible.builtin.file: ansible.builtin.file:
path: "{{ coolify_base_dir }}/source" path: "{{ coolify_base_dir }}/source"
state: directory state: directory
@@ -8,31 +9,72 @@
mode: "0750" mode: "0750"
tags: coolify, configuration tags: coolify, configuration
- name: Check if .env exists - name: Check if .env file already exists
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ coolify_base_dir }}/source/.env" path: "{{ coolify_base_dir }}/source/.env"
register: coolify_env_file register: _coolify_env_check
tags: coolify, configuration tags: coolify, configuration
- name: Generate missing secrets (only for new install) # Empty strings in defaults/main.yaml signal "please auto-generate"
- name: Generate secrets for initial installation
when: not _coolify_env_check.stat.exists
tags: coolify, configuration
block:
- name: Generate APP_ID (if not provided)
ansible.builtin.set_fact: ansible.builtin.set_fact:
coolify_app_key: "{{ coolify_app_key | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'), true) }}" coolify_app_id: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters,digits') }}"
coolify_db_password: "{{ coolify_db_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'), true) }}" when: coolify_app_id | default('', true) | length == 0
coolify_redis_password: "{{ coolify_redis_password | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'), true) }}"
coolify_pusher_app_key: "{{ coolify_pusher_app_key | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'), true) }}"
coolify_pusher_app_secret: "{{ coolify_pusher_app_secret | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits'), true) }}"
coolify_app_id: "{{ coolify_app_id | default(lookup('password', '/dev/null length=16 chars=ascii_letters,digits'), true) }}"
coolify_pusher_app_id: "{{ coolify_pusher_app_id | default(lookup('password', '/dev/null length=16 chars=ascii_letters,digits'), true) }}"
when: not coolify_env_file.stat.exists
tags: coolify, configuration
- name: Configure .env file - name: Generate APP_KEY (if not provided)
ansible.builtin.set_fact:
coolify_app_key: "base64:{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') | b64encode }}"
when: coolify_app_key | default('', true) | length == 0
- name: Generate DB_PASSWORD (if not provided)
ansible.builtin.set_fact:
coolify_db_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
when: coolify_db_password | default('', true) | length == 0
- name: Generate REDIS_PASSWORD (if not provided)
ansible.builtin.set_fact:
coolify_redis_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
when: coolify_redis_password | default('', true) | length == 0
- name: Generate PUSHER_APP_ID (if not provided)
ansible.builtin.set_fact:
coolify_pusher_app_id: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters,digits') }}"
when: coolify_pusher_app_id | default('', true) | length == 0
- name: Generate PUSHER_APP_KEY (if not provided)
ansible.builtin.set_fact:
coolify_pusher_app_key: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
when: coolify_pusher_app_key | default('', true) | length == 0
- name: Generate PUSHER_APP_SECRET (if not provided)
ansible.builtin.set_fact:
coolify_pusher_app_secret: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
when: coolify_pusher_app_secret | default('', true) | length == 0
- name: Deploy Coolify .env configuration
become: true
ansible.builtin.template: ansible.builtin.template:
src: .env.j2 src: .env.j2
dest: "{{ coolify_base_dir }}/source/.env" dest: "{{ coolify_base_dir }}/source/.env"
owner: "{{ coolify_owner }}" owner: "{{ coolify_owner }}"
group: "{{ coolify_group }}" group: "{{ coolify_group }}"
mode: "0640" mode: "0640"
force: false backup: true
when: not coolify_env_file.stat.exists register: _coolify_env_deployed
notify:
- Restart coolify services
- Wait for coolify health
tags: coolify, configuration
- name: Show configuration status
ansible.builtin.debug:
msg: >-
.env file {{ 'created' if not _coolify_env_check.stat.exists else
('updated' if _coolify_env_deployed.changed else 'unchanged') }}
at {{ coolify_base_dir }}/source/.env
verbosity: 1
tags: coolify, configuration tags: coolify, configuration
+84 -67
View File
@@ -1,114 +1,131 @@
--- ---
- name: Check if Coolify is running before uninstallation - name: Stop Coolify services gracefully
community.docker.docker_container_info: become: true
name: "{{ item }}" community.docker.docker_compose_v2:
loop: "{{ coolify_container_names }}" project_src: "{{ coolify_base_dir }}/source"
register: coolify_containers_pre_uninstall files: "{{ coolify_compose_files }}"
ignore_errors: true state: absent
tags: coolify, deletion, pre-check remove_orphans: true
register: _coolify_compose_down
failed_when:
- _coolify_compose_down.rc is defined
- _coolify_compose_down.rc != 0
- "'not found' not in (_coolify_compose_down.msg | default(''))"
- "'no such file' not in (_coolify_compose_down.msg | default('') | lower)"
when: _coolify_installed | bool
tags: coolify, deletion
- name: Stop Coolify services - name: Force-remove any remaining Coolify containers
ansible.builtin.include_tasks: stop.yaml become: true
ignore_errors: true
tags: coolify, deletion, stop
- name: Force remove any remaining Coolify containers
community.docker.docker_container: community.docker.docker_container:
name: "{{ item.item }}" name: "{{ item }}"
state: absent state: absent
force_kill: true force_kill: true
force_remove: true loop: "{{ coolify_container_names }}"
loop: "{{ coolify_containers_pre_uninstall.results }}" register: _coolify_remove_containers
when: failed_when:
- item.exists | default(false) - _coolify_remove_containers is failed
- coolify_remove_data_on_absent | bool - "'No such container' not in (_coolify_remove_containers.msg | default(''))"
ignore_errors: true
tags: coolify, docker, deletion tags: coolify, docker, deletion
- name: Remove Coolify files and data (conditional) - name: Remove Coolify Docker volumes
become: true
community.docker.docker_volume:
name: "{{ item }}"
state: absent
loop:
- coolify-db
- coolify-redis
register: _coolify_remove_volumes
failed_when:
- _coolify_remove_volumes is failed
- "'no such volume' not in (_coolify_remove_volumes.msg | default('') | lower)"
- "'not found' not in (_coolify_remove_volumes.msg | default('') | lower)"
when: coolify_remove_data_on_absent | bool
tags: coolify, docker, deletion
- name: Remove Coolify source files (always on absent)
become: true
ansible.builtin.file:
path: "{{ coolify_base_dir }}/source"
state: absent
tags: coolify, files, deletion
- name: Remove Coolify data directories
become: true
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
state: absent state: absent
loop: loop:
- "{{ coolify_base_dir }}/source" - "{{ coolify_base_dir }}/ssh"
- "{{ coolify_base_dir }}/applications" - "{{ coolify_base_dir }}/applications"
- "{{ coolify_base_dir }}/databases" - "{{ coolify_base_dir }}/databases"
- "{{ coolify_base_dir }}/backups" - "{{ coolify_base_dir }}/backups"
- "{{ coolify_base_dir }}/services" - "{{ coolify_base_dir }}/services"
- "{{ coolify_base_dir }}/proxy" - "{{ coolify_base_dir }}/proxy"
- "{{ coolify_base_dir }}/webhooks-during-maintenance" - "{{ coolify_base_dir }}/webhooks-during-maintenance"
- "{{ coolify_base_dir }}/ssh"
- "{{ coolify_base_dir }}/sentinel" - "{{ coolify_base_dir }}/sentinel"
when: coolify_remove_data_on_absent | bool when: coolify_remove_data_on_absent | bool
tags: coolify, files, deletion, data tags: coolify, files, deletion
- name: Remove base directory if empty (only when requested) - name: Remove Coolify base directory (if full removal requested)
become: true
ansible.builtin.file: ansible.builtin.file:
path: "{{ coolify_base_dir }}" path: "{{ coolify_base_dir }}"
state: absent state: absent
when: coolify_remove_data_on_absent | bool when: coolify_remove_data_on_absent | bool
tags: coolify, files, deletion, data tags: coolify, files, deletion
- name: Remove Coolify docker volumes (find) - name: Remove Coolify Docker network
community.docker.docker_volume_info: become: true
name: "^coolify_.*"
register: coolify_volumes
ignore_errors: true
when: coolify_remove_data_on_absent | bool
tags: coolify, docker, deletion
- name: Remove Coolify docker volumes
community.docker.docker_volume:
name: "{{ item.Name }}"
state: absent
force: true
loop: "{{ coolify_volumes.volumes | default([]) }}"
when: coolify_volumes is defined and coolify_volumes.volumes | length > 0
tags: coolify, docker, deletion
- name: Remove Coolify docker network
community.docker.docker_network: community.docker.docker_network:
name: "{{ coolify_docker_network }}" name: "{{ coolify_docker_network }}"
state: absent state: absent
force: "{{ coolify_remove_data_on_absent | bool }}" force: true
ignore_errors: true register: _coolify_remove_network
failed_when:
- _coolify_remove_network is failed
- "'not found' not in (_coolify_remove_network.msg | default('') | lower)"
- "'network coolify not found' not in (_coolify_remove_network.msg | default('') | lower)"
when: coolify_remove_data_on_absent | bool when: coolify_remove_data_on_absent | bool
tags: coolify, docker, deletion tags: coolify, docker, deletion
- name: Prune Coolify images - name: Prune Coolify container images
become: true become: true
community.docker.docker_prune: community.docker.docker_prune:
images: true images: true
images_filters: images_filters:
reference: "ghcr.io/coollabsio/*" reference: "ghcr.io/coollabsio/*"
build_cache: true register: _coolify_prune_images
ignore_errors: true failed_when:
- _coolify_prune_images is failed
- "'permission denied' in (_coolify_prune_images.msg | default('') | lower)"
when: coolify_remove_data_on_absent | bool when: coolify_remove_data_on_absent | bool
tags: coolify, docker, deletion tags: coolify, docker, deletion
- name: Prune unused Docker resources - name: Verify Coolify containers are removed
become: true
community.docker.docker_prune:
containers: true
images: false
networks: true
volumes: false
builder_cache: true
ignore_errors: true
when: coolify_remove_data_on_absent | bool
tags: coolify, docker, deletion
- name: Verify Coolify removal
community.docker.docker_container_info: community.docker.docker_container_info:
name: "{{ item }}" name: "{{ item }}"
loop: "{{ coolify_container_names }}" loop: "{{ coolify_container_names }}"
register: coolify_containers_post_uninstall register: _coolify_post_delete
ignore_errors: true failed_when: false
tags: coolify, deletion, verification tags: coolify, deletion
- name: Display uninstallation message - name: Confirm containers are gone
ansible.builtin.assert:
that:
- not (item.exists | default(false))
fail_msg: "Container {{ item.item }} still exists after uninstall"
quiet: true
loop: "{{ _coolify_post_delete.results }}"
loop_control:
label: "{{ item.item }}"
failed_when: false
tags: coolify, deletion
- name: Show uninstallation summary
ansible.builtin.debug: ansible.builtin.debug:
msg: msg:
- "Coolify has been uninstalled" - "Coolify has been uninstalled"
- "Application data preserved: {{ not coolify_remove_data_on_absent }}" - "Data removed: {{ coolify_remove_data_on_absent | bool }}"
tags: coolify, deletion tags: coolify, deletion
+62 -7
View File
@@ -1,20 +1,75 @@
--- ---
- name: Check if Coolify is installed (compose file exists) - name: Check if Coolify compose file exists
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ coolify_base_dir }}/source/{{ coolify_compose_files[0] }}" path: "{{ coolify_base_dir }}/source/{{ coolify_compose_files[0] }}"
register: coolify_installed register: _coolify_compose_stat
tags: always
- name: Set installation fact
ansible.builtin.set_fact:
_coolify_installed: "{{ _coolify_compose_stat.stat.exists }}"
tags: always
- name: Check if .env file exists
ansible.builtin.stat:
path: "{{ coolify_base_dir }}/source/.env"
register: _coolify_env_stat
tags: always
- name: Set env file fact
ansible.builtin.set_fact:
_coolify_env_exists: "{{ _coolify_env_stat.stat.exists }}"
tags: always tags: always
- name: Check Coolify container status - name: Check Coolify container status
community.docker.docker_container_info: community.docker.docker_container_info:
name: "{{ item }}" name: "{{ item }}"
loop: "{{ coolify_container_names }}" loop: "{{ coolify_container_names }}"
register: coolify_containers register: _coolify_containers
when: coolify_installed.stat.exists failed_when: false
when: _coolify_installed | bool
tags: always tags: always
- name: Set Coolify health fact - name: Determine Coolify health status
ansible.builtin.set_fact: ansible.builtin.set_fact:
coolify_healthy: "{{ coolify_containers.results | selectattr('container', 'defined') | selectattr('container.State.Health.Status', 'defined') | selectattr('container.State.Health.Status', 'equalto', 'healthy') | list | length == coolify_container_names | length }}" _coolify_healthy: >-
when: coolify_containers is defined and coolify_containers.results is defined {{
_coolify_containers.results
| default([])
| selectattr('exists', 'defined')
| selectattr('exists', 'equalto', true)
| selectattr('container', 'defined')
| map(attribute='container')
| selectattr('State.Health', 'defined')
| selectattr('State.Health.Status', 'equalto', 'healthy')
| list
| length == coolify_container_names | length
}}
_coolify_running: >-
{{
_coolify_containers.results
| default([])
| selectattr('exists', 'defined')
| selectattr('exists', 'equalto', true)
| list
| length == coolify_container_names | length
}}
when: _coolify_installed | bool
tags: always
- name: Set default health facts when not installed
ansible.builtin.set_fact:
_coolify_healthy: false
_coolify_running: false
when: not (_coolify_installed | bool)
tags: always
- name: Display detected state
ansible.builtin.debug:
msg:
- "Installed: {{ _coolify_installed }}"
- "Env exists: {{ _coolify_env_exists }}"
- "Running: {{ _coolify_running }}"
- "Healthy: {{ _coolify_healthy }}"
verbosity: 1
tags: always tags: always
+18 -21
View File
@@ -1,5 +1,6 @@
--- ---
- name: Install prerequisites (apt) - name: Install prerequisites (apt)
become: true
ansible.builtin.apt: ansible.builtin.apt:
name: name:
- curl - curl
@@ -10,13 +11,15 @@
tags: coolify, prerequisites, installation tags: coolify, prerequisites, installation
- name: Ensure Docker service is started and enabled - name: Ensure Docker service is started and enabled
become: true
ansible.builtin.systemd: ansible.builtin.systemd:
name: docker name: docker
state: started state: started
enabled: true enabled: true
tags: coolify, docker, installation tags: coolify, docker, installation
- name: Create Coolify directories - name: Create Coolify directory structure
become: true
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
state: directory state: directory
@@ -35,40 +38,34 @@
- "{{ coolify_base_dir }}/webhooks-during-maintenance" - "{{ coolify_base_dir }}/webhooks-during-maintenance"
tags: coolify, files, installation tags: coolify, files, installation
- name: Download Coolify configuration files - name: Deploy Coolify compose files from templates
ansible.builtin.get_url: become: true
url: "https://cdn.coollabs.io/coolify/{{ item.file }}" ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ coolify_base_dir }}/source/{{ item.dest }}" dest: "{{ coolify_base_dir }}/source/{{ item.dest }}"
mode: "0644"
owner: "{{ coolify_owner }}" owner: "{{ coolify_owner }}"
group: "{{ coolify_group }}" group: "{{ coolify_group }}"
mode: "0644"
loop: loop:
- { file: "docker-compose.yml", dest: "docker-compose.yml" } - src: docker-compose.yml.j2
- { file: "docker-compose.prod.yml", dest: "docker-compose.prod.yml" } dest: docker-compose.yml
- { file: "upgrade.sh", dest: "upgrade.sh" } - src: docker-compose.prod.yml.j2
dest: docker-compose.prod.yml
loop_control:
label: "{{ item.dest }}"
tags: coolify, files, installation tags: coolify, files, installation
- name: Configure Coolify environment - name: Configure Coolify environment
ansible.builtin.include_tasks: configure.yaml ansible.builtin.include_tasks: configure.yaml
tags: coolify, configuration, installation tags: coolify, configuration, installation
- name: Ensure correct ownership and permissions recursively - name: Start Coolify services
ansible.builtin.file:
path: "{{ coolify_base_dir }}"
owner: "{{ coolify_owner }}"
group: "{{ coolify_group }}"
mode: "0750"
recurse: true
tags: coolify, permissions, installation
- name: Start Coolify
ansible.builtin.include_tasks: start.yaml ansible.builtin.include_tasks: start.yaml
tags: coolify, start, installation tags: coolify, start, installation
- name: Show installed message - name: Show installation success message
ansible.builtin.debug: ansible.builtin.debug:
msg: msg:
- "Coolify installed successfully" - "Coolify installed successfully"
- "All containers are healthy and responding" - "Access at: http://{{ ansible_host }}:{{ coolify_app_port }}"
- "Access at: http://{{ ansible_host }}:{{ coolify_http_port }}"
tags: coolify, installation tags: coolify, installation
+44 -42
View File
@@ -3,66 +3,68 @@
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- coolify_state in ['present', 'absent', 'latest', 'stopped'] - coolify_state in ['present', 'absent', 'latest', 'stopped']
msg: "coolify_state must be one of: present, absent, latest, stopped" fail_msg: >-
Invalid coolify_state '{{ coolify_state }}'.
Must be one of: present, absent, latest, stopped.
quiet: true
tags: always tags: always
- name: Detect Coolify installation status - name: Detect Coolify installation status
ansible.builtin.include_tasks: detect.yaml ansible.builtin.include_tasks: detect.yaml
tags: always tags: always
- name: Ensure Docker network exists
become: true
community.docker.docker_network:
name: "{{ coolify_docker_network }}"
driver: bridge
attachable: true
state: present
tags: coolify, docker, installation
- name: Uninstall Coolify - name: Uninstall Coolify
ansible.builtin.include_tasks: delete.yaml ansible.builtin.include_tasks: delete.yaml
when: coolify_state == 'absent' when: coolify_state == 'absent'
tags: coolify, deletion tags: coolify, deletion
- name: Install Coolify
ansible.builtin.include_tasks: install.yaml
when:
- coolify_state in ['present', 'latest']
- not coolify_installed.stat.exists
tags: coolify, installation
- name: Update Coolify
ansible.builtin.include_tasks: update.yaml
when:
- coolify_state == 'latest'
- coolify_installed.stat.exists
tags: coolify, update
- name: Ensure Configuration
ansible.builtin.include_tasks: configure.yaml
when:
- coolify_state == 'present'
- coolify_installed.stat.exists
tags: coolify, configuration
- name: Ensure Started
ansible.builtin.include_tasks: start.yaml
when:
- coolify_state == 'present'
- coolify_installed.stat.exists
tags: coolify, start
- name: Stop Coolify - name: Stop Coolify
ansible.builtin.include_tasks: stop.yaml ansible.builtin.include_tasks: stop.yaml
when: when:
- coolify_state == 'stopped' - coolify_state == 'stopped'
- coolify_installed.stat.exists - _coolify_installed
tags: coolify, stop tags: coolify, stop
- name: Show status - name: Ensure Docker network exists
become: true
community.docker.docker_network:
name: "{{ coolify_docker_network }}"
driver: bridge
state: present
when: coolify_state in ['present', 'latest']
tags: coolify, docker
- name: Install Coolify (fresh)
ansible.builtin.include_tasks: install.yaml
when:
- coolify_state in ['present', 'latest']
- not _coolify_installed
tags: coolify, installation
- name: Update Coolify (existing)
ansible.builtin.include_tasks: update.yaml
when:
- coolify_state == 'latest'
- _coolify_installed
tags: coolify, update
- name: Ensure Coolify is configured and running
when:
- coolify_state == 'present'
- _coolify_installed
tags: coolify, configuration
block:
- name: Ensure configuration is up to date
ansible.builtin.include_tasks: configure.yaml
- name: Ensure services are running
ansible.builtin.include_tasks: start.yaml
- name: Show Coolify status
ansible.builtin.debug: ansible.builtin.debug:
msg: msg:
- "Coolify State: {{ coolify_state }}" - "State: {{ coolify_state }}"
- "URL: http://{{ ansible_host }}:{{ coolify_http_port }}" - "Installed: {{ _coolify_installed }}"
- "URL: http://{{ ansible_host }}:{{ coolify_app_port }}"
when: coolify_state in ['present', 'latest'] when: coolify_state in ['present', 'latest']
tags: coolify, status tags: coolify, status
+8 -9
View File
@@ -1,24 +1,23 @@
--- ---
- name: Start Coolify services - name: Start Coolify services via Docker Compose
become: true become: true
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ coolify_base_dir }}/source" project_src: "{{ coolify_base_dir }}/source"
files: "{{ coolify_compose_files }}" files: "{{ coolify_compose_files }}"
pull: always
state: present state: present
pull: always
wait: true wait: true
wait_timeout: 300 wait_timeout: "{{ coolify_compose_wait_timeout }}"
tags: coolify, docker, start tags: coolify, docker, start
- name: Wait for Coolify HTTP to respond - name: Wait for Coolify HTTP to respond
ansible.builtin.uri: ansible.builtin.uri:
url: "http://localhost:{{ coolify_http_port }}" url: "http://localhost:{{ coolify_app_port }}"
method: GET method: GET
status_code: 200 status_code: 200
timeout: 30 timeout: 30
body_format: json register: _coolify_health
register: coolify_health until: _coolify_health.status == 200
until: coolify_health.status == 200 retries: "{{ coolify_health_retries }}"
retries: 10 delay: "{{ coolify_health_delay }}"
delay: 10
tags: coolify, health, start tags: coolify, health, start
+27 -3
View File
@@ -1,10 +1,34 @@
--- ---
- name: Stop Coolify services (compose down) - name: Stop Coolify services via Docker Compose
become: true become: true
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ coolify_base_dir }}/source" project_src: "{{ coolify_base_dir }}/source"
files: "{{ coolify_compose_files }}" files: "{{ coolify_compose_files }}"
state: absent state: stopped
remove_orphans: true remove_orphans: true
remove_volumes: false
tags: coolify, docker, stop tags: coolify, docker, stop
- name: Verify Coolify containers are stopped
community.docker.docker_container_info:
name: "{{ item }}"
loop: "{{ coolify_container_names }}"
register: _coolify_stopped_check
failed_when: false
tags: coolify, docker, stop
- name: Confirm all containers are stopped
ansible.builtin.assert:
that:
- not (item.exists | default(false)) or
(item.container.State.Running | default(false)) == false
fail_msg: "Container {{ item.item }} is still running"
quiet: true
loop: "{{ _coolify_stopped_check.results }}"
loop_control:
label: "{{ item.item }}"
tags: coolify, docker, stop
- name: Show stop confirmation
ansible.builtin.debug:
msg: "Coolify services have been stopped. Data and volumes are preserved."
tags: coolify, stop
+23 -19
View File
@@ -1,22 +1,27 @@
--- ---
- name: Update Coolify configuration files - name: Deploy latest Coolify compose files from templates
ansible.builtin.get_url: become: true
url: "https://cdn.coollabs.io/coolify/{{ item.file }}" ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ coolify_base_dir }}/source/{{ item.dest }}" dest: "{{ coolify_base_dir }}/source/{{ item.dest }}"
mode: "0644"
owner: "{{ coolify_owner }}" owner: "{{ coolify_owner }}"
group: "{{ coolify_group }}" group: "{{ coolify_group }}"
mode: "0644"
loop: loop:
- { file: "docker-compose.yml", dest: "docker-compose.yml" } - src: docker-compose.yml.j2
- { file: "docker-compose.prod.yml", dest: "docker-compose.prod.yml" } dest: docker-compose.yml
- { file: "upgrade.sh", dest: "upgrade.sh" } - src: docker-compose.prod.yml.j2
dest: docker-compose.prod.yml
loop_control:
label: "{{ item.dest }}"
register: _coolify_compose_updated
tags: coolify, files, update tags: coolify, files, update
- name: Ensure Coolify environment configuration exists - name: Ensure Coolify environment configuration is current
ansible.builtin.include_tasks: configure.yaml ansible.builtin.include_tasks: configure.yaml
tags: coolify, configuration, update tags: coolify, configuration, update
- name: Update Coolify services (pull and recreate) - name: Pull latest Coolify images and recreate services
become: true become: true
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ coolify_base_dir }}/source" project_src: "{{ coolify_base_dir }}/source"
@@ -25,26 +30,25 @@
state: present state: present
recreate: always recreate: always
wait: true wait: true
wait_timeout: 300 wait_timeout: "{{ coolify_compose_wait_timeout }}"
register: _coolify_update_result
tags: coolify, docker, update tags: coolify, docker, update
- name: Wait for Coolify HTTP to respond after update - name: Wait for Coolify HTTP to respond after update
ansible.builtin.uri: ansible.builtin.uri:
url: "http://localhost:{{ coolify_http_port }}" url: "http://localhost:{{ coolify_app_port }}"
method: GET method: GET
status_code: 200 status_code: 200
timeout: 30 timeout: 30
body_format: json register: _coolify_health_after_update
register: coolify_health_after_update until: _coolify_health_after_update.status == 200
until: coolify_health_after_update.status == 200 retries: "{{ coolify_health_retries }}"
retries: 20 delay: "{{ coolify_health_delay }}"
delay: 15
tags: coolify, update, health tags: coolify, update, health
- name: Show update success message - name: Show update result
ansible.builtin.debug: ansible.builtin.debug:
msg: msg:
- "Coolify updated successfully to latest version" - "Coolify updated successfully to latest version"
- "Services have been recreated with latest images and config" - "Access at: http://{{ ansible_host }}:{{ coolify_app_port }}"
- "Access at: http://{{ ansible_host }}:{{ coolify_http_port }}"
tags: coolify, update tags: coolify, update
+33 -13
View File
@@ -1,18 +1,38 @@
APP_ID={{ coolify_app_id | default('') }} # Managed by Ansible — manual changes will be overwritten on next deployment
APP_NAME={{ coolify_app_name | default('Coolify') }}
APP_KEY={{ coolify_app_key | default('') }}
DB_USERNAME={{ coolify_db_username | default('coolify') }} APP_ID={{ coolify_app_id }}
DB_PASSWORD={{ coolify_db_password | default('') }} APP_NAME={{ coolify_app_name }}
APP_KEY={{ coolify_app_key }}
APP_ENV={{ coolify_app_env }}
APP_PORT={{ coolify_app_port }}
REDIS_PASSWORD={{ coolify_redis_password | default('') }} REGISTRY_URL={{ coolify_registry_url }}
LATEST_IMAGE={{ coolify_image_tag }}
PUSHER_APP_ID={{ coolify_pusher_app_id | default('') }} PHP_MEMORY_LIMIT={{ coolify_php_memory_limit }}
PUSHER_APP_KEY={{ coolify_pusher_app_key | default('') }} PHP_FPM_PM_CONTROL={{ coolify_php_fpm_pm_control }}
PUSHER_APP_SECRET={{ coolify_pusher_app_secret | default('') }} PHP_FPM_PM_START_SERVERS={{ coolify_php_fpm_pm_start_servers }}
PHP_FPM_PM_MIN_SPARE_SERVERS={{ coolify_php_fpm_pm_min_spare_servers }}
PHP_FPM_PM_MAX_SPARE_SERVERS={{ coolify_php_fpm_pm_max_spare_servers }}
ROOT_USERNAME={{ coolify_root_username | default('') }} DB_USERNAME={{ coolify_db_username }}
ROOT_USER_EMAIL={{ coolify_root_user_email | default('') }} DB_PASSWORD={{ coolify_db_password }}
ROOT_USER_PASSWORD={{ coolify_root_user_password | default('') }} DB_DATABASE={{ coolify_db_database }}
REGISTRY_URL={{ coolify_registry_url | default('ghcr.io') }} REDIS_PASSWORD={{ coolify_redis_password }}
SOKETI_PORT={{ coolify_soketi_port }}
SOKETI_DEBUG={{ coolify_soketi_debug }}
PUSHER_APP_ID={{ coolify_pusher_app_id }}
PUSHER_APP_KEY={{ coolify_pusher_app_key }}
PUSHER_APP_SECRET={{ coolify_pusher_app_secret }}
{% if coolify_root_username | default('', true) | length > 0 %}
ROOT_USERNAME={{ coolify_root_username }}
{% endif %}
{% if coolify_root_user_email | default('', true) | length > 0 %}
ROOT_USER_EMAIL={{ coolify_root_user_email }}
{% endif %}
{% if coolify_root_user_password | default('', true) | length > 0 %}
ROOT_USER_PASSWORD={{ coolify_root_user_password }}
{% endif %}
@@ -0,0 +1,104 @@
# Managed by Ansible — manual changes will be overwritten on next deployment
services:
coolify:
image: "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify:${LATEST_IMAGE:-latest}"
volumes:
- type: bind
source: /data/coolify/source/.env
target: /var/www/html/.env
read_only: true
- /data/coolify/ssh:/var/www/html/storage/app/ssh
- /data/coolify/applications:/var/www/html/storage/app/applications
- /data/coolify/databases:/var/www/html/storage/app/databases
- /data/coolify/services:/var/www/html/storage/app/services
- /data/coolify/backups:/var/www/html/storage/app/backups
environment:
- APP_ENV=${APP_ENV:-production}
- PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT:-256M}
- PHP_FPM_PM_CONTROL=${PHP_FPM_PM_CONTROL:-dynamic}
- PHP_FPM_PM_START_SERVERS=${PHP_FPM_PM_START_SERVERS:-1}
- PHP_FPM_PM_MIN_SPARE_SERVERS=${PHP_FPM_PM_MIN_SPARE_SERVERS:-1}
- PHP_FPM_PM_MAX_SPARE_SERVERS=${PHP_FPM_PM_MAX_SPARE_SERVERS:-10}
env_file:
- /data/coolify/source/.env
ports:
- name: web
target: 8080
published: ${APP_PORT:-8000}
host_ip: 127.0.0.1
protocol: tcp
app_protocol: http
expose:
- "${APP_PORT:-8000}"
healthcheck:
test: curl --fail http://127.0.0.1:8080/api/health || exit 1
interval: 5s
retries: 10
timeout: 2s
postgres:
volumes:
- coolify-db:/var/lib/postgresql/data
environment:
POSTGRES_USER: "${DB_USERNAME}"
POSTGRES_PASSWORD: "${DB_PASSWORD}"
POSTGRES_DB: "${DB_DATABASE:-coolify}"
healthcheck:
test:
- CMD-SHELL
- pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE:-coolify}
interval: 5s
retries: 10
timeout: 2s
redis:
command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
environment:
REDIS_PASSWORD: "${REDIS_PASSWORD}"
volumes:
- coolify-redis:/data
healthcheck:
test: redis-cli ping
interval: 5s
retries: 10
timeout: 2s
soketi:
image: "${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.10"
ports:
- name: soketi
target: 6001
published: ${SOKETI_PORT:-6001}
host_ip: 127.0.0.1
protocol: tcp
app_protocol: http
- name: terminal
target: 6002
published: 6002
host_ip: 127.0.0.1
protocol: tcp
app_protocol: http
volumes:
- /data/coolify/ssh:/var/www/html/storage/app/ssh
environment:
APP_NAME: "${APP_NAME:-Coolify}"
SOKETI_DEBUG: "${SOKETI_DEBUG:-false}"
SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
healthcheck:
test:
- CMD-SHELL
- wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready || exit 1
interval: 5s
retries: 10
timeout: 2s
volumes:
coolify-db:
name: coolify-db
coolify-redis:
name: coolify-redis
networks:
coolify:
external: true
@@ -0,0 +1,41 @@
# Managed by Ansible — manual changes will be overwritten on next deployment
services:
coolify:
container_name: coolify
restart: always
working_dir: /var/www/html
extra_hosts:
- host.docker.internal:host-gateway
networks:
- coolify
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
soketi:
condition: service_healthy
postgres:
image: postgres:15-alpine
container_name: coolify-db
restart: always
networks:
- coolify
redis:
image: redis:7-alpine
container_name: coolify-redis
restart: always
networks:
- coolify
soketi:
container_name: coolify-realtime
extra_hosts:
- host.docker.internal:host-gateway
restart: always
networks:
- coolify
networks:
coolify:
name: coolify
driver: bridge
external: false