added ansible script
This commit is contained in:
98
ansible/playbooks/01-preflight-checks.yml
Normal file
98
ansible/playbooks/01-preflight-checks.yml
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
# Playbook 01: Preflight Checks
|
||||
# Validates environment before deployment
|
||||
|
||||
- name: Preflight Checks
|
||||
hosts: all
|
||||
gather_facts: yes
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Check Ansible version
|
||||
assert:
|
||||
that:
|
||||
- ansible_version.full is version('2.14', '>=')
|
||||
fail_msg: "Ansible 2.14 or higher is required"
|
||||
success_msg: "Ansible version OK ({{ ansible_version.full }})"
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Test SSH connectivity
|
||||
ping:
|
||||
|
||||
- name: Check sudo access
|
||||
command: sudo -n true
|
||||
changed_when: false
|
||||
|
||||
- name: Check Python3 availability
|
||||
command: python3 --version
|
||||
register: python_version
|
||||
changed_when: false
|
||||
|
||||
- name: Display Python version
|
||||
debug:
|
||||
msg: "Python version: {{ python_version.stdout }}"
|
||||
|
||||
- name: Check disk space
|
||||
shell: df -h / | awk 'NR==2 {print $4}'
|
||||
register: disk_space
|
||||
changed_when: false
|
||||
|
||||
- name: Validate sufficient disk space
|
||||
assert:
|
||||
that:
|
||||
- disk_space.stdout is regex('[0-9]+G')
|
||||
fail_msg: "Insufficient disk space. At least 20GB recommended."
|
||||
success_msg: "Disk space OK ({{ disk_space.stdout }} available)"
|
||||
|
||||
- name: Check if ports 80 and 443 are available
|
||||
wait_for:
|
||||
port: "{{ item }}"
|
||||
state: stopped
|
||||
timeout: 1
|
||||
loop:
|
||||
- 80
|
||||
- 443
|
||||
ignore_errors: yes
|
||||
register: port_check
|
||||
|
||||
- name: Detect virtualization type
|
||||
command: systemd-detect-virt
|
||||
register: virt_type
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Warn if running in LXC
|
||||
debug:
|
||||
msg: |
|
||||
⚠️ RUNNING IN LXC CONTAINER
|
||||
Docker requires nested virtualization.
|
||||
Ensure on LXC host: lxc config set {{ inventory_hostname }} security.nesting true
|
||||
when: "'lxc' in virt_type.stdout"
|
||||
|
||||
- name: Validate DNS resolution for all subdomains
|
||||
command: dig +short {{ item }}.{{ domain }} @8.8.8.8
|
||||
register: dns_check
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop:
|
||||
- "{{ subdomain_nextcloud }}"
|
||||
- "{{ subdomain_office }}"
|
||||
- "{{ subdomain_draw }}"
|
||||
- "{{ subdomain_notes }}"
|
||||
- "{{ subdomain_homarr }}"
|
||||
- "{{ subdomain_dockhand }}"
|
||||
- "{{ subdomain_uptime }}"
|
||||
|
||||
- name: Display DNS check results
|
||||
debug:
|
||||
msg: "{{ item.item }}.{{ domain }} → {{ item.stdout if item.stdout else 'NOT CONFIGURED' }}"
|
||||
loop: "{{ dns_check.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}.{{ domain }}"
|
||||
|
||||
- name: Preflight checks complete
|
||||
debug:
|
||||
msg: |
|
||||
✓ All preflight checks passed
|
||||
✓ Ready to proceed with deployment
|
||||
119
ansible/playbooks/02-system-setup.yml
Normal file
119
ansible/playbooks/02-system-setup.yml
Normal file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
# Playbook 02: System Setup
|
||||
# Install packages, configure firewall and security
|
||||
|
||||
- name: System Setup
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Upgrade all packages
|
||||
apt:
|
||||
upgrade: dist
|
||||
autoremove: yes
|
||||
autoclean: yes
|
||||
|
||||
- name: Install essential packages
|
||||
apt:
|
||||
name:
|
||||
- curl
|
||||
- wget
|
||||
- git
|
||||
- vim
|
||||
- htop
|
||||
- net-tools
|
||||
- dnsutils
|
||||
- ufw
|
||||
- fail2ban
|
||||
- unattended-upgrades
|
||||
- apt-transport-https
|
||||
- ca-certificates
|
||||
- gnupg
|
||||
- lsb-release
|
||||
- software-properties-common
|
||||
- python3-pip
|
||||
- python3-docker
|
||||
- rsync
|
||||
- "{% if install_rclone %}rclone{% endif %}"
|
||||
state: present
|
||||
|
||||
- name: Configure UFW - Allow SSH
|
||||
ufw:
|
||||
rule: allow
|
||||
port: '22'
|
||||
proto: tcp
|
||||
|
||||
- name: Configure UFW - Allow HTTP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: '80'
|
||||
proto: tcp
|
||||
|
||||
- name: Configure UFW - Allow HTTPS TCP
|
||||
ufw:
|
||||
rule: allow
|
||||
port: '443'
|
||||
proto: tcp
|
||||
|
||||
- name: Configure UFW - Allow HTTPS UDP (HTTP/3)
|
||||
ufw:
|
||||
rule: allow
|
||||
port: '443'
|
||||
proto: udp
|
||||
|
||||
- name: Configure UFW - Allow Tailscale
|
||||
ufw:
|
||||
rule: allow
|
||||
port: '41641'
|
||||
proto: udp
|
||||
|
||||
- name: Enable UFW
|
||||
ufw:
|
||||
state: enabled
|
||||
policy: deny
|
||||
|
||||
- name: Configure fail2ban for SSH
|
||||
copy:
|
||||
dest: /etc/fail2ban/jail.local
|
||||
content: |
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 5
|
||||
bantime = 600
|
||||
notify: restart fail2ban
|
||||
|
||||
- name: Enable unattended security updates
|
||||
copy:
|
||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
|
||||
- name: Set timezone
|
||||
timezone:
|
||||
name: "{{ timezone }}"
|
||||
|
||||
- name: Set kernel parameters for Docker
|
||||
sysctl:
|
||||
name: "{{ item.key }}"
|
||||
value: "{{ item.value }}"
|
||||
state: present
|
||||
reload: yes
|
||||
loop:
|
||||
- { key: 'net.ipv4.ip_forward', value: '1' }
|
||||
- { key: 'fs.inotify.max_user_watches', value: '524288' }
|
||||
|
||||
handlers:
|
||||
- name: restart fail2ban
|
||||
service:
|
||||
name: fail2ban
|
||||
state: restarted
|
||||
115
ansible/playbooks/03-docker-setup.yml
Normal file
115
ansible/playbooks/03-docker-setup.yml
Normal file
@@ -0,0 +1,115 @@
|
||||
---
|
||||
# Playbook 03: Docker Setup
|
||||
# Install Docker CE and Docker Compose v2
|
||||
|
||||
- name: Docker Installation
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Remove old Docker installations
|
||||
apt:
|
||||
name:
|
||||
- docker
|
||||
- docker-engine
|
||||
- docker.io
|
||||
- containerd
|
||||
- runc
|
||||
- docker-compose
|
||||
state: absent
|
||||
purge: yes
|
||||
|
||||
- name: Remove old Docker data directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /var/lib/docker
|
||||
- /var/lib/containerd
|
||||
- /etc/docker
|
||||
|
||||
- name: Add Docker GPG key
|
||||
apt_key:
|
||||
url: https://download.docker.com/linux/ubuntu/gpg
|
||||
state: present
|
||||
|
||||
- name: Add Docker repository
|
||||
apt_repository:
|
||||
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
|
||||
state: present
|
||||
|
||||
- name: Install Docker CE
|
||||
apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Create Docker daemon configuration
|
||||
copy:
|
||||
dest: /etc/docker/daemon.json
|
||||
content: |
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
},
|
||||
"storage-driver": "overlay2",
|
||||
"userland-proxy": false,
|
||||
"live-restore": true
|
||||
}
|
||||
notify: restart docker
|
||||
|
||||
- name: Create docker group
|
||||
group:
|
||||
name: docker
|
||||
state: present
|
||||
|
||||
- name: Add user to docker group
|
||||
user:
|
||||
name: "{{ ansible_user }}"
|
||||
groups: docker
|
||||
append: yes
|
||||
|
||||
- name: Create deployment directory
|
||||
file:
|
||||
path: "{{ deployment_dir }}"
|
||||
state: directory
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Start and enable Docker
|
||||
service:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Verify Docker installation
|
||||
command: docker --version
|
||||
register: docker_version
|
||||
changed_when: false
|
||||
|
||||
- name: Display Docker version
|
||||
debug:
|
||||
msg: "Docker installed: {{ docker_version.stdout }}"
|
||||
|
||||
- name: Verify Docker Compose installation
|
||||
command: docker compose version
|
||||
register: compose_version
|
||||
changed_when: false
|
||||
|
||||
- name: Display Docker Compose version
|
||||
debug:
|
||||
msg: "Docker Compose installed: {{ compose_version.stdout }}"
|
||||
|
||||
handlers:
|
||||
- name: restart docker
|
||||
service:
|
||||
name: docker
|
||||
state: restarted
|
||||
60
ansible/playbooks/04-tailscale-setup.yml
Normal file
60
ansible/playbooks/04-tailscale-setup.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
# Playbook 04: Tailscale Setup
|
||||
# Install and optionally activate Tailscale VPN
|
||||
|
||||
- name: Tailscale Installation
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Add Tailscale GPG key
|
||||
apt_key:
|
||||
url: https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_distribution_release }}.noarmor.gpg
|
||||
state: present
|
||||
|
||||
- name: Add Tailscale repository
|
||||
apt_repository:
|
||||
repo: "deb https://pkgs.tailscale.com/stable/ubuntu {{ ansible_distribution_release }} main"
|
||||
state: present
|
||||
|
||||
- name: Install Tailscale
|
||||
apt:
|
||||
name: tailscale
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Check if Tailscale auth key is provided
|
||||
set_fact:
|
||||
tailscale_auto_enable: "{{ tailscale_auth_key is defined and tailscale_auth_key != '' }}"
|
||||
|
||||
- name: Activate Tailscale (if auth key provided)
|
||||
command: tailscale up --authkey={{ tailscale_auth_key }} --advertise-tags=tag:nextcloud
|
||||
when: tailscale_auto_enable
|
||||
register: tailscale_activation
|
||||
|
||||
- name: Get Tailscale IP (if activated)
|
||||
command: tailscale ip -4
|
||||
register: tailscale_ip
|
||||
when: tailscale_auto_enable
|
||||
changed_when: false
|
||||
|
||||
- name: Display Tailscale status (activated)
|
||||
debug:
|
||||
msg: |
|
||||
✓ Tailscale activated
|
||||
IP: {{ tailscale_ip.stdout }}
|
||||
when: tailscale_auto_enable
|
||||
|
||||
- name: Display manual activation instructions (not activated)
|
||||
debug:
|
||||
msg: |
|
||||
Tailscale installed but not activated.
|
||||
To enable, run on the server:
|
||||
sudo tailscale up
|
||||
when: not tailscale_auto_enable
|
||||
|
||||
- name: Enable Tailscale service
|
||||
service:
|
||||
name: tailscaled
|
||||
state: started
|
||||
enabled: yes
|
||||
109
ansible/playbooks/05-deploy-stack.yml
Normal file
109
ansible/playbooks/05-deploy-stack.yml
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
# Playbook 05: Deploy Stack
|
||||
# Deploy Docker Compose stack with all services
|
||||
|
||||
- name: Deploy Nextcloud Stack
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Create directory structure
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ deployment_dir }}/configs"
|
||||
- "{{ deployment_dir }}/configs/caddy"
|
||||
- "{{ deployment_dir }}/configs/nextcloud"
|
||||
- "{{ deployment_dir }}/data"
|
||||
- "{{ deployment_dir }}/data/homarr"
|
||||
- "{{ deployment_dir }}/data/obsidian/config"
|
||||
- "{{ deployment_dir }}/data/obsidian/vault"
|
||||
- "{{ deployment_dir }}/backups"
|
||||
- "{{ deployment_dir }}/backups/database"
|
||||
- "{{ deployment_dir }}/backups/volumes"
|
||||
|
||||
- name: Template docker-compose.yml
|
||||
template:
|
||||
src: ../roles/nextcloud_stack/templates/docker-compose.yml.j2
|
||||
dest: "{{ deployment_dir }}/docker-compose.yml"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Template .env file
|
||||
template:
|
||||
src: ../roles/nextcloud_stack/templates/env.j2
|
||||
dest: "{{ deployment_dir }}/.env"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0600'
|
||||
no_log: true
|
||||
|
||||
- name: Template Caddyfile
|
||||
template:
|
||||
src: ../roles/caddy/templates/Caddyfile.j2
|
||||
dest: "{{ deployment_dir }}/configs/caddy/Caddyfile"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Pull Docker images
|
||||
command: docker compose pull
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
become_user: "{{ ansible_user }}"
|
||||
|
||||
- name: Start Docker Compose stack
|
||||
command: docker compose up -d
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
become_user: "{{ ansible_user }}"
|
||||
|
||||
- name: Wait for PostgreSQL to be healthy
|
||||
command: docker exec next-db pg_isready -U {{ db_user }}
|
||||
register: pg_ready
|
||||
until: pg_ready.rc == 0
|
||||
retries: 30
|
||||
delay: 10
|
||||
changed_when: false
|
||||
|
||||
- name: Wait for Nextcloud to be accessible
|
||||
uri:
|
||||
url: http://localhost:8808/status.php
|
||||
status_code: 200
|
||||
register: nc_status
|
||||
until: nc_status.status == 200
|
||||
retries: 30
|
||||
delay: 10
|
||||
|
||||
- name: Configure Nextcloud Redis cache
|
||||
command: |
|
||||
docker exec -u www-data next php occ config:system:set redis host --value=next-redis
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Configure Nextcloud Redis port
|
||||
command: |
|
||||
docker exec -u www-data next php occ config:system:set redis port --value=6379
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Configure Nextcloud memcache
|
||||
command: |
|
||||
docker exec -u www-data next php occ config:system:set memcache.locking --value='\\OC\\Memcache\\Redis'
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Display deployment success
|
||||
debug:
|
||||
msg: |
|
||||
✓ Docker Compose stack deployed
|
||||
✓ All containers started
|
||||
✓ Nextcloud is accessible
|
||||
48
ansible/playbooks/06-configure-caddy.yml
Normal file
48
ansible/playbooks/06-configure-caddy.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
# Playbook 06: Configure Caddy
|
||||
# Setup reverse proxy and obtain SSL certificates
|
||||
|
||||
- name: Configure Caddy Reverse Proxy
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Validate Caddyfile syntax
|
||||
command: docker exec caddy caddy validate --config /etc/caddy/Caddyfile
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
register: caddy_validate
|
||||
failed_when: caddy_validate.rc != 0
|
||||
changed_when: false
|
||||
|
||||
- name: Reload Caddy configuration
|
||||
command: docker exec caddy caddy reload --config /etc/caddy/Caddyfile
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
|
||||
- name: Wait for SSL certificates (may take 1-2 minutes)
|
||||
pause:
|
||||
seconds: 30
|
||||
prompt: "Waiting for Let's Encrypt to issue certificates..."
|
||||
|
||||
- name: Test HTTPS endpoint for Nextcloud
|
||||
uri:
|
||||
url: "https://{{ subdomain_nextcloud }}.{{ domain }}/status.php"
|
||||
validate_certs: yes
|
||||
status_code: 200
|
||||
register: https_test
|
||||
until: https_test.status == 200
|
||||
retries: 10
|
||||
delay: 10
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Display Caddy status
|
||||
debug:
|
||||
msg: |
|
||||
✓ Caddyfile validated
|
||||
✓ Caddy reloaded
|
||||
{% if https_test.status == 200 %}
|
||||
✓ HTTPS working: https://{{ subdomain_nextcloud }}.{{ domain }}
|
||||
{% else %}
|
||||
⚠ HTTPS check failed - verify DNS and firewall
|
||||
{% endif %}
|
||||
87
ansible/playbooks/07-setup-backups.yml
Normal file
87
ansible/playbooks/07-setup-backups.yml
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
# Playbook 07: Setup Backups
|
||||
# Configure automated backup system
|
||||
|
||||
- name: Setup Backup System
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Create backup script
|
||||
copy:
|
||||
dest: "{{ deployment_dir }}/backup.sh"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ ansible_user }}"
|
||||
mode: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
# Nextcloud Stack Backup Script
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DIR="{{ deployment_dir }}/backups"
|
||||
DB_BACKUP_DIR="$BACKUP_DIR/database"
|
||||
VOLUME_BACKUP_DIR="$BACKUP_DIR/volumes"
|
||||
RETENTION_DAYS={{ backup_retention_days }}
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
LOG_FILE="$BACKUP_DIR/backup.log"
|
||||
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "Starting backup process..."
|
||||
|
||||
# Database backup
|
||||
log "Backing up PostgreSQL database..."
|
||||
docker exec next-db pg_dump -U {{ db_user }} {{ db_name }} | \
|
||||
gzip > "$DB_BACKUP_DIR/nextcloud_db_$DATE.sql.gz"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
log "Database backup completed: nextcloud_db_$DATE.sql.gz"
|
||||
else
|
||||
log "ERROR: Database backup failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Weekly volume backup (Sundays only)
|
||||
if [ $(date +%u) -eq 7 ]; then
|
||||
log "Weekly volume backup (Sunday)..."
|
||||
docker exec -u www-data next php occ maintenance:mode --on
|
||||
|
||||
tar -czf "$VOLUME_BACKUP_DIR/nextcloud_data_$DATE.tar.gz" \
|
||||
-C /var/lib/docker/volumes/nextcloud_nextcloud_data/_data . 2>/dev/null || true
|
||||
|
||||
tar -czf "$VOLUME_BACKUP_DIR/configs_$DATE.tar.gz" \
|
||||
-C {{ deployment_dir }}/configs . 2>/dev/null || true
|
||||
|
||||
docker exec -u www-data next php occ maintenance:mode --off
|
||||
log "Volume backup completed"
|
||||
fi
|
||||
|
||||
# Cleanup old backups
|
||||
log "Cleaning up backups older than $RETENTION_DAYS days..."
|
||||
find "$DB_BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
|
||||
find "$VOLUME_BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
|
||||
|
||||
log "Backup process completed successfully!"
|
||||
|
||||
- name: Create cron job for daily backups
|
||||
cron:
|
||||
name: "Nextcloud Stack Backup"
|
||||
minute: "0"
|
||||
hour: "3"
|
||||
job: "{{ deployment_dir }}/backup.sh >> {{ deployment_dir }}/backups/backup.log 2>&1"
|
||||
user: root
|
||||
|
||||
- name: Run initial test backup
|
||||
command: "{{ deployment_dir }}/backup.sh"
|
||||
register: backup_test
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Display backup status
|
||||
debug:
|
||||
msg: |
|
||||
✓ Backup script created
|
||||
✓ Cron job configured (daily 3:00 AM)
|
||||
✓ Test backup completed
|
||||
Location: {{ deployment_dir }}/backups/
|
||||
154
ansible/playbooks/08-post-deployment.yml
Normal file
154
ansible/playbooks/08-post-deployment.yml
Normal file
@@ -0,0 +1,154 @@
|
||||
---
|
||||
# Playbook 08: Post-Deployment
|
||||
# Final verification and configuration
|
||||
|
||||
- name: Post-Deployment Tasks
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Verify all containers are running
|
||||
command: docker compose ps --format json
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
register: container_status
|
||||
changed_when: false
|
||||
|
||||
- name: Check Nextcloud status
|
||||
command: docker exec -u www-data next php occ status
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
register: nc_status
|
||||
changed_when: false
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Install recommended Nextcloud apps
|
||||
command: docker exec -u www-data next php occ app:install {{ item }}
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
loop:
|
||||
- calendar
|
||||
- contacts
|
||||
- tasks
|
||||
- notes
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Configure Nextcloud background jobs
|
||||
command: docker exec -u www-data next php occ background:cron
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Setup Nextcloud cron job
|
||||
cron:
|
||||
name: "Nextcloud Background Jobs"
|
||||
minute: "*/5"
|
||||
job: "docker exec -u www-data next php /var/www/html/cron.php"
|
||||
user: root
|
||||
|
||||
- name: Get Tailscale IP (if activated)
|
||||
command: tailscale ip -4
|
||||
register: tailscale_ip_result
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Create deployment report
|
||||
copy:
|
||||
dest: "{{ deployment_dir }}/DEPLOYMENT.txt"
|
||||
content: |
|
||||
════════════════════════════════════════════════════════════
|
||||
NEXTCLOUD STACK DEPLOYMENT REPORT
|
||||
════════════════════════════════════════════════════════════
|
||||
|
||||
Server: {{ inventory_hostname }}
|
||||
IP Address: {{ ansible_host }}
|
||||
Domain: {{ domain }}
|
||||
Deployment Date: {{ ansible_date_time.iso8601 }}
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
PUBLIC SERVICES (HTTPS)
|
||||
────────────────────────────────────────────────────────────
|
||||
• Nextcloud: https://{{ subdomain_nextcloud }}.{{ domain }}
|
||||
• OnlyOffice: https://{{ subdomain_office }}.{{ domain }}
|
||||
• Excalidraw: https://{{ subdomain_draw }}.{{ domain }}
|
||||
• Obsidian: https://{{ subdomain_notes }}.{{ domain }}
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
MANAGEMENT SERVICES (Tailscale only)
|
||||
────────────────────────────────────────────────────────────
|
||||
• Homarr: https://{{ subdomain_homarr }}.{{ domain }}
|
||||
• Dockhand: https://{{ subdomain_dockhand }}.{{ domain }}
|
||||
• Uptime Kuma: https://{{ subdomain_uptime }}.{{ domain }}
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
CREDENTIALS
|
||||
────────────────────────────────────────────────────────────
|
||||
Nextcloud Admin User: {{ admin_user }}
|
||||
Nextcloud Admin Password: [stored in Ansible vault]
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
TAILSCALE
|
||||
────────────────────────────────────────────────────────────
|
||||
{% if tailscale_ip_result.rc == 0 %}
|
||||
Status: Connected
|
||||
Tailscale IP: {{ tailscale_ip_result.stdout }}
|
||||
{% else %}
|
||||
Status: Not activated
|
||||
Activate with: sudo tailscale up
|
||||
{% endif %}
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
BACKUPS
|
||||
────────────────────────────────────────────────────────────
|
||||
Schedule: Daily at 3:00 AM
|
||||
Location: {{ deployment_dir }}/backups/
|
||||
Retention: {{ backup_retention_days }} days
|
||||
|
||||
────────────────────────────────────────────────────────────
|
||||
USEFUL COMMANDS
|
||||
────────────────────────────────────────────────────────────
|
||||
View containers: cd {{ deployment_dir }} && docker compose ps
|
||||
View logs: cd {{ deployment_dir }} && docker compose logs -f
|
||||
Restart service: cd {{ deployment_dir }} && docker compose restart [service]
|
||||
Manual backup: {{ deployment_dir }}/backup.sh
|
||||
Nextcloud CLI: docker exec -u www-data next php occ [command]
|
||||
|
||||
════════════════════════════════════════════════════════════
|
||||
|
||||
- name: Display deployment summary
|
||||
debug:
|
||||
msg: |
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ DEPLOYMENT COMPLETED SUCCESSFULLY! ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
|
||||
Server: {{ inventory_hostname }} ({{ ansible_host }})
|
||||
Domain: {{ domain }}
|
||||
|
||||
📦 Public Services:
|
||||
• Nextcloud: https://{{ subdomain_nextcloud }}.{{ domain }}
|
||||
• OnlyOffice: https://{{ subdomain_office }}.{{ domain }}
|
||||
• Excalidraw: https://{{ subdomain_draw }}.{{ domain }}
|
||||
• Obsidian: https://{{ subdomain_notes }}.{{ domain }}
|
||||
|
||||
🔒 Management (Tailscale only):
|
||||
• Homarr: https://{{ subdomain_homarr }}.{{ domain }}
|
||||
• Dockhand: https://{{ subdomain_dockhand }}.{{ domain }}
|
||||
• Uptime Kuma: https://{{ subdomain_uptime }}.{{ domain }}
|
||||
|
||||
👤 Nextcloud Admin:
|
||||
Username: {{ admin_user }}
|
||||
Password: [check vault]
|
||||
|
||||
💾 Backups:
|
||||
Daily at 3:00 AM
|
||||
Location: {{ deployment_dir }}/backups/
|
||||
|
||||
📝 Next Steps:
|
||||
1. Login to Nextcloud and complete setup
|
||||
2. Setup Uptime Kuma monitoring (via Tailscale)
|
||||
3. Configure Homarr dashboard (via Tailscale)
|
||||
4. Review deployment report: {{ deployment_dir }}/DEPLOYMENT.txt
|
||||
|
||||
Deployment report saved to:
|
||||
{{ deployment_dir }}/DEPLOYMENT.txt
|
||||
41
ansible/playbooks/99-rollback.yml
Normal file
41
ansible/playbooks/99-rollback.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
# Playbook 99: Emergency Rollback
|
||||
# Stop and remove the deployment (keeps backups)
|
||||
|
||||
- name: Emergency Rollback
|
||||
hosts: all
|
||||
become: yes
|
||||
|
||||
tasks:
|
||||
- name: Confirm rollback
|
||||
pause:
|
||||
prompt: |
|
||||
⚠️ WARNING: This will stop and remove all containers!
|
||||
Backups in {{ deployment_dir }}/backups/ will be preserved.
|
||||
Press ENTER to continue or Ctrl+C to cancel
|
||||
|
||||
- name: Stop Docker Compose stack
|
||||
command: docker compose down
|
||||
args:
|
||||
chdir: "{{ deployment_dir }}"
|
||||
become_user: "{{ ansible_user }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Remove deployment directory (except backups)
|
||||
shell: |
|
||||
cd {{ deployment_dir }}
|
||||
rm -rf configs data docker-compose.yml .env
|
||||
ls -la
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: Display rollback status
|
||||
debug:
|
||||
msg: |
|
||||
✓ Containers stopped and removed
|
||||
✓ Deployment files removed
|
||||
✓ Backups preserved in {{ deployment_dir }}/backups/
|
||||
✓ Docker volumes preserved (use 'docker volume ls' to see)
|
||||
|
||||
To completely remove volumes (DELETES ALL DATA):
|
||||
cd {{ deployment_dir }} && docker compose down -v
|
||||
26
ansible/playbooks/site.yml
Normal file
26
ansible/playbooks/site.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# Main Playbook - Nextcloud Stack Deployment
|
||||
# This orchestrates the complete deployment process
|
||||
|
||||
- name: Nextcloud Stack - Complete Deployment
|
||||
hosts: all
|
||||
gather_facts: yes
|
||||
|
||||
pre_tasks:
|
||||
- name: Display deployment banner
|
||||
debug:
|
||||
msg: |
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ Nextcloud Stack Deployment Starting ║
|
||||
║ Target: {{ inventory_hostname }} ({{ ansible_host }}) ║
|
||||
║ Domain: {{ domain }} ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
|
||||
- import_playbook: 01-preflight-checks.yml
|
||||
- import_playbook: 02-system-setup.yml
|
||||
- import_playbook: 03-docker-setup.yml
|
||||
- import_playbook: 04-tailscale-setup.yml
|
||||
- import_playbook: 05-deploy-stack.yml
|
||||
- import_playbook: 06-configure-caddy.yml
|
||||
- import_playbook: 07-setup-backups.yml
|
||||
- import_playbook: 08-post-deployment.yml
|
||||
Reference in New Issue
Block a user