This guide provides a full Ansible playbook to deploy Cannery with Docker Compose on Debian 10+, Ubuntu LTS, and RHEL 9+ compatible hosts.
- name: Deploy Cannery
hosts: cannery
become: true
vars:
app_root: /opt/cannery
app_port: 4000
cannery_host: "cannery.{{ ansible_default_ipv4.address }}"
# Generate with: docker run -it shibaobun/cannery /app/priv/random.sh
secret_key_base: "replace-with-generated-secret-key"
tasks:
- name: Install Docker on Debian/Ubuntu
apt:
name:
- docker.io
- docker-compose-plugin
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install Docker on RHEL family
dnf:
name:
- docker
- docker-compose-plugin
state: present
when: ansible_os_family == "RedHat"
- name: Enable and start Docker
service:
name: docker
state: started
enabled: true
- name: Add ansible user to docker group
user:
name: "{{ ansible_user }}"
groups: docker
append: yes
- name: Create application directory
file:
path: "{{ app_root }}"
state: directory
mode: "0755"
- name: Generate secret key base
command: docker run -it shibaobun/cannery /app/priv/random.sh
register: secret_output
when: secret_key_base == "replace-with-generated-secret-key"
changed_when: false
- name: Set secret key base fact
set_fact:
actual_secret_key: "{{ secret_output.stdout if secret_key_base == 'replace-with-generated-secret-key' else secret_key_base }}"
- name: Write Docker Compose file
template:
src: docker-compose.yml.j2
dest: "{{ app_root }}/docker-compose.yml"
mode: "0644"
- name: Start application stack
command: docker compose up -d
args:
chdir: "{{ app_root }}"
register: docker_up_result
- name: Wait for application to be ready
wait_for:
host: "{{ ansible_default_ipv4.address }}"
port: "{{ app_port }}"
delay: 10
timeout: 60
when: docker_up_result.changed
- name: Print access information
debug:
msg: "Cannery is now accessible at http://{{ ansible_default_ipv4.address }}:{{ app_port }}"
Create a template file at templates/docker-compose.yml.j2:
version: '3.8'
services:
cannery:
image: shibaobun/cannery:latest
restart: unless-stopped
ports:
- "{{ app_port }}:4000"
environment:
- DATABASE_URL=postgresql://cannery:{{ postgres_password | default('changeme') }}@cannery-db:5432/cannery
- SECRET_KEY_BASE={{ actual_secret_key }}
- HOST=http://{{ ansible_default_ipv4.address }}:{{ app_port }}
- PORT=4000
- REGISTRATION=invite_only
depends_on:
- cannery-db
cannery-db:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- cannery_postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=cannery
- POSTGRES_USER=cannery
- POSTGRES_PASSWORD={{ postgres_password | default('changeme') }}
volumes:
cannery_postgres_data:
Example inventory file (hosts.yml):
all:
children:
cannery:
hosts:
cannery-server:
ansible_host: 192.168.1.100
postgres_password: "your_secure_postgres_password_here"
secret_key_base: "your_generated_secret_key_here" # Leave empty to auto-generate
# Run the playbook
ansible-playbook -i hosts.yml cannery-playbook.yml
# Run with specific vault password file
ansible-playbook -i hosts.yml cannery-playbook.yml --vault-password-file ~/.vault_pass
latest for better stability.Any questions?
Feel free to contact us. Find all contact information on our contact page.