diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dd290b0 --- /dev/null +++ b/.env.example @@ -0,0 +1,38 @@ +# ========================================== +# REQUIRED: Tailscale / Headscale (all ts-* services) +# ========================================== + +# Your Tailscale or Headscale auth key +TS_AUTHKEY=*** + +# Tailscale control server (default) +# For Headscale: update to your Headscale server URL +TS_LOGIN_SERVER=https://controlplane.tailscale.com + +# ========================================== +# REFERENCE: Database credentials (only if your service uses an external DB) +# Remove this section if your service uses SQLite or has no database +# ========================================== + +POSTGRES_USER={{service}} +POSTGRES_PASSWORD=*** +POSTGRES_DB={{service}} + +# ========================================== +# CUSTOMIZE: App-specific variables (replace with what your service needs) +# ========================================== + +# Public URL users will access the service at +# Tailscale example: https://{{service}}.your-tailnet.ts.net +# Headscale example: http://{{service}}.yourdomain.com +{{SERVICE}}_SERVICE_PUBLICURL=http://{{service}}.example.com + +# Frontend URL (usually the same as PUBLICURL) +{{SERVICE}}_SERVICE_FRONTENDURL=http://{{service}}.example.com + +# Service JWT secret (change this!) +{{SERVICE}}_SERVICE_JWTSECRET=*** + +# Add more app-specific vars here as needed, for example: +# {{SERVICE}}_TIMEZONE=UTC +# {{SERVICE}}_ADMIN_EMAIL=admin@example.com diff --git a/.gitignore b/.gitignore index 10c6b93..b7c0aa1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,18 @@ -# Secrets and environment files +# Real environment files (never commit) .env -.env.* +.env.local +.env.*.local + +# Secrets and keys *.key tskey-* authkey* -# Tailscale data (never commit state) +# Tailscale state tailscale/tailscale-data/ + +# OS / editor +.DS_Store +*.swp +*.swo +*~ diff --git a/README.md b/README.md index 710b826..6ac1c51 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,70 @@ # {{Service}} with Tailscale Integration -![{{Service}} with Tailscale](https://damconsulting.llc/images/logo_yellow.svg "{{Service}}") +![{{Service}} with Tailscale](https://raw.githubusercontent.com/go-vikunja/vikunja/main/frontend/src/assets/logo.svg "{{Service}}") -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 {{Service}} 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. Start the stack: + ```bash + docker compose up -d + ``` +4. Customize the app config per official documentation +5. Access {{Service}} at `http://{{service}}..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 `{{service}}.example.com` with your actual domain +5. Start the stack: + ```bash + docker compose up -d + ``` +6. Customs the app config per official documentation +7. Access {{Service}} at `http://{{service}}.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 {{service}}-ts +``` -- Depends on {{service}}-ts service +## Optional: Direct Host Access -## Usage +Uncomment the ports section in `docker-compose.yml` if you need direct access without Tailscale: +```yaml +ports: + - {{port}}:{{port}} +``` -- 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 +## Links +put links to offical site, and git repo 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 c1553e6..84f1a84 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,6 @@ +# ========================================== +# REQUIRED: Tailscale sidecar (all ts-* services) +# ========================================== services: {{service}}-ts: image: tailscale/tailscale:latest @@ -17,6 +20,10 @@ services: - net_admin restart: unless-stopped + # ========================================== + # REFERENCE: Example database (REMOVE this section if your service + # uses SQLite or has no database requirement) + # ========================================== db: image: postgres:15 environment: @@ -30,22 +37,29 @@ services: network_mode: service:{{service}}-ts restart: unless-stopped + # ========================================== + # REQUIRED: Your service container + # Customize the image, env vars, and volumes for your specific app + # ========================================== {{service}}: image: {{service}}/{{service}}:latest environment: + # Database (remove these lines if your service has no database) {{SERVICE}}_DATABASE_TYPE: postgres {{SERVICE}}_DATABASE_HOST: 127.0.0.1 {{SERVICE}}_DATABASE_USER: ${POSTGRES_USER} {{SERVICE}}_DATABASE_PASSWORD: ${POSTGRES_PASSWORD} {{SERVICE}}_DATABASE_DATABASE: ${POSTGRES_DB} + + # Service configuration (customize these for your app) {{SERVICE}}_SERVICE_JWTSECRET: ${{{SERVICE}}_SERVICE_JWTSECRET} {{SERVICE}}_SERVICE_PUBLICURL: ${{{SERVICE}}_SERVICE_PUBLICURL} {{SERVICE}}_SERVICE_FRONTENDURL: ${{{SERVICE}}_SERVICE_FRONTENDURL} + # Add or remove more app-specific env vars here as needed volumes: - - ./files:/app/{{service}}/files + - ./{{service}}/files:/app/files depends_on: - {{service}}-ts - - db network_mode: service:{{service}}-ts restart: unless-stopped diff --git a/tailscale/config/serve.headscale.json b/tailscale/config/serve.headscale.json new file mode 100644 index 0000000..89d6087 --- /dev/null +++ b/tailscale/config/serve.headscale.json @@ -0,0 +1,16 @@ +{ + "TCP": { + "80": { + "HTTP": true + } + }, + "Web": { + "{{service}}.yourdomain.com:80": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:{{port}}" + } + } + } + } +} diff --git a/tailscale/config/serve.json b/tailscale/config/serve.json index 121ffb8..5be8901 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:{{port}}" } } }, - "AllowFunnel": { - "${TS_CERT_DOMAIN}:443": false + "${TS_CERT_DOMAIN}:443": { + "Handlers": { + "/": { + "Proxy": "http://127.0.0.1:{{port}}" + } + } } - } \ No newline at end of file + }, + "AllowFunnel": { + "${TS_CERT_DOMAIN}:443": false + } +}