From f652eea021c2be9350a67bfe4905841b4d03dbdd Mon Sep 17 00:00:00 2001 From: peskyadmin Date: Sun, 2 Aug 2026 21:46:17 -0400 Subject: [PATCH] feat: bring ts-bookstack up to current template spec - Add SECURITY.md (matches template) - Add tailscale/config/serve.headscale.json (HTTP-only variant) - Default serve.json to Tailscale generic with ${TS_CERT_DOMAIN} - Use linuxserver env var names (DB_USERNAME not DB_USER) - Use named Docker volumes for cross-platform portability - Both db and app use network_mode: service:bookstack-ts - Rewrite README with Tailscale vs Headscale structure - Rename db service to bookstack-db to avoid collisions with other ts-* repos --- README.md | 142 +++++++++----------------- SECURITY.md | 30 ++++++ docker-compose.yml | 57 +++++++++-- tailscale/config/serve.headscale.json | 16 +++ tailscale/config/serve.json | 36 ++++--- 5 files changed, 167 insertions(+), 114 deletions(-) create mode 100644 SECURITY.md create mode 100644 tailscale/config/serve.headscale.json diff --git a/README.md b/README.md index 159395b..0ce23dd 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,66 @@ -# {{Service}} with Tailscale Integration +# BookStack with Tailscale Integration -![{{Service}} with Tailscale](https://damconsulting.llc/images/logo_yellow.svg "{{Service}}") +![BookStack with Tailscale](https://raw.githubusercontent.com/BookStackApp/BookStack/master/logo.svg "BookStack") -This project sets up a {{Service}} instance with Tailscale VPN integration using Docker Compose. It creates a secure, private network connection for your {{Service}} instance using Tailscale. +This project sets up a BookStack instance with Tailscale VPN integration using Docker Compose. -## Prerequisites +## Quick Start (Tailscale) -- Docker and Docker Compose installed on your system -- A Tailscale account and auth key (get one from https://login.tailscale.com/admin/authkeys) -- Basic understanding of Docker and networking concepts - -## Project Structure -``` -ts-{{service}}/ -├── docker-compose.yml -├── tailscale/ -│ ├── tailscale-data/ # Persistent Tailscale state -│ └── config/ # Tailscale configuration files -└── {{service}}/ - └── config/ # {{Service}} configuration files -``` - -## Setup Instructions - -1. **Clone the Repository** +1. Copy the example environment file and fill in your values: ```bash - git clone https://gitea.damconsulting.llc/DAM/ts-{{service}} - cd ts-{{service}} + cp .env.example .env ``` -2. Create Required Directories - ```bash - mkdir -p tailscale/tailscale-data - ``` -3. Configure Tailscale - - Make sure `TS_AUTHKEY` and `TS_LOGIN_SERVER` are set in your environment (or a local .env file) before running docker compose. - - Optionally, update the file in `tailscale/config/serve.json` if you need specific Tailscale serve configurations - - CAUTION: Changing `"${TS_CERT_DOMAIN}:443": false` to `true` will expose the service to the internet +2. Edit `.env` and set: + - `TS_AUTHKEY` — your Tailscale auth key +3. Generate a BookStack `APP_KEY` (32-char base64) — see https://bookstack.com/installation/generate-appkey +4. Start the stack: + ```bash + docker compose up -d + ``` +5. Access BookStack at `http://bookstack..ts.net` -4. Configure {{Service}} - - See the [documentation]({{service_docs}}) for configuration options +## Headscale -5. Start the Services - ```bash - docker compose up -d - ``` +If you're using Headscale instead of Tailscale: -6. Wait for Certificate to propagate [~2m] +1. Copy the example environment file: + ```bash + cp .env.example .env + ``` +2. Edit `.env` and set: + - `TS_AUTHKEY` — your Headscale auth key + - `TS_LOGIN_SERVER` — your Headscale server URL +3. Switch to the Headscale serve config: + ```bash + cp tailscale/config/serve.headscale.json tailscale/config/serve.json + ``` +4. Edit `serve.json` and replace `bookstack.example.com` with your actual domain +5. Start the stack: + ```bash + docker compose up -d + ``` +6. Access BookStack at `http://bookstack.yourdomain.com` -7. Login - - After starting the services your service should be available via tailnet at https://{{service}}.{{YOUR_TAILNET_DOMAIN}}.ts.net ie https://{{service}}.tail12345.ts.net/ +## Configuration -## Services +See `.env.example` for all available options. -### {{service}}-ts (Tailscale) +### Switching Serve Configs -- Runs Tailscale VPN client -- Image: tailscale/tailscale:latest -- Container name: {{service}}-ts -- Hostname: {{service}} -- Requires NET_ADMIN and SYS_MODULE capabilities -- Persists state in ./tailscale/tailscale-data -- Uses configuration from ./tailscale/config +| Environment | File to use | Notes | +|-------------------|--------------------------------------|-------| +| Tailscale (default) | `tailscale/config/serve.json` | Supports HTTP + HTTPS with certs | +| Headscale | `tailscale/config/serve.headscale.json` | HTTP only | -### {{service}} +After changing the serve config, restart the sidecar: +```bash +docker compose restart bookstack-ts +``` -- Depends on {{service}}-ts service +## Optional: Direct Host Access -## Usage - -- After starting the services your service should be available via tailnet at `https://{{service}}.{{YOUR_TAILNET_DOMAIN}}.ts.net` ie `https://{{service}}.tail12345.ts.net/` -- To manually get the Tailscale IP/hostname of your container: - ```bash - docker logs {{service}}-ts - ``` - Look for the Tailscale IP address in the logs. - -## Optional Features - -- Uncomment and adjust the ports mapping if you need direct access (without Tailscale): - ```yaml - ports: - - 3000:3000 - ``` -- Stopping the Services - ```bash - docker compose down - ``` - -## Troubleshooting -- Check container logs: - ```bash - docker logs {{service}}-ts - docker logs {{service}} - ``` -- Ensure your Tailscale auth key is valid and not expired -- Verify the configuration files have proper permissions -- Make sure required directories exist before starting - -## Notes -- The {{Service}} service uses the Tailscale service's network stack via `network_mode: service:{{service}}-ts` -- Direct port mapping is disabled by default as Tailscale handles the networking -- Services restart automatically unless explicitly stopped -- For more information: - - Tailscale documentation: https://tailscale.com/kb/ - - {{Service}} [documentation]({{service_docs}}) - - {{Service}} [repository]({{service_repo}}) - - {{Service}} [linuxserve.io]({{service_lcsr}}) \ No newline at end of file +Uncomment the ports section in `docker-compose.yml` if you need direct access without Tailscale: +```yaml +ports: + - 80:80 +``` diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..def471b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +# Security Notes + +## Sensitive Files + +- `.env` — Contains your Tailscale/Headscale auth key and service configuration. **Never commit this file.** +- `tailscale/tailscale-data/` — Contains Tailscale node state and keys. **Never commit this directory.** + +## Capabilities + +This compose file adds the following capabilities to the Tailscale sidecar: + +- `net_admin` — Required for Tailscale to manage network interfaces and routes. + +These capabilities are necessary for Tailscale to function but increase the attack surface if the container is compromised. + +## Default Passwords & Secrets + +The `docker-compose.yml` and `.env` files contain placeholder values (`***`) for sensitive items such as: + +- Database credentials +- Service JWT secret + +**Change these values** before deploying anywhere security matters. Never use the default placeholders in production or shared environments. + +## Recommendations + +- Use a dedicated, limited-scope auth key for each service. +- Regularly rotate auth keys. +- Review Headscale/Tailscale ACLs to ensure services only have the access they need. +- Keep the Tailscale Docker image reasonably up to date. diff --git a/docker-compose.yml b/docker-compose.yml index 72aa767..30f45a4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,60 @@ services: - {{service}}-ts: + bookstack-ts: image: tailscale/tailscale:latest - hostname: {{service}} - container_name: {{service}}-ts + hostname: bookstack + container_name: bookstack-ts environment: - - TS_AUTHKEY={{YOUR_TAILSCALE_AUTHKEY}} + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_LOGIN_SERVER=${TS_LOGIN_SERVER} - TS_STATE_DIR=/var/lib/tailscale - TS_SERVE_CONFIG=/config/serve.json + - TS_EXTRA_ARGS=--login-server=${TS_LOGIN_SERVER} volumes: - ./tailscale/tailscale-data:/var/lib/tailscale - ./tailscale/config:/config - /dev/net/tun:/dev/net/tun cap_add: - net_admin - - sys_module restart: unless-stopped - {{service-compose}} - network_mode: service:{{service}}-ts - depends_on: - - {{service}}-ts \ No newline at end of file + + bookstack-db: + image: lscr.io/linuxserver/mariadb:latest + environment: + - PUID=1000 + - PGID=1000 + - TZ=UTC + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + - MYSQL_DATABASE=${DB_DATABASE} + - MYSQL_USER=${DB_USERNAME} + - MYSQL_PASSWORD=${DB_PASSWORD} + volumes: + - bookstack-db-data:/config + depends_on: + - bookstack-ts + network_mode: service:bookstack-ts + restart: unless-stopped + + bookstack: + image: lscr.io/linuxserver/bookstack:latest + environment: + - PUID=1000 + - PGID=1000 + - TZ=UTC + - APP_URL=${APP_URL} + - APP_KEY=${APP_KEY} + - DB_HOST=127.0.0.1 + - DB_PORT=3306 + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} + - DB_DATABASE=${DB_DATABASE} + volumes: + - bookstack-data:/config + depends_on: + - bookstack-ts + - bookstack-db + network_mode: service:bookstack-ts + restart: unless-stopped + +volumes: + bookstack-db-data: + bookstack-data: diff --git a/tailscale/config/serve.headscale.json b/tailscale/config/serve.headscale.json new file mode 100644 index 0000000..4e1b3e8 --- /dev/null +++ b/tailscale/config/serve.headscale.json @@ -0,0 +1,16 @@ +{ + "TCP": { + "80": { + "HTTP": true + } + }, + "Web": { + "bookstack.example.com:80": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:80" + } + } + } + } +} diff --git a/tailscale/config/serve.json b/tailscale/config/serve.json index 121ffb8..f4f4ee4 100644 --- a/tailscale/config/serve.json +++ b/tailscale/config/serve.json @@ -1,19 +1,29 @@ { - "TCP": { - "443": { - "HTTPS": true - } + "TCP": { + "80": { + "HTTP": true }, - "Web": { - "${TS_CERT_DOMAIN}:443": { - "Handlers": { - "/": { - "Proxy": "http://127.0.0.1:3000" - } + "443": { + "HTTPS": true + } + }, + "Web": { + "${TS_CERT_DOMAIN}:80": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:80" } } }, - "AllowFunnel": { - "${TS_CERT_DOMAIN}:443": false + "${TS_CERT_DOMAIN}:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:80" + } + } } - } \ No newline at end of file + }, + "AllowFunnel": { + "${TS_CERT_DOMAIN}:443": false + } +}