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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose
| 🖼️ **Immich** | A self-hosted Google Photos alternative with face recognition and mobile sync. | [Details](services/immich) |
| 📺 **Jellyfin** | An open-source media system that puts you in control of managing and streaming your media. | [Details](services/jellyfin) |
| 📖 **Kavita** | An open-source, self-hosted digital library for comics, manga, and ebooks. | [Details](services/kavita) |
| 🎮 **Minecraft** | A java based Minecraft server. | [Details](services/minecraft) |
| 🎮 **Minecraft Bedrock** | A Minecraft server based on Bedrock Game Console compatible (Nintendo/Xbox/Playstation). | [Details](services/minecraft-bedrock) |
| 📻 **Miniflux** | A minimalist and opinionated feed reader. | [Details](services/miniflux) |
| 🎶 **Navidrome** | Your Personal Streaming Service self-hosted. | [Details](services/navidrome) |
| 🎶 **Swing Music** | A fast, beautiful, self-hosted music streaming server for your local audio library. | [Details](services/swingmx) |
Expand Down Expand Up @@ -147,6 +149,7 @@ ScaleTail provides ready-to-run [Docker Compose](https://docs.docker.com/compose
| 📝 **Nanote** | A lightweight, self-hosted note-taking app with Markdown support. | [Details](services/nanote) |
| 🤖 **Open WebUI** | A self-hosted AI platform with a ChatGPT-style interface for local and cloud-based models. | [Details](services/open-webui) |
| 🔗 **Pingvin Share** | **PROJECT ARCHIVED** A self-hosted file sharing platform. | [Details](services/pingvin-share) |
| 💮 **Pulse** | A universal monitoring tool for ProxMox, Docker and much more. | [Details](services/pulse) |
| 🔄 **Resilio Sync** | A fast, reliable, and simple file sync and share solution. | [Details](services/resilio-sync) |
| 🗂️ **Stirling-PDF** | A web application for managing and editing PDF files. | [Details](services/stirlingpdf) |
| 📄 **BentoPDF** | A lightweight, self-hosted web app for viewing and managing PDF documents. | [Details](services/bentopdf) |
Expand Down
43 changes: 43 additions & 0 deletions services/minecraft-bedrock/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#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=minecraft-bedrock # Service name. Used as hostname in Tailscale and for container naming (app-${SERVICE}).
IMAGE_URL=itzg/minecraft-bedrock-server:latest # Docker image URL.

# Network Configuration
SERVICEPORT=19132 # Bedrock UDP port. Uncomment the "ports:" section in compose.yaml to enable LAN exposure.
DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable.

# Tailscale Configuration
# Auth key from https://tailscale.com/admin/authkeys
TS_AUTHKEY=

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

# Bedrock Server Configuration
# By setting EULA to TRUE you agree to the Mojang Minecraft End User License Agreement: https://www.minecraft.net/en-us/eula
EULA=FALSE

# Bedrock version: LATEST or a specific version like 1.21.50
VERSION=LATEST

# Name shown in the friends/server list
SERVER_NAME=A Minecraft Bedrock Server on Tailscale

# Default gamemode: survival, creative, adventure
GAMEMODE=survival

# Server difficulty: peaceful, easy, normal, hard
DIFFICULTY=normal

# World name (also the directory name on disk)
LEVEL_NAME=Bedrock level

# Maximum number of concurrent players
MAX_PLAYERS=10

# Online mode: true requires valid Xbox Live accounts, false allows offline clients
ONLINE_MODE=true
87 changes: 87 additions & 0 deletions services/minecraft-bedrock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Minecraft Bedrock Server with Tailscale Sidecar Configuration

This Docker Compose configuration sets up a [Minecraft Bedrock Edition](https://www.minecraft.net/en-us/about-minecraft) server with Tailscale as a sidecar container, enabling private multiplayer access over your Tailnet. No port forwarding or public IP required — only players on your Tailscale network can connect.

## Minecraft Bedrock

[Minecraft Bedrock Edition](https://www.minecraft.net/en-us/about-minecraft) is the cross-platform variant that runs on Windows 10/11, mobile, and consoles. This configuration uses the [itzg/minecraft-bedrock-server](https://hub.docker.com/r/itzg/minecraft-bedrock-server) Docker image. For the **Java Edition** server (TCP 25565, plugin/mod support), see [services/minecraft](../minecraft/).

## Networking Note

Bedrock uses **raw UDP on port 19132**. Tailscale Serve and Funnel only proxy HTTPS, so neither is used here — there is no `serve.json` block in the compose file. The Bedrock server listens directly on the Tailscale interface and players connect at the Tailnet IP or MagicDNS hostname of the node.

## Configuration Overview

The `tailscale-minecraft-bedrock` service runs the Tailscale client to join your Tailnet. The application service uses `network_mode: service:tailscale`, so the Bedrock server's UDP 19132 binds inside the Tailscale container's network namespace and is reachable from Tailnet peers only.

## Setup

1. Clone the repository and navigate to the service directory:

```bash
git clone https://github.com/tailscale-dev/ScaleTail.git
cd ScaleTail/services/minecraft-bedrock
```

2. Edit `.env`:
- Paste your Tailscale auth key into `TS_AUTHKEY=`.
- Set `EULA=TRUE` to accept the [Mojang EULA](https://www.minecraft.net/en-us/eula). The server will not start until you do.
- (Optional) Adjust `SERVER_NAME`, `GAMEMODE`, `DIFFICULTY`, `MAX_PLAYERS`, etc.

3. (OPTIONAL) Pre-create the data directories so Docker does not create them as `root`:

```bash
mkdir -p minecraft-bedrock-data ts/state
```

4. Start the stack:

```bash
docker compose up -d
```

5. Find your Tailnet name in the [Tailscale admin console](https://login.tailscale.com/admin/machines).

## Connecting

Bedrock clients (Windows / mobile / console) cannot enter a custom port through the in-game Quick Server interface on every platform. Two options:

- **Add Server (Bedrock 1.16+)**: Servers tab → Add Server. Enter the Tailnet IP or `minecraft-bedrock.<tailnet-name>.ts.net` and port `19132`.
- **Direct Connect**: enter the address and port at the connect prompt where supported.

Notes:

- All players must be on the same Tailnet (or have been shared access to the node).
- `ONLINE_MODE=false` allows clients without an Xbox Live account but reduces security — use only on trusted networks.

## Server Console

Attach to the running container for in-server commands (`/op`, `/stop`, `/save`, etc.):

```bash
docker attach app-minecraft-bedrock
```

Detach without stopping the server: `Ctrl-p Ctrl-q`.

## Environment Variables

| Variable | Default | Description |
| --- | --- | --- |
| `TS_AUTHKEY` | _(empty)_ | Tailscale auth key from the admin console |
| `EULA` | `FALSE` | Must be `TRUE` to accept Mojang's EULA before the server will start |
| `VERSION` | `LATEST` | Bedrock version: `LATEST` or a pinned version like `1.21.50` |
| `SERVER_NAME` | `A Minecraft Bedrock Server on Tailscale` | Name shown in the Bedrock server list |
| `GAMEMODE` | `survival` | `survival`, `creative`, or `adventure` |
| `DIFFICULTY` | `normal` | `peaceful`, `easy`, `normal`, or `hard` |
| `LEVEL_NAME` | `Bedrock level` | World name (also the directory name on disk) |
| `MAX_PLAYERS` | `10` | Maximum concurrent players |
| `ONLINE_MODE` | `true` | Require Xbox Live accounts (set false for offline play) |

## Useful Links

- [MUST READ - Bedrock DNS redirect for XBOX](https://github.com/Pugmatt/BedrockConnect)
- [itzg/minecraft-bedrock-server on Docker Hub](https://hub.docker.com/r/itzg/minecraft-bedrock-server)
- [itzg/minecraft-bedrock-server on GitHub](https://github.com/itzg/docker-minecraft-bedrock-server)
- [Mojang EULA](https://www.minecraft.net/en-us/eula)
- [Tailscale Docker guide](https://tailscale.com/blog/docker-tailscale-guide)
61 changes: 61 additions & 0 deletions services/minecraft-bedrock/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
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_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
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}/udp # Bedrock is UDP. Uncomment ONLY if LAN exposure is wanted.
# 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: # Variables are declared in .env file.
- EULA=${EULA} # Must be TRUE before first boot — see README.
- VERSION=${VERSION} # LATEST or pinned (e.g. 1.21.50)
- SERVER_NAME=${SERVER_NAME}
- GAMEMODE=${GAMEMODE} # survival, creative, adventure
- DIFFICULTY=${DIFFICULTY} # peaceful, easy, normal, hard
- LEVEL_NAME=${LEVEL_NAME}
- MAX_PLAYERS=${MAX_PLAYERS}
- ONLINE_MODE=${ONLINE_MODE} # true requires Xbox Live accounts; false allows offline clients
- TZ=${TZ}
volumes:
- ./${SERVICE}-data:/data # itzg/minecraft-bedrock-server stores world + config under /data
tty: true # Required for the Bedrock server console
stdin_open: true # Allows `docker attach app-${SERVICE}` for /op, /stop, etc.
depends_on:
tailscale:
condition: service_healthy
# Healthcheck is provided by the upstream itzg/minecraft-bedrock-server image,
# so no compose-level healthcheck is declared here.
restart: always
18 changes: 18 additions & 0 deletions services/pulse/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#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=pulse
IMAGE_URL=rcourtman/pulse:latest

# Network Configuration
SERVICEPORT=7655
DNS_SERVER=9.9.9.9

# Tailscale Configuration
# Auth key from https://tailscale.com/admin/authkeys
TS_AUTHKEY=

# Time Zone setting for containers
TZ=Europe/Amsterdam
49 changes: 49 additions & 0 deletions services/pulse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Pulse with Tailscale Sidecar Configuration

This Docker Compose configuration sets up [Pulse](https://hub.docker.com/r/rcourtman/pulse) with Tailscale as a sidecar so the dashboard is reachable only over your Tailnet at `https://pulse.<tailnet-name>.ts.net`.

## Pulse

Pulse is a modern, unified dashboard for monitoring your infrastructure across Proxmox, Docker, and Kubernetes. It consolidates metrics, alerts, and AI-powered insights from all your systems into a single interface, aimed at homelabs, sysadmins, and MSPs who want a "single pane of glass" without the complexity of an enterprise monitoring stack.

## Configuration Overview

The `tailscale-pulse` service runs the Tailscale client to join your Tailnet. The application service uses `network_mode: service:tailscale`, so Pulse listens on TCP `7655` inside the Tailscale container's network namespace and Tailscale Serve proxies HTTPS `443` → `127.0.0.1:7655`. `AllowFunnel` is `false`; the dashboard is **never** exposed to the public internet from this configuration.

## Setup

1. Clone the repository and navigate to the service directory:

```bash
git clone https://github.com/tailscale-dev/ScaleTail.git
cd ScaleTail/services/pulse
```

2. Edit `.env` and paste your Tailscale auth key into `TS_AUTHKEY=`.

3. (OPTIONAL) Pre-create the data directories so Docker does not create them as `root`:

```bash
mkdir -p pulse-data ts/state
```

4. Start the stack:

```bash
docker compose up -d
```

5. Open `https://pulse.<tailnet-name>.ts.net` from any Tailnet peer.

## Notes

- Pulse stores its state (Proxmox/Docker/Kubernetes credentials, alert rules, cached metrics) in `./pulse-data` mounted at `/data`. Treat this directory like a secrets vault — it contains tokens used to query your infrastructure.
- The original upstream `docker run` uses `-p 7655:7655` to bind the port to all host interfaces. In this configuration that direct port mapping is intentionally **not** used — access is via Tailnet only. Uncomment the `ports:` block in `compose.yaml` only if you also want LAN access from non-Tailnet devices.
- The upstream image's restart policy is `unless-stopped`; this configuration uses `restart: always` to match the rest of the ScaleTail catalog.

## Useful Links

- [rcourtman/pulse on Docker Hub](https://hub.docker.com/r/rcourtman/pulse)
- [rcourtman/pulse on GitHub](https://github.com/rcourtman/Pulse)
- [Tailscale Serve docs](https://tailscale.com/kb/1242/tailscale-serve)
- [Tailscale Docker guide](https://tailscale.com/blog/docker-tailscale-guide)
62 changes: 62 additions & 0 deletions services/pulse/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
configs:
ts-serve:
content: |
{"TCP":{"443":{"HTTPS":true}},
"Web":{"$${TS_CERT_DOMAIN}:443":
{"Handlers":{"/":
{"Proxy":"http://127.0.0.1:7655"}}}},
"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
- 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
- ./ts/state:/var/lib/tailscale # Tailscale state
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} # Uncomment ONLY if LAN exposure is wanted
# 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
timeout: 10s
retries: 3
start_period: 10s
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:
- TZ=${TZ}
volumes:
- ./${SERVICE}-data:/data # Pulse persistent data (configs, alerts, cached metrics)
depends_on:
tailscale:
condition: service_healthy
restart: always