Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions services/nextcloud/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#version=1.1
#URL=https://github.com/tailscale-dev/ScaleTail
#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure.

# Service Configuration
SERVICE=nextcloud
IMAGE_URL=nextcloud:apache # Docker image URL from container registry

# Network Configuration
SERVICEPORT=80 # Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable.
DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable.

# Tailscale Configuration
TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions.

# Time Zone setting for containers
TZ=UTC # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

# Database Configuration (MariaDB)
MYSQL_ROOT_PASSWORD= # Set a strong root password
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD= # Set a strong database password

# Nextcloud Admin Credentials (auto-created on first run)
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD= # Set a strong admin password
NEXTCLOUD_TRUSTED_DOMAINS= # Set to your Nextcloud domain (e.g., nextcloud.your-tailnet.ts.net)

# Optional Service variables
# PUID=1000
# PHP_MEMORY_LIMIT=512M
# PHP_UPLOAD_LIMIT=512M

#EXAMPLE_VAR="Environment varibale"
61 changes: 61 additions & 0 deletions services/nextcloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Nextcloud with Tailscale Sidecar Configuration

This Docker Compose configuration sets up [Nextcloud](https://github.com/nextcloud/docker) with Tailscale as a sidecar container to securely access your files and collaboration tools over your Tailnet. By using Tailscale in a sidecar configuration, you get automatic HTTPS with a URL like `https://nextcloud.your-tailnet.ts.net` without exposing anything to the public internet.

## Nextcloud

[Nextcloud](https://nextcloud.com) is a self-hosted platform for file sync, sharing, and collaboration. It provides a web interface for documents, calendars, contacts, and media, along with desktop and mobile apps for all major platforms. When paired with Tailscale, your Nextcloud instance becomes accessible across all your trusted devices through your secure Tailnet, with no need for port forwarding or complex reverse proxy configurations.

## Configuration Overview

In this setup, the `tailscale-nextcloud` service runs Tailscale, which manages secure networking for the Nextcloud stack. The `nextcloud`, `db`, and `redis` services all use the Tailscale network stack via Docker's `network_mode: service:` configuration. This keeps your entire Nextcloud stack Tailnet-only unless you intentionally expose ports.

This stack includes four containers:
- **Tailscale** - Manages networking and exposes Nextcloud via Tailscale Serve with automatic HTTPS
- **Nextcloud** - The application server (Apache image, port 80)
- **MariaDB** - Database backend (LTS release)
- **Redis** - Caching and file locking to prevent performance issues

## Prerequisites

- Docker and Docker Compose installed
- A Tailscale auth key from the [Tailscale Admin Console](https://login.tailscale.com/admin/settings/keys)
- Your host user should be in the `docker` group

## Getting Started

1. Copy `templates/service-template` into `services/nextcloud` (or clone this repo)
2. Edit the `.env` file and set strong passwords for:
- `MYSQL_ROOT_PASSWORD`
- `MYSQL_PASSWORD`
- `NEXTCLOUD_ADMIN_PASSWORD`
3. Set your Tailscale auth key in `TS_AUTHKEY`
4. Run `docker compose up -d`
5. Access Nextcloud at `https://nextcloud.your-tailnet.ts.net` from any device on your Tailnet

## Trusted Domains

The `NEXTCLOUD_TRUSTED_DOMAINS` variable in `compose.yaml` is set to `${SERVICE}.tail12345.ts.net` by default. You should update this to match your actual Tailscale domain. You can find your domain in the Tailscale Admin Console under **DNS** settings.

## Volumes

| Volume | Purpose |
|--------|---------|
| `./nextcloud-data/html` | Nextcloud application and configuration files |
| `./nextcloud-data/db` | MariaDB database files |

Pre-creating these directories is optional; Docker will create them automatically with root ownership.

## Files to check

Please check the following contents for validity as some variables need to be defined upfront.

- `.env`
- Required: `TS_AUTHKEY`
- Required: `MYSQL_ROOT_PASSWORD`, `MYSQL_PASSWORD`, `NEXTCLOUD_ADMIN_PASSWORD` - change all from defaults

## Upstream Documentation

- [Nextcloud Docker Documentation](https://github.com/nextcloud/docker)
- [Nextcloud Admin Manual](https://docs.nextcloud.com/server/latest/admin_manual/)
- [Nextcloud Docker Compose Examples](https://github.com/nextcloud/docker#usage)
114 changes: 114 additions & 0 deletions services/nextcloud/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
configs:
ts-serve:
content: |
{"TCP":{"443":{"HTTPS":true}},
"Web":{"$${TS_CERT_DOMAIN}:443":
{"Handlers":{"/":
{"Proxy":"http://127.0.0.1:80"}}}},
"AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}

services:
# Make sure you have updated/checked the .env file with the correct variables.
# All the ${ xx } need to be defined there.
# Tailscale Sidecar Configuration
tailscale:
image: tailscale/tailscale:latest # Image to be used
container_name: tailscale-${SERVICE} # Name for local container management
hostname: ${SERVICE} # Name used within your Tailscale environment
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required
- TS_USERSPACE=false
- TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz"
- TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The <addr>:<port> for the healthz endpoint
#- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS
- TS_AUTH_ONCE=true
configs:
- source: ts-serve
target: /config/serve.json
volumes:
- ./config:/config # Config folder used to store Tailscale files - you may need to change the path
- ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path
devices:
- /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work
cap_add:
- net_admin # Tailscale requirement
#ports:
# - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICEPORT} to the local network - may be removed if only exposure to your Tailnet is required
# If any DNS issues arise, use your preferred DNS provider by uncommenting the config below
#dns:
# - ${DNS_SERVER}
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 10s # Time to wait before starting health checks
restart: always

# ${SERVICE}
application:
image: ${IMAGE_URL} # Image to be used
network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale
container_name: app-${SERVICE} # Name for local container management
environment:
- MYSQL_HOST=127.0.0.1
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=localhost
- REDIS_HOST_PORT=6379
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_TRUSTED_DOMAINS}
- OVERWRITEPROTOCOL=https
- TZ=${TZ}
volumes:
- ./${SERVICE}-data/html:/var/www/html
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
tailscale:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/status.php"] # Check if Nextcloud status endpoint responds
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 60s # Time to wait before starting health checks - Nextcloud needs time to initialize
restart: always

db:
image: mariadb:lts # MariaDB LTS for production use
network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale
container_name: app-${SERVICE}-database # Name for local container management
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW # Required MariaDB configuration for Nextcloud
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- ./${SERVICE}-data/db:/var/lib/mysql
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"] # Check if MariaDB is responsive
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 30s # Time to wait before starting health checks
restart: always

redis:
image: redis:alpine # Redis for caching and file locking
network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale
container_name: app-${SERVICE}-redis # Name for local container management
healthcheck:
test: ["CMD", "redis-cli", "ping"] # Check if Redis responds to ping
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 10s # Time to wait before starting health checks
restart: always
17 changes: 17 additions & 0 deletions services/tailscale-exit-wireguard/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#version=1.1

# Service Configuration
SERVICE=exit-wireguard

# Tailscale Configuration
TS_AUTHKEY= # Your Tailscale auth key from https://login.tailscale.com/admin/settings/keys

# WireGuard (ProtonVPN) Configuration
# Place your ProtonVPN WireGuard config file at ./wireguard/config/wg0.conf

# Time Zone setting for containers
TZ=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

# Optional Service variables
PUID=1000
PGID=1000
110 changes: 110 additions & 0 deletions services/tailscale-exit-wireguard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Tailscale Exit Node with WireGuard (ProtonVPN) Sidecar

This Docker Compose configuration sets up a Tailscale Exit Node that routes all traffic through a WireGuard VPN tunnel (e.g., ProtonVPN). Devices on your Tailscale network can use this node as an exit point, ensuring all their internet traffic is encrypted and routed through your VPN provider.

## Architecture

```
Device → Tailscale Exit Node → WireGuard (ProtonVPN) → Internet
```

- **WireGuard** runs the ProtonVPN tunnel as a VPN client
- **Tailscale** advertises itself as an exit node, routing traffic through WireGuard
- When you select this exit node on any Tailscale device, your traffic flows through ProtonVPN

## Configuration Overview

### WireGuard Service

- Uses `linuxserver/wireguard` image to run the ProtonVPN WireGuard tunnel as a **client**
- Requires your ProtonVPN WireGuard config file at `./wireguard/config/wg0.conf`
- No ports are exposed - WireGuard connects outbound to ProtonVPN only
- Handles IP forwarding and NAT for VPN traffic

### Tailscale Exit Node

- Uses `network_mode: service:wireguard` to share WireGuard's network namespace
- Advertises itself as an exit node via `--advertise-exit-node`
- All Tailscale traffic is routed through the WireGuard tunnel

## Setup Instructions

### 1. Get a Tailscale Auth Key

1. Go to [Tailscale Admin](https://login.tailscale.com/admin/settings/keys)
2. Generate a new auth key
3. Set `TS_AUTHKEY` in the `.env` file

### 2. Get Your ProtonVPN WireGuard Config

1. Go to [ProtonVPN Dashboard](https://account.protonvpn.com/vpn/dashboard)
2. Download the WireGuard configuration for your desired server
3. Create the config directory and place the file:

```bash
mkdir -p wireguard/config
cp /path/to/your/protonvpn-wg0.conf ./wireguard/config/wg0.conf
```

### 3. Configure Environment Variables

Edit the `.env` file with your settings:

| Variable | Description | Default |
|----------|-------------|---------|
| `TS_AUTHKEY` | Tailscale auth key (required) | - |
| `TZ` | Timezone | `Europe/Amsterdam` |

### 4. Enable Exit Node on Tailscale

After starting the stack:

1. Go to [Tailscale Admin](https://login.tailscale.com/admin/machines)
2. Find your exit node machine
3. Click the `...` menu → **Edit route settings**
4. Enable the exit node

### 5. Use the Exit Node

On any Tailscale device:

```bash
# Linux/macOS
tailscale up --exit-node=<exit-node-name>

# Or select it in the Tailscale app UI
```

## File Structure

```
tailscale-exit-wireguard/
├── compose.yaml # Docker Compose configuration
├── .env # Environment variables
├── README.md # This file
├── wireguard/
│ └── config/
│ └── wg0.conf # Your ProtonVPN WireGuard config
└── ts/
└── state/ # Tailscale state (auto-created)
```

## Troubleshooting

### WireGuard not connecting

- Verify your `wg0.conf` is valid: `docker compose exec wireguard cat /config/wg0.conf`
- Check WireGuard logs: `docker compose logs wireguard`
- Ensure the config file has no BOM or Windows line endings

### Tailscale not advertising exit node

- Check Tailscale status: `docker compose exec tailscale tailscale status`
- Verify exit node is enabled in Tailscale admin panel
- Check Tailscale logs: `docker compose logs tailscale`

### Health check failing

- WireGuard health check runs `wg show wg0` to verify the interface is up
- Tailscale health check hits `http://127.0.0.1:41234/healthz`
- Both services must be healthy for the stack to work correctly
Loading