# 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**:
   ```bash
   git clone <your-repo-url>
   cd ansible-nextcloud-deployment
   ```

2. **Run interactive setup**:
   ```bash
   ./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**:
   ```bash
   make deploy
   ```
   
   Or manually:
   ```bash
   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

```bash
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

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

### Restore from Backup

See [BACKUP_RESTORE.md](BACKUP_RESTORE.md) for detailed procedures.

## Tailscale Setup

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

```bash
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

```bash
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:
```bash
dig +short cloud.yourdomain.com
```

### LXC Container Issues
**Error**: Docker fails to start

**Solution**: On LXC host, enable nested virtualization:
```bash
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:
```bash
sudo ss -tlnp | grep ':80\|:443'
sudo systemctl stop apache2  # or nginx
```

### Nextcloud Stuck in Maintenance Mode
```bash
docker exec -u www-data next php occ maintenance:mode --off
```

### View Logs
```bash
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**:
   ```bash
   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:
```bash
make edit-vault
```

## Multiple Server Deployment

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

```bash
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:
```bash
make deploy
```

Deploy to specific server:
```bash
ansible-playbook playbooks/site.yml --limit server_hostname --ask-vault-pass
```

## Maintenance

### Check Container Status
```bash
make status
```

### Restart Services
```bash
make restart
```

### Update Images (safe services only)
```bash
make update
```

### View Logs
```bash
make logs
```

## Uninstallation

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

## Support

- See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for common issues
- See [BACKUP_RESTORE.md](BACKUP_RESTORE.md) for backup procedures
- See [AGENTS.md](AGENTS.md) for development guidelines

## License

MIT

## Acknowledgments

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

---

**Built with ❤️ for self-hosting enthusiasts**
