From 08e787b7d4ea1a4897c5abcdc7d2a8bea769ea1c Mon Sep 17 00:00:00 2001 From: he Date: Sun, 12 Jul 2026 11:07:53 -0400 Subject: [PATCH 1/3] Added service nextcloud --- services/nextcloud/.env | 34 ++++++++++ services/nextcloud/README.md | 61 ++++++++++++++++++ services/nextcloud/compose.yaml | 111 ++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 services/nextcloud/.env create mode 100644 services/nextcloud/README.md create mode 100644 services/nextcloud/compose.yaml diff --git a/services/nextcloud/.env b/services/nextcloud/.env new file mode 100644 index 0000000..f0aad65 --- /dev/null +++ b/services/nextcloud/.env @@ -0,0 +1,34 @@ +#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=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + +# Database Configuration (MariaDB) +MYSQL_ROOT_PASSWORD=change-me-to-a-strong-root-password +MYSQL_DATABASE=nextcloud +MYSQL_USER=nextcloud +MYSQL_PASSWORD=change-me-to-a-strong-password + +# Nextcloud Admin Credentials (auto-created on first run) +NEXTCLOUD_ADMIN_USER=admin +NEXTCLOUD_ADMIN_PASSWORD=change-me-to-a-strong-admin-password + +# Optional Service variables +# PUID=1000 +# PHP_MEMORY_LIMIT=512M +# PHP_UPLOAD_LIMIT=512M + +#EXAMPLE_VAR="Environment varibale" diff --git a/services/nextcloud/README.md b/services/nextcloud/README.md new file mode 100644 index 0000000..2cb46b8 --- /dev/null +++ b/services/nextcloud/README.md @@ -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) diff --git a/services/nextcloud/compose.yaml b/services/nextcloud/compose.yaml new file mode 100644 index 0000000..5e35ddc --- /dev/null +++ b/services/nextcloud/compose.yaml @@ -0,0 +1,111 @@ +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 : 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=localhost + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER} + - NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD} + - NEXTCLOUD_TRUSTED_DOMAINS=${SERVICE}.tail12345.ts.net + - 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 From 686dc359faf9fe3df7a17ce6a2a36ac6809c020e Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 16 Jul 2026 01:55:49 -0400 Subject: [PATCH 2/3] added services --- services/nextcloud/.env | 9 +++++---- services/nextcloud/compose.yaml | 7 +++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/services/nextcloud/.env b/services/nextcloud/.env index f0aad65..0355c41 100644 --- a/services/nextcloud/.env +++ b/services/nextcloud/.env @@ -14,17 +14,18 @@ DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" se 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=Europe/Amsterdam # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +TZ=UTC # See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones # Database Configuration (MariaDB) -MYSQL_ROOT_PASSWORD=change-me-to-a-strong-root-password +MYSQL_ROOT_PASSWORD= # Set a strong root password MYSQL_DATABASE=nextcloud MYSQL_USER=nextcloud -MYSQL_PASSWORD=change-me-to-a-strong-password +MYSQL_PASSWORD= # Set a strong database password # Nextcloud Admin Credentials (auto-created on first run) NEXTCLOUD_ADMIN_USER=admin -NEXTCLOUD_ADMIN_PASSWORD=change-me-to-a-strong-admin-password +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 diff --git a/services/nextcloud/compose.yaml b/services/nextcloud/compose.yaml index 5e35ddc..86dd6d5 100644 --- a/services/nextcloud/compose.yaml +++ b/services/nextcloud/compose.yaml @@ -53,13 +53,16 @@ services: network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale container_name: app-${SERVICE} # Name for local container management environment: - - MYSQL_HOST=localhost + - 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=${SERVICE}.tail12345.ts.net + - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_TRUSTED_DOMAINS} + - OVERWRITEPROTOCOL=https - TZ=${TZ} volumes: - ./${SERVICE}-data/html:/var/www/html From b25f934c0210da1c7a3cfb0dbacd24fcbbfafe0b Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 16 Jul 2026 01:56:06 -0400 Subject: [PATCH 3/3] add wireguard exit node --- services/tailscale-exit-wireguard/.env | 17 +++ services/tailscale-exit-wireguard/README.md | 110 ++++++++++++++++++ .../tailscale-exit-wireguard/compose.yaml | 60 ++++++++++ 3 files changed, 187 insertions(+) create mode 100644 services/tailscale-exit-wireguard/.env create mode 100644 services/tailscale-exit-wireguard/README.md create mode 100644 services/tailscale-exit-wireguard/compose.yaml diff --git a/services/tailscale-exit-wireguard/.env b/services/tailscale-exit-wireguard/.env new file mode 100644 index 0000000..d308b16 --- /dev/null +++ b/services/tailscale-exit-wireguard/.env @@ -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 diff --git a/services/tailscale-exit-wireguard/README.md b/services/tailscale-exit-wireguard/README.md new file mode 100644 index 0000000..4e7e834 --- /dev/null +++ b/services/tailscale-exit-wireguard/README.md @@ -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= + +# 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 diff --git a/services/tailscale-exit-wireguard/compose.yaml b/services/tailscale-exit-wireguard/compose.yaml new file mode 100644 index 0000000..994c149 --- /dev/null +++ b/services/tailscale-exit-wireguard/compose.yaml @@ -0,0 +1,60 @@ +services: +# Make sure you have updated/checked the .env file with the correct variables. +# All the ${ xx } need to be defined there. + + # WireGuard (ProtonVPN) - Runs the VPN tunnel + wireguard: + image: linuxserver/wireguard:latest + container_name: app-wireguard + cap_add: + - net_admin + - sys_module + environment: + - PUID=${PUID:-1000} + - PGID=${PGID:-1000} + - TZ=${TZ} + volumes: + - ./wireguard/config:/config + devices: + - /dev/net/tun:/dev/net/tun + sysctls: + - net.ipv4.conf.all.src_valid_mark=1 + - net.ipv4.ip_forward=1 + healthcheck: + test: ["CMD", "wg", "show", "wg0"] + interval: 1m + timeout: 10s + retries: 3 + start_period: 30s + restart: always + + # Tailscale Exit Node - Routes traffic through WireGuard + tailscale: + image: tailscale/tailscale:latest + container_name: tailscale-${SERVICE} + network_mode: service:wireguard + depends_on: + wireguard: + condition: service_healthy + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_EXTRA_ARGS=--advertise-exit-node + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 + #- TS_ACCEPT_DNS=true + - TS_AUTH_ONCE=true + volumes: + - ./ts/state:/var/lib/tailscale + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] + interval: 1m + timeout: 10s + retries: 3 + start_period: 10s + restart: always