Files
dotfiles_arch/ansible/README.md
2026-02-16 23:40:30 +01:00

9.6 KiB

Nextcloud Stack - Automated Deployment with Ansible

Complete automation for deploying a self-hosted Nextcloud productivity stack on Ubuntu-based LXC/VPS servers.

Features

  • 12 Services: Nextcloud, OnlyOffice, Excalidraw, Obsidian, Homarr, Dockhand, Uptime Kuma, PostgreSQL, Redis, Caddy, Watchtower
  • Automatic SSL: Let's Encrypt certificates via Caddy
  • Secure Management: Tailscale-only access for admin interfaces
  • Auto-updates: Watchtower with safety exclusions for critical services
  • Automated Backups: Daily database backups, weekly volume backups (30-day retention)
  • Monitoring: Uptime Kuma with configurable alerts
  • Multi-server: Deploy to multiple VPS servers with unique domains

Quick Start

Prerequisites

  1. Control Machine (your laptop):

    • Ansible 2.14+ installed
    • SSH access to target servers
  2. Target Server(s):

    • Ubuntu 20.04+ (LXC container or VPS)
    • Root or sudo access
    • Minimum 100GB disk space
    • Ports 80, 443 available
  3. DNS Configuration (BEFORE deployment):

    cloud.yourdomain.com    → YOUR_SERVER_IP
    office.yourdomain.com   → YOUR_SERVER_IP
    draw.yourdomain.com     → YOUR_SERVER_IP
    notes.yourdomain.com    → YOUR_SERVER_IP
    home.yourdomain.com     → YOUR_SERVER_IP
    manage.yourdomain.com   → YOUR_SERVER_IP
    uptime.yourdomain.com   → YOUR_SERVER_IP
    

Installation

  1. Clone this repository:

    git clone <your-repo-url>
    cd ansible-nextcloud-deployment
    
  2. Run interactive setup:

    ./setup.sh
    

    This will ask for:

    • Server IP addresses and domains
    • Your name and email
    • Admin credentials
    • Subdomain preferences
    • Tailscale auth key (optional)
    • Monitoring email
    • Ansible Vault password
  3. Deploy the stack:

    make deploy
    

    Or manually:

    ansible-playbook playbooks/site.yml --ask-vault-pass
    
  4. Access your services:

    • Nextcloud: https://cloud.yourdomain.com
    • OnlyOffice: https://office.yourdomain.com
    • Homarr (Tailscale only): https://home.yourdomain.com
    • Uptime Kuma (Tailscale only): https://uptime.yourdomain.com

Project Structure

ansible-nextcloud-deployment/
├── setup.sh                      # Interactive configuration script
├── Makefile                      # Convenient command shortcuts
├── ansible.cfg                   # Ansible configuration
├── inventory/
│   ├── hosts.yml                # Generated by setup.sh
│   └── group_vars/all/
│       ├── vars.yml             # Public variables
│       └── vault.yml            # Encrypted secrets
├── playbooks/
│   ├── site.yml                 # Main orchestrator
│   ├── 01-preflight-checks.yml  # Pre-deployment validation
│   ├── 02-system-setup.yml      # System packages & security
│   ├── 03-docker-setup.yml      # Docker installation
│   ├── 04-tailscale-setup.yml   # VPN setup
│   ├── 05-deploy-stack.yml      # Docker Compose deployment
│   ├── 06-configure-caddy.yml   # Reverse proxy configuration
│   ├── 07-setup-backups.yml     # Backup automation
│   └── 08-post-deployment.yml   # Final verification
└── roles/
    ├── nextcloud_stack/
    │   └── templates/
    │       ├── docker-compose.yml.j2
    │       └── env.j2
    └── caddy/
        └── templates/
            └── Caddyfile.j2

Makefile Commands

make help          # Show all commands
make setup         # Run interactive setup
make ping          # Test connectivity
make check         # Run preflight checks
make deploy        # Full deployment
make deploy-dry    # Dry run (no changes)
make status        # Show container status
make logs          # View container logs
make backup        # Run manual backup
make restart       # Restart all containers
make edit-vault    # Edit encrypted secrets

Service Stack

Service Purpose Port Access Auto-Update
Caddy Reverse proxy + SSL 80, 443 Public
Nextcloud File sync & collaboration Internal Public (via Caddy) Manual
PostgreSQL 18 Database Internal Internal only Manual
Redis 7 Cache layer Internal Internal only Manual
OnlyOffice Document editor Internal Public (via Caddy) 👁️ Monitor
Excalidraw Whiteboard tool Internal Public (via Caddy)
Obsidian Note-taking Internal Public (via Caddy)
Homarr Dashboard Internal Tailscale only
Dockhand Container manager 3003 Tailscale only
Uptime Kuma Monitoring Internal Tailscale only
Watchtower Auto-updater N/A N/A N/A

Security Features

  • Firewall: UFW configured with minimal open ports
  • Fail2ban: SSH brute-force protection
  • Automatic Updates: Unattended security updates enabled
  • Secret Management: Ansible Vault encryption for all credentials
  • Access Control: Management UIs restricted to Tailscale network
  • SSL/TLS: Automatic Let's Encrypt certificates
  • Container Isolation: Dedicated Docker network

Backup System

  • Daily: PostgreSQL database dumps (3:00 AM)
  • Weekly: Full volume backups (Sundays)
  • Retention: 30 days
  • Location: /opt/nextcloud-stack/backups/
  • rclone: Pre-installed for future remote backups

Manual Backup

ssh user@server
cd /opt/nextcloud-stack
./backup.sh

Restore from Backup

See BACKUP_RESTORE.md for detailed procedures.

Tailscale Setup

If you didn't provide an auth key during setup:

ssh user@server
sudo tailscale up

Then access management interfaces via Tailscale IP or MagicDNS.

Updating Services

Safe to Auto-Update (Watchtower handles)

  • Caddy, Excalidraw, Obsidian, Homarr, Dockhand, Uptime Kuma

Monitor Only (notifications, no auto-update)

  • OnlyOffice

Manual Update Required

  • Nextcloud
  • PostgreSQL
  • Redis

Updating Nextcloud Manually

ssh user@server
cd /opt/nextcloud-stack

# 1. Backup
./backup.sh

# 2. Enable maintenance mode
docker exec -u www-data next php occ maintenance:mode --on

# 3. Update
docker compose pull next
docker compose up -d next

# 4. Run database migrations
docker exec -u www-data next php occ upgrade

# 5. Disable maintenance mode
docker exec -u www-data next php occ maintenance:mode --off

Troubleshooting

DNS Not Configured

Error: Let's Encrypt fails to issue certificates

Solution: Ensure all DNS A records point to your server IP. Check with:

dig +short cloud.yourdomain.com

LXC Container Issues

Error: Docker fails to start

Solution: On LXC host, enable nested virtualization:

lxc config set CONTAINER_NAME security.nesting true
lxc restart CONTAINER_NAME

Port Already in Use

Error: Port 80 or 443 already bound

Solution: Check what's using the ports:

sudo ss -tlnp | grep ':80\|:443'
sudo systemctl stop apache2  # or nginx

Nextcloud Stuck in Maintenance Mode

docker exec -u www-data next php occ maintenance:mode --off

View Logs

cd /opt/nextcloud-stack
docker compose logs -f [service-name]

Post-Deployment Tasks

  1. Login to Nextcloud:

    • URL: https://cloud.yourdomain.com
    • Username: (set during setup)
    • Password: (stored in vault)
  2. Setup Uptime Kuma:

    • URL: https://uptime.yourdomain.com (via Tailscale)
    • Create admin account on first visit
    • Configure monitors for your services
  3. Configure Homarr Dashboard:

    • URL: https://home.yourdomain.com (via Tailscale)
    • Add service tiles
    • Customize layout
  4. Configure OnlyOffice in Nextcloud:

    • Nextcloud Settings → Administration → Office
    • Document Editing Service: https://office.yourdomain.com
  5. Test Backups:

    make backup
    

File Locations on Server

/opt/nextcloud-stack/
├── docker-compose.yml
├── .env
├── backup.sh
├── configs/
│   ├── caddy/Caddyfile
│   └── nextcloud/
├── data/
│   ├── homarr/
│   └── obsidian/
└── backups/
    ├── database/
    └── volumes/

Environment Variables

All secrets are stored in inventory/group_vars/all/vault.yml (encrypted).

To edit:

make edit-vault

Multiple Server Deployment

The setup script supports multiple servers. Each can have its own domain:

Server 1: 192.168.1.100 → cloud1.example.com
Server 2: 192.168.1.101 → cloud2.anotherdomain.net
Server 3: 192.168.1.102 → personal.mydomain.org

Deploy to all:

make deploy

Deploy to specific server:

ansible-playbook playbooks/site.yml --limit server_hostname --ask-vault-pass

Maintenance

Check Container Status

make status

Restart Services

make restart

Update Images (safe services only)

make update

View Logs

make logs

Uninstallation

ssh user@server
cd /opt/nextcloud-stack
docker compose down -v  # WARNING: Deletes all data!
cd /opt
rm -rf nextcloud-stack

Support

License

MIT

Acknowledgments

  • Nextcloud team
  • Caddy web server
  • Ansible community
  • All open-source contributors

Built with ❤️ for self-hosting enthusiasts