mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
1 line
76 KiB
JSON
1 line
76 KiB
JSON
{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to ionscale","text":"<p>ionscale is an open-source alternative to Tailscale's control server, designed to provide a self-hosted coordination service for your Tailscale networks.</p> <p>Beta status</p> <p>ionscale is currently in beta. While it's stable for production use for small tailnets, we're actively developing new features and improvements.</p> <p>Documentation status</p> <p>This documentation is a work in progress. Some sections may be incomplete or missing. We're continuously improving the documentation to provide comprehensive coverage of all features.</p>"},{"location":"#what-is-ionscale","title":"What is ionscale?","text":"<p>Tailscale allows your devices to communicate securely across networks using WireGuard\u00ae. While Tailscale's client software is open source, their centralized coordination server (which manages public keys and network configurations) is proprietary.</p> <p>ionscale aims to implement a lightweight, open-source control server that:</p> <ul> <li>Acts as a drop-in replacement for Tailscale's coordination server</li> <li>Can be self-hosted on your infrastructure</li> <li>Gives you full control over your network configuration</li> <li>Works with the standard Tailscale clients</li> <li>Supports a wide range of Tailscale features</li> </ul>"},{"location":"#getting-started","title":"Getting started","text":"<ul> <li>Installation guide - Install ionscale using Docker or directly on Linux</li> <li>CLI configuration - Set up the ionscale CLI and authenticate</li> <li>Creating a tailnet - Create and manage your first tailnet</li> <li>OIDC authentication - Configure user authentication via OIDC</li> <li>DNS providers - Set up DNS integration for HTTPS certificates</li> </ul> <p> Disclaimer: This is not an official Tailscale or Tailscale Inc. project. Tailscale and WireGuard are trademarks of their respective owners. </p>"},{"location":"configuration/","title":"Configuration Guide","text":"<p>ionscale uses a flexible YAML-based configuration system that supports environment variable substitution and sensible defaults. This guide explains how to configure your ionscale instance.</p>"},{"location":"configuration/#configuration-file-format","title":"Configuration File Format","text":"<p>ionscale uses YAML for its configuration files. Here's a basic example:</p> <pre><code># Server network configuration\nlisten_addr: \":8080\"\npublic_addr: \"ionscale.example.com:443\"\nstun_listen_addr: \":3478\"\nstun_public_addr: \"ionscale.example.com:3478\"\n\n# TLS configuration\ntls:\n disable: false\n force_https: true\n cert_file: /etc/ionscale/cert.pem\n key_file: /etc/ionscale/key.pem\n\n# Database configuration\ndatabase:\n type: postgres\n url: postgres://user:password@localhost:5432/ionscale\n</code></pre>"},{"location":"configuration/#loading-configuration","title":"Loading Configuration","text":"<p>When starting ionscale, you can specify a configuration file using the <code>--config</code> or <code>-c</code> flag:</p> <pre><code>ionscale server --config /etc/ionscale/config.yaml\n</code></pre> <p>If no configuration file is provided, ionscale will use its default values.</p>"},{"location":"configuration/#environment-variable-support","title":"Environment Variable Support","text":"<p>ionscale supports two ways to use environment variables in configuration:</p>"},{"location":"configuration/#1-direct-configuration-via-environment-variables","title":"1. Direct Configuration via Environment Variables","text":"<p>You can provide the entire configuration as a base64-encoded string using the <code>IONSCALE_CONFIG_BASE64</code> environment variable. This is useful for containerized deployments where you want to inject configuration without mounting files.</p> <pre><code># Create base64-encoded config\nCONFIG_B64=$(cat config.yaml | base64 -w0)\n\n# Run ionscale with environment config\nIONSCALE_CONFIG_BASE64=$CONFIG_B64 ionscale server\n</code></pre>"},{"location":"configuration/#2-variable-substitution-in-yaml-files","title":"2. Variable Substitution in YAML Files","text":"<p>You can reference environment variables directly in your YAML configuration files using:</p> <ul> <li><code>${VAR}</code> syntax for required variables</li> <li><code>${VAR:default}</code> syntax for variables with default values</li> </ul> <p>For example:</p> <pre><code>database:\n type: ${DB_TYPE:sqlite}\n url: ${DB_URL}\n max_open_conns: ${DB_MAX_OPEN_CONNS:10}\n</code></pre> <p>In this example: - <code>DB_TYPE</code> has a default value of \"sqlite\" if the environment variable is not set - <code>DB_URL</code> is required and must be set in the environment - <code>DB_MAX_OPEN_CONNS</code> defaults to 10 if not set</p> <p>If a required variable is missing, the configuration loading will fail with an error.</p>"},{"location":"configuration/#default-configuration","title":"Default Configuration","text":"<p>If no configuration file is provided, ionscale uses these default values:</p> <pre><code>listen_addr: \":8080\"\nmetrics_listen_addr: \":9091\"\nstun_listen_addr: \":3478\"\n\ndatabase:\n type: sqlite\n url: ./ionscale.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)&_pragma=foreign_keys(ON)\n max_idle_conns: 2\n\npoll_net:\n keep_alive_interval: 1m\n\ndns:\n magic_dns_suffix: ionscale.net\n\nderp:\n server:\n disabled: false\n region_id: 1000\n region_code: ionscale\n region_name: ionscale Embedded DERP\n\nlogging:\n level: info\n</code></pre>"},{"location":"configuration/#configuration-sections","title":"Configuration Sections","text":""},{"location":"configuration/#server-network-configuration","title":"Server Network Configuration","text":"<p>Controls the network interfaces and addresses:</p> <pre><code># The HTTP(S) listen address for the control plane\nlisten_addr: \":8080\"\n\n# The metrics listen address (for Prometheus)\nmetrics_listen_addr: \":9091\"\n\n# The STUN listen address when using the embedded DERP\nstun_listen_addr: \":3478\"\n\n# The DNS name of the server HTTP(S) endpoint as accessible by clients\npublic_addr: \"ionscale.example.com:443\"\n\n# The DNS name of the STUN endpoint as accessible by clients\nstun_public_addr: \"ionscale.example.com:3478\"\n</code></pre>"},{"location":"configuration/#tls-configuration","title":"TLS Configuration","text":"<p>Controls HTTPS and certificate usage:</p> <pre><code>tls:\n # Disable TLS (not recommended for production)\n disable: false\n\n # Force HTTPS redirect\n force_https: true\n\n # Path to certificate files (when not using ACME)\n cert_file: /etc/ionscale/cert.pem\n key_file: /etc/ionscale/key.pem\n\n # Let's Encrypt ACME configuration\n acme: true\n acme_email: admin@example.com\n acme_ca: https://acme-v02.api.letsencrypt.org/directory\n</code></pre>"},{"location":"configuration/#database-configuration","title":"Database Configuration","text":"<p>Controls the database storage:</p> <pre><code>database:\n # Database type: sqlite or postgres\n type: postgres\n\n # Database connection URL\n url: postgres://user:password@localhost:5432/ionscale\n\n # Connection pool settings\n max_open_conns: 10\n max_idle_conns: 5\n conn_max_life_time: 5m\n conn_max_idle_time: 5m\n</code></pre>"},{"location":"configuration/#oidc-configuration","title":"OIDC Configuration","text":"<p>Controls OpenID Connect authentication providers and admin access:</p> <pre><code>auth:\n # OIDC provider configuration\n provider:\n issuer: https://auth.example.com\n client_id: client_id\n client_secret: client_secret\n additional_scopes: [\"profile\", \"email\"]\n\n # System administrators configuration\n system_admins:\n emails: [\"admin@example.com\"]\n subs: [\"subject123\"]\n filters: [\"domain == example.com\"]\n</code></pre> <p>For more details about configuring OIDC authentication, see OIDC Configuration.</p>"},{"location":"configuration/#dns-configuration","title":"DNS Configuration","text":"<p>Controls DNS settings:</p> <pre><code>dns:\n # Suffix for MagicDNS\n magic_dns_suffix: ionscale.net\n\n # DNS provider for dynamic updates\n provider:\n name: cloudflare\n zone: example.com\n config:\n auth_token: ${CLOUDFLARE_TOKEN}\n</code></pre> <p>For more details about configuring DNS providers, see DNS Providers.</p>"},{"location":"configuration/#derp-configuration","title":"DERP Configuration","text":"<p>Controls relay server configuration:</p> <pre><code>derp:\n # Embedded DERP server configuration\n server:\n disabled: false\n region_id: 1000\n region_code: ionscale\n region_name: ionscale Embedded DERP\n\n # External DERP maps to load\n sources:\n - https://controlplane.tailscale.com/derpmap/default\n - file:///etc/ionscale/custom-derp.json\n</code></pre> <p>For more details about configuring DERP servers, see DERP Configuration.</p>"},{"location":"configuration/#logging-configuration","title":"Logging Configuration","text":"<p>Controls log output:</p> <pre><code>logging:\n # Log level: debug, info, warn, error\n level: info\n\n # Log format: text, json\n format: text\n\n # Optional file output (in addition to stdout)\n file: /var/log/ionscale.log\n</code></pre>"},{"location":"configuration/#keys-and-security","title":"Keys and Security","text":"<p>You can configure private keys for the system:</p> <pre><code>keys:\n # System administrator key for CLI authentication\n system_admin_key: your-private-key\n\n # Control plane keys (optional, auto-generated when not provided)\n control_key: your-control-key\n legacy_control_key: your-legacy-control-key\n</code></pre> <p>The <code>control_key</code> and <code>legacy_control_key</code> are optional and will be automatically generated if not provided. Once generated, they are stored in the database and reused across restarts.</p> <p>Warning</p> <p>Never commit sensitive keys in your configuration files to version control. Use environment variables for sensitive values.</p>"},{"location":"configuration/#configuration-file-locations","title":"Configuration File Locations","text":"<p>Common locations for ionscale configuration files:</p> <ul> <li><code>/etc/ionscale/config.yaml</code> - System-wide configuration</li> <li><code>$HOME/.config/ionscale/config.yaml</code> - User-specific configuration</li> <li><code>./config.yaml</code> - Local directory configuration</li> </ul>"},{"location":"configuration/#complete-configuration-example","title":"Complete Configuration Example","text":"<p>Below is a complete configuration file example with comments:</p> <pre><code># Network configuration\nlisten_addr: \":8080\" # HTTP/HTTPS control plane address\nstun_listen_addr: \":3478\" # STUN server listen address\nmetrics_listen_addr: \":9091\" # Prometheus metrics address\npublic_addr: \"ionscale.example.com:443\" # Public HTTPS endpoint for clients\nstun_public_addr: \"ionscale.example.com:3478\" # Public STUN endpoint for clients\n\n# TLS configuration\ntls:\n disable: false # Set to true if behind a TLS-terminating proxy\n force_https: true # Redirect HTTP to HTTPS\n # Provide your own certificates\n cert_file: \"/etc/ionscale/cert.pem\" \n key_file: \"/etc/ionscale/key.pem\"\n # Or use Let's Encrypt\n acme: false # Enable ACME/Let's Encrypt\n acme_email: \"admin@example.com\" # Contact email for Let's Encrypt\n acme_ca: \"https://acme-v02.api.letsencrypt.org/directory\"\n acme_path: \"./data\" # Storage path for ACME certificates\n\n# Database configuration\ndatabase:\n # SQLite configuration\n type: \"sqlite\"\n url: \"/var/lib/ionscale/ionscale.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)&_pragma=foreign_keys(ON)\"\n\n # Or PostgreSQL configuration\n # type: \"postgres\"\n # url: \"postgres://user:password@localhost:5432/ionscale?sslmode=disable\"\n\n # Connection pool settings\n max_open_conns: 10\n max_idle_conns: 5\n conn_max_life_time: \"5m\"\n conn_max_idle_time: \"5m\"\n\n# DERP (relay) configuration\nderp:\n # Embedded DERP server\n server:\n disabled: false # Set to true to disable embedded DERP\n region_id: 1000 # Region ID (1000+ reserved for ionscale)\n region_code: \"ionscale\" # Short code for the region\n region_name: \"ionscale Embedded DERP\" # Human-readable name\n\n # External DERP sources (optional)\n sources:\n - https://controlplane.tailscale.com/derpmap/default # Tailscale's DERP map\n # - file:///etc/ionscale/custom-derp.json # Custom DERP map\n # - git::https://github.com/example/derp//map.json # DERP map from git\n\n# Security keys\nkeys:\n # System admin key for CLI authentication (required for admin CLI usage)\n system_admin_key: \"${IONSCALE_SYSTEM_ADMIN_KEY}\" # Use environment variable\n\n # Control keys (optional, auto-generated if not provided)\n # control_key: \"privkey:xxxxxx\"\n # legacy_control_key: \"privkey:xxxxxx\"\n\n# Network polling configuration\npoll_net:\n # How often to send keep-alive messages\n keep_alive_interval: \"60s\"\n\n# OIDC authentication configuration\nauth:\n # OIDC provider settings\n provider:\n issuer: \"https://auth.example.com\" # OIDC issuer URL\n client_id: \"your-client-id\" # OAuth client ID\n client_secret: \"${OIDC_CLIENT_SECRET}\" # OAuth client secret from env var\n additional_scopes: [\"profile\", \"email\"] # Extra scopes to request\n\n # System administrator policy\n system_admins:\n # Users identified by email\n emails: [\"admin@example.com\"]\n # Users identified by subject ID\n subs: [\"subject-id-12345\"]\n # Users matching expression filters\n filters: [\"domain == example.com\"]\n\n# DNS configuration\ndns:\n # Suffix for MagicDNS hostnames\n magic_dns_suffix: \"ionscale.net\"\n\n # DNS provider for automatic DNS management (optional)\n provider:\n name: \"cloudflare\" # Provider name (cloudflare, route53, etc.)\n zone: \"example.com\" # DNS zone to manage\n config: # Provider-specific configuration\n auth_token: \"${DNS_API_TOKEN}\"\n\n# Logging configuration\nlogging:\n level: \"info\" # debug, info, warn, error\n format: \"text\" # text or json\n file: \"/var/log/ionscale.log\" # Optional log file path\n</code></pre> <p>Environment variables</p> <p>In this example, we use environment variables for sensitive values: <pre><code>${IONSCALE_SYSTEM_ADMIN_KEY} - System admin key for CLI authentication\n${OIDC_CLIENT_SECRET} - OIDC client secret\n${DNS_API_TOKEN} - DNS provider API token\n</code></pre></p> <p>These must be set in your environment before starting ionscale.</p>"},{"location":"configuration/auth-oidc/","title":"Configuring authentication with OIDC","text":"<p>While ionscale can operate without an OIDC (OpenID Connect) provider using only static keys, configuring an OIDC provider is highly recommended for enhanced security, user management, and a smoother administrative experience.</p>"},{"location":"configuration/auth-oidc/#why-configure-an-oidc-provider","title":"Why configure an OIDC provider?","text":"<p>Without an OIDC provider, ionscale operates in a key-only mode:</p> <ul> <li>System administrators can only use the system admin key for administrative tasks</li> <li>Tailscale devices can only connect using tags and pre-authentication keys</li> <li>No user accounts or user-specific permissions are available</li> </ul> <p>With an OIDC provider configured:</p> <ul> <li>Users can authenticate using their existing identity provider credentials</li> <li>Administrators can assign specific permissions to users</li> <li>System administration can be delegated to specific users</li> <li>Fine-grained access control based on user identity becomes possible</li> <li>More seamless user experience with browser-based authentication</li> </ul>"},{"location":"configuration/auth-oidc/#supported-oidc-providers","title":"Supported OIDC providers","text":"<p>ionscale supports any standard OIDC provider, including:</p> <ul> <li>Google Workspace</li> <li>Auth0</li> <li>Okta</li> <li>Azure AD / Microsoft Entra ID</li> <li>Keycloak</li> <li>GitLab</li> <li>GitHub (OAuth 2.0 with OIDC extensions)</li> <li>And many others</li> </ul>"},{"location":"configuration/auth-oidc/#basic-oidc-configuration","title":"Basic OIDC configuration","text":"<p>To configure an OIDC provider, update your ionscale configuration file (<code>config.yaml</code>) with the following settings:</p> <pre><code>auth:\n provider:\n # OIDC issuer URL where ionscale can find the OpenID Provider Configuration Document\n issuer: \"https://your-oidc-provider.com\"\n # OIDC client ID and secret\n client_id: \"your-client-id\"\n client_secret: \"your-client-secret\"\n # Optional: additional OIDC scopes used in the OIDC flow\n additional_scopes: \"groups\"\n</code></pre>"},{"location":"configuration/auth-oidc/#required-configuration-fields","title":"Required configuration fields","text":"<ul> <li><code>issuer</code>: The URL to your OIDC provider's issuer. This URL is used to discover your provider's endpoints.</li> <li><code>client_id</code>: The client ID from your OIDC provider application registration.</li> <li><code>client_secret</code>: The client secret from your OIDC provider application registration.</li> </ul>"},{"location":"configuration/auth-oidc/#optional-configuration","title":"Optional configuration","text":"<ul> <li><code>additional_scopes</code>: A space-separated list of additional OAuth scopes to request during authentication. By default, ionscale requests the <code>openid</code>, <code>email</code>, and <code>profile</code> scopes.</li> </ul>"},{"location":"configuration/auth-oidc/#configuring-your-oidc-provider","title":"Configuring your OIDC provider","text":"<p>When registering ionscale with your OIDC provider, you'll need to configure the following:</p> <p>Redirect URI: Set to <code>https://your-ionscale-domain.com/auth/callback</code></p>"},{"location":"configuration/auth-oidc/#system-administrator-access","title":"System administrator access","text":"<p>With OIDC configured, you'll want to specify which users have system administrator privileges. This is done in the <code>auth.system_admins</code> section of your configuration:</p> <pre><code>auth:\n # Configuration from previous section...\n\n system_admins:\n # By email address\n emails:\n - \"admin@example.com\"\n - \"secadmin@example.com\"\n\n # By subject identifier (sub claim from OIDC)\n subs:\n - \"user|123456\"\n\n # By attribute expression (using BEXPR syntax)\n filters:\n - \"token.groups contains \\\"admin\\\"\"\n - \"domain == \\\"admin.example.com\\\"\"\n</code></pre> <p>You can use one or more of these methods to designate system administrators:</p> <ol> <li>By Email: List specific email addresses that should have admin privileges.</li> <li>By Subject ID: List specific user IDs (the <code>sub</code> claim from your OIDC provider).</li> <li>By Expression: Use BEXPR filters to determine admin status based on token claims.</li> </ol>"},{"location":"configuration/auth-oidc/#oidc-authentication-flow","title":"OIDC authentication flow","text":"<p>When a user attempts to authenticate with ionscale:</p> <ol> <li>The user is redirected to the OIDC provider's login page.</li> <li>After successful authentication, the user is redirected back to ionscale.</li> <li>ionscale verifies the authentication and checks if:</li> <li>The user is a system administrator (based on the <code>system_admins</code> configuration).</li> <li>The user has access to any tailnets (based on IAM policies configured for individual tailnets).</li> </ol>"},{"location":"configuration/auth-oidc/#provider-specific-setup-instructions","title":"Provider-specific setup instructions","text":""},{"location":"configuration/auth-oidc/#google","title":"Google","text":"<ol> <li>Go to the Google Cloud Console.</li> <li>Create a new project or select an existing one.</li> <li>Navigate to \"APIs & Services\" > \"Credentials\".</li> <li>Click \"Create Credentials\" > \"OAuth client ID\".</li> <li>Select \"Web application\" as the application type.</li> <li>Add <code>https://your-ionscale-domain.com/auth/callback</code> as an authorized redirect URI.</li> <li>Copy the client ID and client secret.</li> </ol> <p>Configure ionscale: <pre><code>auth:\n provider:\n issuer: \"https://accounts.google.com\"\n client_id: \"your-client-id.apps.googleusercontent.com\"\n client_secret: \"your-client-secret\"\n</code></pre></p>"},{"location":"configuration/auth-oidc/#auth0","title":"Auth0","text":"<ol> <li>Go to the Auth0 Dashboard.</li> <li>Create a new application or select an existing one of type \"Regular Web Application\".</li> <li>Under \"Settings\", configure:</li> <li>Allowed Callback URLs: <code>https://your-ionscale-domain.com/auth/callback</code></li> <li>Copy the Domain, Client ID, and Client Secret.</li> </ol> <p>Configure ionscale: <pre><code>auth:\n provider:\n issuer: \"https://your-tenant.auth0.com/\"\n client_id: \"your-client-id\"\n client_secret: \"your-client-secret\"\n</code></pre></p>"},{"location":"configuration/auth-oidc/#microsoft-azure-ad-entra-id","title":"Microsoft Azure AD / Entra ID","text":"<ol> <li>Go to the Azure Portal.</li> <li>Navigate to \"Azure Active Directory\" > \"App registrations\".</li> <li>Create a new registration.</li> <li>Add <code>https://your-ionscale-domain.com/auth/callback</code> as a redirect URI of type \"Web\".</li> <li>Under \"Certificates & secrets\", create a new client secret.</li> <li>Copy the Application (client) ID and the new secret.</li> </ol> <p>Configure ionscale: <pre><code>auth:\n provider:\n issuer: \"https://login.microsoftonline.com/your-tenant-id/v2.0\"\n client_id: \"your-client-id\"\n client_secret: \"your-client-secret\"\n additional_scopes: \"offline_access\"\n</code></pre></p>"},{"location":"configuration/auth-oidc/#complete-configuration-example","title":"Complete configuration example","text":"<pre><code>auth:\n provider:\n issuer: \"https://accounts.google.com\"\n client_id: \"your-client-id.apps.googleusercontent.com\"\n client_secret: \"your-client-secret\"\n additional_scopes: \"groups\"\n\n system_admins:\n emails:\n - \"admin@example.com\"\n filters:\n - \"domain == \\\"example.com\\\" && token.groups contains \\\"admin\\\"\"\n</code></pre>"},{"location":"configuration/auth-oidc/#oidc-without-system-admin","title":"OIDC without system admin","text":"<p>If you've configured OIDC but no system administrators, you can still use the system admin key from your initial setup for administrative tasks:</p> <pre><code>export IONSCALE_ADDR=\"https://your-ionscale-domain.com\"\nexport IONSCALE_SYSTEM_ADMIN_KEY=\"your-system-admin-key\"\nionscale tailnet list\n</code></pre>"},{"location":"configuration/derp/","title":"DERP Configuration","text":"<p>DERP (Designated Encrypted Relay for Packets) servers are relay servers that help Tailscale clients establish connections when direct connections aren't possible due to NAT, firewalls, or other network impediments. ionscale provides flexible DERP configuration options to support various deployment scenarios.</p>"},{"location":"configuration/derp/#embedded-derp-server","title":"Embedded DERP Server","text":"<p>ionscale includes a built-in DERP server that is enabled by default. This provides an out-of-the-box relay solution without requiring additional infrastructure.</p>"},{"location":"configuration/derp/#configuration","title":"Configuration","text":"<p>The embedded DERP server can be configured in your ionscale configuration file:</p> <pre><code>derp:\n server:\n disabled: false # Set to true to disable the embedded DERP server\n region_id: 1000 # The region ID for the embedded DERP server\n region_code: \"ionscale\" # The region code (short name)\n region_name: \"ionscale Embedded DERP\" # Human-readable region name\n</code></pre> <p>Additional networking parameters that affect the DERP server:</p> <pre><code># The HTTP(S) listen address for the control plane (also used for DERP)\nlisten_addr: \":8080\"\n\n# The STUN listen address when using the embedded DERP\nstun_listen_addr: \":3478\"\n\n# The DNS name of the server HTTP(S) endpoint as accessible by clients\npublic_addr: \"ionscale.example.com:443\"\n\n# The DNS name of the STUN endpoint as accessible by clients\nstun_public_addr: \"ionscale.example.com:3478\"\n</code></pre> <p>Important</p> <p>For the embedded DERP server to function properly, clients must be able to reach your ionscale server at the configured <code>public_addr</code> and <code>stun_public_addr</code>. Ensure these addresses are publicly accessible and have the appropriate ports open in your firewall.</p>"},{"location":"configuration/derp/#external-derp-sources","title":"External DERP Sources","text":"<p>In addition to or instead of the embedded DERP server, ionscale can use external DERP servers. This is useful for:</p> <ul> <li>Using Tailscale's global DERP infrastructure</li> <li>Setting up your own geographically distributed DERP servers</li> <li>Optimizing connection paths for globally distributed teams</li> </ul> <p>To configure external DERP sources:</p> <pre><code>derp:\n sources:\n - https://controlplane.tailscale.com/derpmap/default # Tailscale's default DERP map\n - https://example.com/my-custom-derpmap.json # Custom DERP map\n - git::https://github.com/example/derpmap//config.json # From a git repository\n - file:///etc/ionscale/derpmaps/custom.json # From a local file\n</code></pre> <p>The <code>derp.sources</code> field accepts a list of URLs that point to JSON files containing DERP map configurations. These sources are loaded at server startup and merged with the embedded DERP configuration (if enabled).</p> <p>Source locations</p> <p>ionscale uses HashiCorp's go-getter library to fetch external sources, which supports multiple protocols and source types:</p> <ul> <li>HTTP/HTTPS: <code>https://example.com/derpmap.json</code></li> <li>Local files: <code>file:///path/to/derpmap.json</code></li> <li>Git repositories: <code>git::https://github.com/user/repo//path/to/file.json</code></li> <li>S3 buckets: <code>s3::https://s3.amazonaws.com/bucket/derpmap.json</code></li> <li>GCS buckets: <code>gcs::https://www.googleapis.com/storage/v1/bucket/derpmap.json</code></li> </ul> <p>This flexibility allows you to store and manage your DERP maps in various locations based on your organization's needs.</p> <p>Note</p> <p>At the time of writing, ionscale only loads external DERP sources at startup and does not automatically poll them for changes. To apply changes to external DERP sources, you will need to restart the ionscale server.</p>"},{"location":"configuration/derp/#instance-and-tailnet-derp-configuration","title":"Instance and Tailnet DERP Configuration","text":"<p>ionscale provides a flexible DERP configuration model:</p>"},{"location":"configuration/derp/#default-instance-configuration","title":"Default Instance Configuration","text":"<p>By default, all tailnets use the DERP map defined at the instance level, which includes:</p> <ul> <li>The embedded DERP server (if enabled)</li> <li>Any external DERP sources configured in your ionscale configuration file</li> </ul> <p>You can view the instance-level DERP map with:</p> <pre><code>ionscale system get-derp-map [--json]\n</code></pre>"},{"location":"configuration/derp/#tailnet-specific-configuration","title":"Tailnet-Specific Configuration","text":"<p>Each tailnet can be configured with its own custom DERP map. This gives you the flexibility to:</p> <ul> <li>Provide optimized DERP configurations for teams in different regions</li> <li>Test new DERP setups on specific tailnets before broader deployment</li> <li>Create specialized network paths for particular use cases</li> </ul> <p>When a tailnet doesn't have a custom DERP map configured, it automatically uses the instance's default DERP map.</p> <p>Managing tailnet-specific DERP maps:</p> <pre><code># View a tailnet's current DERP map\nionscale tailnets get-derp-map --tailnet <tailnet-id> [--json]\n\n# Set a custom DERP map for a specific tailnet\nionscale tailnets set-derp-map --tailnet <tailnet-id> --file <derpmap.json>\n\n# Remove the custom configuration and revert to the instance default\nionscale tailnets reset-derp-map --tailnet <tailnet-id>\n</code></pre>"},{"location":"configuration/derp/#creating-custom-derp-maps","title":"Creating Custom DERP Maps","text":"<p>A DERP map is a JSON structure containing regions and nodes. Here's an example:</p> <pre><code>{\n \"Regions\": {\n \"1\": {\n \"RegionID\": 1,\n \"RegionCode\": \"nyc\",\n \"RegionName\": \"New York City\",\n \"Nodes\": [\n {\n \"Name\": \"1a\",\n \"RegionID\": 1,\n \"HostName\": \"derp1.example.com\",\n \"DERPPort\": 443,\n \"STUNPort\": 3478\n }\n ]\n },\n \"2\": {\n \"RegionID\": 2,\n \"RegionCode\": \"sfo\",\n \"RegionName\": \"San Francisco\",\n \"Nodes\": [\n {\n \"Name\": \"2a\",\n \"RegionID\": 2,\n \"HostName\": \"derp2.example.com\",\n \"DERPPort\": 443,\n \"STUNPort\": 3478\n }\n ]\n }\n }\n}\n</code></pre> <p>Important fields:</p> <ul> <li><code>RegionID</code>: A unique identifier for the region (1-999 for custom regions, 1000+ reserved for ionscale)</li> <li><code>RegionCode</code>: A short code for the region (e.g., \"nyc\", \"sfo\")</li> <li><code>RegionName</code>: A human-readable name for the region</li> <li><code>Nodes</code>: A list of DERP servers in the region</li> <li><code>Name</code>: A unique name for the node within the region</li> <li><code>HostName</code>: The DNS name of the DERP server</li> <li><code>DERPPort</code>: The port for DERP traffic (typically 443)</li> <li><code>STUNPort</code>: The port for STUN traffic (typically 3478)</li> </ul> <p>To apply a custom DERP map to a tailnet:</p> <pre><code># Create the DERP map file\ncat > my-derpmap.json <<EOF\n{\n \"Regions\": {\n \"1\": {\n \"RegionID\": 1,\n \"RegionCode\": \"custom\",\n \"RegionName\": \"My Custom DERP\",\n \"Nodes\": [\n {\n \"Name\": \"derp1\",\n \"RegionID\": 1,\n \"HostName\": \"derp.example.com\",\n \"DERPPort\": 443,\n \"STUNPort\": 3478\n }\n ]\n }\n }\n}\nEOF\n\n# Apply it to a tailnet\nionscale tailnets set-derp-map --tailnet <tailnet-id> --file my-derpmap.json\n</code></pre> <p>Tip</p> <p>DERP servers primarily help with establishing connections when direct peer-to-peer connections aren't possible. Having DERP servers geographically close to your users can improve connection establishment times and provide better fallback performance.</p> <p>Note</p> <p>Changes to DERP maps are automatically distributed to clients during their regular polling. There's no need to manually update clients when changing DERP configurations.</p>"},{"location":"configuration/dns-providers/","title":"Configuring DNS providers","text":"<p>ionscale supports integration with various DNS providers to enable Tailscale's HTTPS certificate functionality. When a DNS provider is properly configured, ionscale can automatically manage TXT records required for the DNS-01 challenge when requesting certificates.</p>"},{"location":"configuration/dns-providers/#why-configure-a-dns-provider","title":"Why configure a DNS provider","text":"<p>While not strictly required for basic ionscale operation, configuring a DNS provider enables important Tailscale features:</p> <ol> <li>Tailscale HTTPS Certificates: Allows nodes to receive valid HTTPS certificates for their Tailscale hostnames, enabling secure web services within your tailnet.</li> <li>Tailscale Serve: Supports the <code>tailscale serve</code> feature, which allows users to easily share web services with proper HTTPS.</li> </ol> <p>Without a configured DNS provider, these features will not be available to your users.</p>"},{"location":"configuration/dns-providers/#supported-dns-providers","title":"Supported DNS providers","text":"<p>ionscale supports DNS providers through two methods:</p>"},{"location":"configuration/dns-providers/#built-in-providers-deprecated","title":"Built-in providers (deprecated)","text":"<p>ionscale includes built-in support for the following DNS providers using libdns libraries:</p> <ul> <li>Azure DNS</li> <li>Cloudflare</li> <li>DigitalOcean</li> <li>Google Cloud DNS</li> <li>Amazon Route 53</li> </ul> <p>Built-in providers are deprecated</p> <p>The built-in DNS providers are deprecated and will be removed in a future release. Please migrate to external DNS plugins for continued support.</p>"},{"location":"configuration/dns-providers/#external-dns-plugins-recommended","title":"External DNS plugins (recommended)","text":"<p>ionscale now supports external DNS plugins through a plugin system. This allows for:</p> <ul> <li>Extensibility: Add support for any DNS provider without modifying ionscale</li> <li>Maintainability: Plugins are maintained independently</li> <li>Flexibility: Plugin configuration specific to each provider's needs</li> </ul> <p>Plugin availability</p> <p>External DNS plugins implement the libdns-plugin interface. Official plugin implementations can be found in the ionscale GitHub organization with repositories named <code>ionscale-<provider>-dns</code>. You can also create your own following the plugin specification.</p>"},{"location":"configuration/dns-providers/#dns-provider-configuration","title":"DNS provider configuration","text":"<p>To configure a DNS provider, add the appropriate settings to your ionscale configuration file (<code>config.yaml</code>):</p>"},{"location":"configuration/dns-providers/#built-in-provider-configuration","title":"Built-in provider configuration","text":"<pre><code>dns:\n # The base domain for MagicDNS FQDN hostnames\n magic_dns_suffix: \"ionscale.net\"\n\n # DNS provider configuration for HTTPS certificates\n provider:\n # Name of your DNS provider\n name: \"cloudflare\"\n # The DNS zone to use (typically your domain name)\n zone: \"example.com\"\n # Provider-specific configuration (varies by provider)\n config:\n # Provider-specific credentials and settings go here\n # See provider-specific examples below\n</code></pre>"},{"location":"configuration/dns-providers/#external-plugin-configuration","title":"External plugin configuration","text":"<pre><code>dns:\n # The base domain for MagicDNS FQDN hostnames\n magic_dns_suffix: \"ionscale.net\"\n\n # DNS provider configuration for HTTPS certificates\n provider:\n # Path to your DNS plugin executable\n plugin_path: \"/path/to/your/dns-plugin\"\n # The DNS zone to use (typically your domain name)\n zone: \"example.com\"\n # Plugin-specific configuration (varies by plugin)\n config:\n # Plugin-specific credentials and settings go here\n # See plugin documentation for configuration options\n</code></pre>"},{"location":"configuration/dns-providers/#important-requirements","title":"Important requirements","text":"<ol> <li>The <code>magic_dns_suffix</code> must be a subdomain of the provider's zone (or the zone itself).</li> <li>MagicDNS must be enabled for the tailnet to use HTTPS certificates.</li> <li>You must have administrative access to the DNS zone to configure the provider.</li> <li>For external plugins, the plugin executable must be accessible and executable by the ionscale process.</li> </ol>"},{"location":"configuration/dns-providers/#provider-specific-examples","title":"Provider-specific examples","text":""},{"location":"configuration/dns-providers/#cloudflare","title":"Cloudflare","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n name: \"cloudflare\"\n zone: \"example.com\"\n config:\n api_token: \"your-cloudflare-api-token\"\n</code></pre> <p>For Cloudflare, create an API token with the \"Edit\" permission for \"Zone:DNS\".</p>"},{"location":"configuration/dns-providers/#azure-dns","title":"Azure DNS","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n name: \"azure\"\n zone: \"example.com\"\n config:\n tenant_id: \"your-tenant-id\"\n client_id: \"your-client-id\"\n client_secret: \"your-client-secret\"\n subscription_id: \"your-subscription-id\"\n resource_group_name: \"your-resource-group\"\n</code></pre> <p>For Azure, create a service principal with \"DNS Zone Contributor\" role for your DNS zone's resource group.</p>"},{"location":"configuration/dns-providers/#amazon-route-53","title":"Amazon Route 53","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n name: \"route53\"\n zone: \"example.com\"\n config:\n access_key_id: \"your-access-key-id\"\n secret_access_key: \"your-secret-access-key\"\n # Optional region, defaults to us-east-1\n region: \"us-east-1\"\n ...\n</code></pre> <p>For AWS Route 53, create an IAM user with permissions to modify records in your hosted zone.</p>"},{"location":"configuration/dns-providers/#google-cloud-dns","title":"Google Cloud DNS","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n name: \"googleclouddns\"\n zone: \"example-com\" # Note: GCP uses zone names without dots\n config:\n gcp_project: \"your-project-id\"\n # Optional path to a service account key file\n # gcp_application_default: \"/path/to/service-account-key.json\"\n</code></pre> <p>For Google Cloud DNS, create a service account with the \"DNS Administrator\" role.</p>"},{"location":"configuration/dns-providers/#digitalocean","title":"DigitalOcean","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n name: \"digitalocean\"\n zone: \"example.com\"\n config:\n auth_token: \"your-digitalocean-api-token\"\n</code></pre> <p>For DigitalOcean, create an API token with read and write access.</p>"},{"location":"configuration/dns-providers/#external-dns-plugin-examples","title":"External DNS plugin examples","text":""},{"location":"configuration/dns-providers/#using-a-hypothetical-cloudflare-plugin","title":"Using a hypothetical Cloudflare plugin","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n plugin_path: \"/usr/local/bin/libdns-cloudflare-plugin\"\n zone: \"example.com\"\n config:\n api_token: \"your-cloudflare-api-token\"\n</code></pre>"},{"location":"configuration/dns-providers/#using-a-custom-dns-plugin","title":"Using a custom DNS plugin","text":"<pre><code>dns:\n magic_dns_suffix: \"ts.example.com\"\n provider:\n plugin_path: \"/opt/dns-plugins/my-custom-provider\"\n zone: \"example.com\"\n config:\n # Configuration specific to your custom plugin\n endpoint: \"https://api.mydnsprovider.com\"\n api_key: \"your-api-key\"\n custom_setting: \"value\"\n</code></pre> <p>Plugin development</p> <p>To create your own DNS plugin, implement the libdns-plugin interface. The plugin system uses HashiCorp's go-plugin framework for communication between ionscale and your plugin.</p>"},{"location":"configuration/dns-providers/#enabling-https-certificates-for-a-tailnet","title":"Enabling HTTPS certificates for a tailnet","text":"<p>After configuring a DNS provider in your ionscale server, you can enable HTTPS certificates for a tailnet:</p> <pre><code># Enable MagicDNS and HTTPS certificates for a tailnet\nionscale dns update --tailnet \"my-tailnet\" --magic-dns --https-certs\n</code></pre>"},{"location":"configuration/dns-providers/#verifying-dns-provider-configuration","title":"Verifying DNS provider configuration","text":"<p>To verify that your DNS provider is correctly configured:</p> <ol> <li>Configure a tailnet with MagicDNS and HTTPS certificates enabled.</li> <li>Connect a device to the tailnet.</li> <li>On the device, run: <pre><code>tailscale cert <hostname>\n</code></pre></li> <li>If successful, the command will obtain a certificate for the hostname.</li> <li>You should see TXT records created in your DNS zone for the ACME challenge.</li> </ol>"},{"location":"configuration/dns-providers/#troubleshooting","title":"Troubleshooting","text":"<p>If you encounter issues with DNS provider integration:</p>"},{"location":"configuration/dns-providers/#general-troubleshooting","title":"General troubleshooting","text":"<ol> <li>Check DNS Provider Credentials: Ensure the credentials in your configuration have sufficient permissions.</li> <li>Verify Zone Configuration: Make sure the zone in your configuration matches your actual DNS zone.</li> <li>Check MagicDNS Settings: Confirm that <code>magic_dns_suffix</code> is properly configured as a subdomain of your zone.</li> <li>Review Server Logs: The ionscale server logs may contain error messages related to DNS provider integration.</li> <li>Test DNS Record Creation: Some providers offer tools to test API access for creating and updating DNS records.</li> </ol>"},{"location":"configuration/dns-providers/#external-plugin-troubleshooting","title":"External plugin troubleshooting","text":"<ol> <li>Plugin Executable: Ensure the plugin path is correct and the executable has proper permissions.</li> <li>Plugin Logs: Check both ionscale logs and any plugin-specific logs for error messages.</li> <li>Plugin Health: ionscale automatically restarts failed plugins, but persistent failures may indicate configuration issues.</li> </ol>"},{"location":"getting-started/","title":"Getting started with ionscale","text":"<p>After installing ionscale, you'll need to configure the CLI to interact with your server. This guide will walk you through the initial setup and explain the authentication options available.</p>"},{"location":"getting-started/#installing-the-ionscale-cli","title":"Installing the ionscale CLI","text":"<p>The ionscale CLI is the primary tool for managing your ionscale instance. It allows you to create and manage tailnets, users, and access controls.</p> <pre><code># Download the CLI (adjust the URL for your system architecture)\ncurl -L -o ionscale https://github.com/jsiebens/ionscale/releases/download/v0.17.0/ionscale_linux_amd64\n\n# Make it executable\nchmod +x ionscale\n\n# Move to system path\nsudo mv ionscale /usr/local/bin/\n</code></pre>"},{"location":"getting-started/#authentication-requirements","title":"Authentication requirements","text":"<p>To use the ionscale CLI, you must authenticate with the server using one of two methods:</p> <p>Administrator access required</p> <p>All management operations require either:</p> <ol> <li>System admin key authentication, or</li> <li>OIDC user authentication with system administrator privileges</li> </ol>"},{"location":"getting-started/#option-1-using-the-system-admin-key","title":"Option 1: Using the system admin key","text":"<p>If you configured ionscale with a system admin key during installation, you can authenticate using that key:</p> <pre><code># Configure environment variables\nexport IONSCALE_ADDR=\"https://ionscale.example.com\"\nexport IONSCALE_SYSTEM_ADMIN_KEY=\"your-system-admin-key\"\n\n# Verify connection\nionscale version\n</code></pre> <p>The system admin key provides full administrative access to your ionscale instance. This is the default authentication method when OIDC is not configured.</p>"},{"location":"getting-started/#option-2-using-oidc-authentication","title":"Option 2: Using OIDC authentication","text":"<p>If you configured ionscale with an OIDC provider, users designated as system administrators in the OIDC configuration can authenticate:</p> <pre><code># Configure URL only\nexport IONSCALE_ADDR=\"https://ionscale.example.com\"\n\n# Authenticate through OIDC\nionscale auth login\n</code></pre> <p>This will open a browser window where you can authenticate with your OIDC provider. After successful authentication, if your account has system administrator privileges, you'll be able to use the CLI.</p> <p>OIDC system administrators</p> <p>System administrators are defined in the ionscale configuration under the <code>auth.system_admins</code> section. See the Authentication with OIDC documentation for details.</p>"},{"location":"getting-started/#basic-cli-commands","title":"Basic CLI commands","text":"<p>Once authenticated, you can use the ionscale CLI to manage your instance:</p> <pre><code># View general information\nionscale version # Show version information\nionscale help # Display help information\n\n# Tailnet management\nionscale tailnet list # List all tailnets\nionscale tailnet create -n NAME # Create a new tailnet\n\n# Auth key management\nionscale auth-key list --tailnet NAME # List auth keys for a tailnet\nionscale auth-key create --tailnet NAME # Create a new auth key\n</code></pre>"},{"location":"getting-started/acl-policies/","title":"ACL Policies","text":"<p>Access Control Lists (ACLs) define what network access is allowed within a tailnet. By default, tailnets are created with an open policy that allows all connections between devices.</p>"},{"location":"getting-started/acl-policies/#understanding-acl-policies","title":"Understanding ACL policies","text":"<p>ACL policies in ionscale follow the same format and rules as Tailscale's ACL system. They allow you to control:</p> <ul> <li>Which devices can communicate with each other</li> <li>What ports and protocols are allowed</li> <li>Who can use exit nodes and other special features</li> <li>SSH access between machines</li> <li>Tag ownership and management</li> </ul>"},{"location":"getting-started/acl-policies/#basic-acl-structure","title":"Basic ACL structure","text":"<p>A basic ACL policy contains rules that specify which sources can access which destinations:</p> <pre><code>{\n \"acls\": [\n {\"action\": \"accept\", \"src\": [\"tag:web\"], \"dst\": [\"tag:db:5432\"]},\n {\"action\": \"accept\", \"src\": [\"group:admins\"], \"dst\": [\"*:*\"]}\n ],\n \"groups\": {\n \"admins\": [\"admin@example.com\"]\n },\n \"tagOwners\": {\n \"tag:web\": [\"admin@example.com\"],\n \"tag:db\": [\"admin@example.com\"]\n }\n}\n</code></pre> <p>In this example: - Web servers (tagged <code>tag:web</code>) can only access database servers on port 5432 - Admins have full access to all resources - Only admin@example.com can assign the web and database tags to machines</p>"},{"location":"getting-started/acl-policies/#managing-acl-policies","title":"Managing ACL policies","text":"<p>You can view and update the ACL policy for a tailnet using the ionscale CLI:</p> <pre><code># View current ACL policy\nionscale acl get --tailnet \"my-tailnet\"\n\n# Update ACL policy from a file\nionscale acl update --tailnet \"my-tailnet\" --file acl.json\n</code></pre> <p>Tip</p> <p>ACL changes take effect immediately for all devices in the tailnet.</p>"},{"location":"getting-started/acl-policies/#common-acl-patterns","title":"Common ACL patterns","text":""},{"location":"getting-started/acl-policies/#allow-specific-tags-to-communicate","title":"Allow specific tags to communicate","text":"<pre><code>{\n \"acls\": [\n {\"action\": \"accept\", \"src\": [\"tag:web\"], \"dst\": [\"tag:api:8080\"]},\n {\"action\": \"accept\", \"src\": [\"tag:api\"], \"dst\": [\"tag:db:5432\"]}\n ]\n}\n</code></pre>"},{"location":"getting-started/acl-policies/#group-based-access","title":"Group-based access","text":"<pre><code>{\n \"acls\": [\n {\"action\": \"accept\", \"src\": [\"group:developers\"], \"dst\": [\"tag:dev-env:*\"]},\n {\"action\": \"accept\", \"src\": [\"group:ops\"], \"dst\": [\"*:*\"]}\n ],\n \"groups\": {\n \"developers\": [\"alice@example.com\", \"bob@example.com\"],\n \"ops\": [\"charlie@example.com\", \"diana@example.com\"]\n }\n}\n</code></pre>"},{"location":"getting-started/acl-policies/#ssh-access-control","title":"SSH access control","text":"<pre><code>{\n \"ssh\": [\n {\n \"action\": \"accept\",\n \"src\": [\"group:admins\"],\n \"dst\": [\"tag:server\"],\n \"users\": [\"root\"]\n },\n {\n \"action\": \"accept\",\n \"src\": [\"group:developers\"],\n \"dst\": [\"tag:dev\"],\n \"users\": [\"autogroup:nonroot\"]\n }\n ]\n}\n</code></pre>"},{"location":"getting-started/acl-policies/#auto-approving-advertised-routes","title":"Auto-approving advertised routes","text":"<pre><code>{\n \"autoApprovers\": {\n \"routes\": {\n \"10.0.0.0/24\": [\"group:network-admins\"],\n \"192.168.1.0/24\": [\"user@example.com\"]\n },\n \"exitNode\": [\"group:network-admins\"]\n }\n}\n</code></pre>"},{"location":"getting-started/acl-policies/#additional-resources","title":"Additional resources","text":"<p>For more detailed information on ACL syntax and capabilities, see the Tailscale ACL documentation.</p> <p>Feature support</p> <p>Not all ACL features from the official Tailscale control plane are supported in ionscale. Some advanced features or newer functionality may not be available.</p>"},{"location":"getting-started/iam-policies/","title":"IAM Policies","text":"<p>Identity and Access Management (IAM) policies in ionscale control who can access a tailnet and what administrative permissions they have.</p> <p>OIDC required</p> <p>IAM policies are only relevant when an OIDC provider is configured. If your ionscale instance isn't using OIDC, access to tailnets is managed solely through auth keys.</p>"},{"location":"getting-started/iam-policies/#understanding-iam-policies","title":"Understanding IAM policies","text":"<p>IAM policies determine:</p> <ul> <li>Which users can join a tailnet</li> <li>What roles and permissions users have within the tailnet</li> <li>How access decisions are made based on user attributes</li> </ul> <p>An IAM policy consists of:</p> <pre><code>{\n \"subs\": [\"auth0|123456789\"],\n \"filters\": [\"domain == example.com\"],\n \"emails\": [\"specific-user@otherdomain.com\"],\n \"roles\": {\n \"admin@example.com\": \"admin\"\n }\n}\n</code></pre>"},{"location":"getting-started/iam-policies/#iam-policy-components","title":"IAM policy components","text":""},{"location":"getting-started/iam-policies/#subs","title":"Subs","text":"<p>The <code>subs</code> list provides direct access based on user IDs (subjects):</p> <pre><code>\"subs\": [\"auth0|123456789\", \"google-oauth2|12345\"]\n</code></pre> <p>Any user whose ID matches an entry in this list will be granted access to the tailnet. User IDs are typically provided by the OIDC provider and are unique identifiers for each user.</p>"},{"location":"getting-started/iam-policies/#emails","title":"Emails","text":"<p>The <code>emails</code> list provides direct access to specific email addresses:</p> <pre><code>\"emails\": [\"alice@example.com\", \"bob@otherdomain.com\"]\n</code></pre> <p>Any user with an email in this list will be granted access to the tailnet, regardless of filters.</p>"},{"location":"getting-started/iam-policies/#filters","title":"Filters","text":"<p>Filters are expressions that evaluate user attributes:</p> <pre><code>\"filters\": [\"domain == example.com\", \"email.endsWith('@engineering.example.com')\"]\n</code></pre> <p>These expressions determine if a user can access the tailnet based on their identity attributes. Users matching any filter expression will be granted access.</p>"},{"location":"getting-started/iam-policies/#roles","title":"Roles","text":"<p>The <code>roles</code> map assigns specific roles to users:</p> <pre><code>\"roles\": {\n \"admin@example.com\": \"admin\",\n \"devops@example.com\": \"admin\",\n \"developer@example.com\": \"member\"\n}\n</code></pre> <p>Available roles: - <code>admin</code>: Can manage tailnet settings, ACLs, and auth keys - <code>member</code>: Standard access to use the tailnet (default)</p>"},{"location":"getting-started/iam-policies/#managing-iam-policies","title":"Managing IAM policies","text":"<p>View and update IAM policies using the ionscale CLI:</p> <pre><code># View current IAM policy\nionscale iam get-policy --tailnet \"my-tailnet\"\n\n# Update IAM policy using a JSON file\nionscale iam update-policy --tailnet \"my-tailnet\" --file policy.json\n</code></pre>"},{"location":"getting-started/iam-policies/#common-iam-patterns","title":"Common IAM patterns","text":""},{"location":"getting-started/iam-policies/#domain-based-tailnet","title":"Domain-based tailnet","text":"<p>Grant access to everyone with the same email domain:</p> <pre><code>{\n \"filters\": [\"domain == example.com\"],\n \"roles\": {\n \"admin1@example.com\": \"admin\",\n \"admin2@example.com\": \"admin\"\n }\n}\n</code></pre>"},{"location":"getting-started/iam-policies/#personal-tailnet","title":"Personal tailnet","text":"<p>Create a tailnet for individual use:</p> <pre><code>{\n \"emails\": [\"personal@example.com\"],\n \"roles\": {\n \"personal@example.com\": \"admin\"\n }\n}\n</code></pre>"},{"location":"getting-started/iam-policies/#setting-iam-during-tailnet-creation","title":"Setting IAM during tailnet creation","text":"<p>You can set basic IAM policies during tailnet creation with CLI flags:</p> <pre><code># Allow all users with an @example.com email address\nionscale tailnet create --name \"shared-tailnet\" --domain \"example.com\"\n\n# Allow only a specific user\nionscale tailnet create --name \"personal-tailnet\" --email \"user@example.com\"\n</code></pre> <p>These shortcuts create appropriate filter rules or email entries in the IAM policy.</p>"},{"location":"getting-started/iam-policies/#iam-policy-evaluation","title":"IAM policy evaluation","text":"<p>When a user attempts to access a tailnet, the following checks occur:</p> <ol> <li>Is the user's ID in the <code>subs</code> list? If yes, grant access.</li> <li>Is the user's email in the <code>emails</code> list? If yes, grant access.</li> <li>Does the user match any expression in the <code>filters</code> list? If yes, grant access.</li> <li>If none of these conditions are met, access is denied.</li> </ol> <p>For role determination:</p> <ol> <li>Check if the user has an entry in the <code>roles</code> map</li> <li>If yes, assign that role</li> <li>If no, assign the default <code>member</code> role</li> </ol>"},{"location":"getting-started/iam-policies/#security-considerations","title":"Security considerations","text":"<ul> <li>Principle of least privilege: Start with minimal access and add users or filters as needed</li> <li>Regular audits: Periodically review IAM policies to ensure only appropriate users have access</li> <li>Admin roles: Limit admin roles to trusted users who need to manage tailnet settings</li> </ul>"},{"location":"getting-started/iam-policies/#troubleshooting-access-issues","title":"Troubleshooting access issues","text":"<p>If a user is having trouble accessing a tailnet:</p> <ol> <li>Verify the user's email is correct and matches their OIDC identity</li> <li>Check filter expressions to ensure they match the user's attributes</li> <li>Verify the user is authenticating against the correct ionscale instance</li> <li>Check OIDC provider configuration and token issuance</li> </ol>"},{"location":"getting-started/tailnet/","title":"Creating your first tailnet","text":"<p>A tailnet is a private network that connects your devices securely using Tailscale. This guide will walk you through creating your first tailnet with ionscale.</p>"},{"location":"getting-started/tailnet/#prerequisites","title":"Prerequisites","text":"<p>Before creating a tailnet, make sure you have:</p> <ul> <li>ionscale server installed and running</li> <li>The ionscale CLI installed and configured</li> <li>Authentication with system administrator privileges</li> </ul>"},{"location":"getting-started/tailnet/#creating-a-tailnet","title":"Creating a tailnet","text":"<p>The simplest way to create a tailnet is with the <code>tailnet create</code> command:</p> <pre><code>ionscale tailnet create --name \"my-first-tailnet\"\n</code></pre> <p>This creates a basic tailnet named \"my-first-tailnet\" with:</p> <ul> <li>A default ACL policy that allows all connections <pre><code>{\"acls\": [{\"action\": \"accept\", \"src\": [\"*\"], \"dst\": [\"*:*\"]}]}\n</code></pre></li> <li>A default IAM policy that determines who can access the tailnet</li> </ul> <p>Note</p> <p>The tailnet name must be unique within your ionscale instance and should only contain alphanumeric characters, hyphens, and underscores.</p>"},{"location":"getting-started/tailnet/#setting-iam-policies-for-access-control","title":"Setting IAM policies for access control","text":"<p>OIDC required</p> <p>IAM policies are only relevant when an OIDC provider is configured. If your ionscale instance isn't using OIDC, access to tailnets is managed solely through auth keys, and the configuration in this section won't apply.</p> <p>When using OIDC authentication, you'll need to configure who can access your tailnet through IAM policies.</p>"},{"location":"getting-started/tailnet/#configuring-iam-during-tailnet-creation","title":"Configuring IAM during tailnet creation","text":"<p>You can set a basic IAM policy when creating a tailnet using flags:</p> <pre><code># Allow all users with an @example.com email address\nionscale tailnet create --name \"company-tailnet\" --domain \"example.com\"\n\n# Allow only a specific user\nionscale tailnet create --name \"personal-tailnet\" --email \"user@example.com\"\n</code></pre> <p>These flags provide quick ways to set up common IAM policies:</p> <ul> <li> <p><code>--domain example.com</code>: Creates a shared tailnet that allows all users with an email address from the specified domain. This is ideal for company or team networks where multiple users need access. The IAM policy will contain a filter rule like <code>domain == \"example.com\"</code>.</p> </li> <li> <p><code>--email user@example.com</code>: Creates a personal tailnet that grants access only to the specific email address. This is suitable for individual use or when you want to tightly control access to a specific user. The IAM policy will contain an entry for the specified email.</p> </li> </ul> <p>Note</p> <p>You can't use both flags together. Choose either domain-based access for a shared network or email-based access for a personal network.</p>"},{"location":"getting-started/tailnet/#configuring-iam-after-tailnet-creation","title":"Configuring IAM after tailnet creation","text":"<p>You can view and update the IAM policy for an existing tailnet:</p> <pre><code># View current IAM policy\nionscale iam get-policy --tailnet \"my-first-tailnet\"\n\n# Update IAM policy using a JSON file\nionscale iam update-policy --tailnet \"my-first-tailnet\" --file policy.json\n</code></pre> <p>Example policy.json file: <pre><code>{\n \"filters\": [\"domain == example.com\"],\n \"emails\": [\"specific-user@otherdomain.com\"],\n \"roles\": {\n \"admin@example.com\": \"admin\"\n }\n}\n</code></pre></p>"},{"location":"getting-started/tailnet/#connecting-devices-to-your-tailnet","title":"Connecting devices to your tailnet","text":"<p>There are two main methods to connect devices to your tailnet:</p> <p>Tip</p> <p>For detailed instructions on configuring various Tailscale clients to use ionscale as a control server, refer to the Tailscale Knowledge Base.</p>"},{"location":"getting-started/tailnet/#interactive-login","title":"Interactive login","text":"<p>When you have an OIDC provider configured, users can connect to their tailnet through an interactive web authentication flow:</p> <pre><code>tailscale up --login-server=https://ionscale.example.com\n</code></pre> <p>This opens a browser window where the user authenticates with the OIDC provider. After successful authentication, if the user has access based on the tailnet's IAM policy, the device will be connected to the tailnet.</p> <p>Note</p> <p>Interactive login requires an OIDC provider to be configured on your ionscale instance.</p>"},{"location":"getting-started/tailnet/#using-pre-authentication-keys","title":"Using pre-authentication keys","text":"<p>Pre-authentication keys (auth keys) allow devices to join a tailnet without interactive authentication. This is useful for automated deployments, servers, or environments where browser-based authentication isn't practical.</p> <p>To create an auth key:</p> <pre><code># Create an auth key\nionscale auth-key create --tailnet \"my-first-tailnet\"\n\n# Create an auth key with specific tags\nionscale auth-key create --tailnet \"my-first-tailnet\" --tags \"tag:server\"\n</code></pre> <p>The tags assigned to the key will determine what network access the device has once connected, based on your ACL rules.</p> <p>Note</p> <p>In environments with OIDC, users with access to a tailnet can create auth keys for that tailnet. Without OIDC, only system administrators can create keys.</p> <p>To connect a device using an auth key:</p> <pre><code># Connect using the auth key\ntailscale up --login-server=https://ionscale.example.com --auth-key=...\n</code></pre>"},{"location":"getting-started/tailnet/#network-access-and-security-policies","title":"Network access and security policies","text":"<p>By default, tailnets are created with an open policy that allows all connections between devices. For production environments, you'll want to configure:</p> <ul> <li>IAM Policies: Manage who can access your tailnet</li> <li>ACL Policies: Control which devices can communicate within your tailnet</li> </ul> <p>Tip</p> <p>For detailed information on configuring security policies, see the dedicated documentation sections on IAM Policies and ACL Policies.</p>"},{"location":"getting-started/tailnet/#managing-multiple-tailnets","title":"Managing multiple tailnets","text":"<p>You can create multiple tailnets to separate different network environments:</p> <pre><code># List all tailnets\nionscale tailnet list\n\n# Create tailnets for different teams or businesses\nionscale tailnet create --name \"tailnet-a\"\nionscale tailnet create --name \"tailnet-b\"\nionscale tailnet create --name \"tailnet-c\"\n</code></pre> <p>Note</p> <p>Each tailnet is a separate network with its own devices, ACLs, and IAM policies. Devices in different tailnets cannot communicate with each other by default.</p>"},{"location":"installation/","title":"Installation guide","text":"<p>ionscale can be installed in several ways, depending on your preferences and requirements. This section covers the different installation methods available.</p>"},{"location":"installation/#choose-your-installation-method","title":"Choose your installation method","text":"<p>ionscale offers two primary installation methods:</p>"},{"location":"installation/#docker-installation","title":"Docker installation","text":"<p>The Docker installation method is recommended for:</p> <ul> <li>Quick deployments</li> <li>Testing and evaluation</li> <li>Users familiar with container environments</li> <li>Simplified upgrades and maintenance</li> </ul> <p>Docker provides an isolated environment with all dependencies included, making it the easiest way to get started with ionscale.</p>"},{"location":"installation/#linux-installation","title":"Linux installation","text":"<p>The Linux installation method is suitable for:</p> <ul> <li>Production environments</li> <li>Integration with existing infrastructure</li> <li>More control over the installation</li> <li>Systems without Docker</li> </ul> <p>This approach installs ionscale directly on your Linux server and configures it as a system service.</p>"},{"location":"installation/#post-installation-steps","title":"Post-installation steps","text":"<p>After completing the installation, consider these next steps:</p> <ol> <li>Configure an OIDC provider for user authentication</li> <li>Set up a DNS provider to enable HTTPS certificates for Tailscale nodes</li> <li>Create and configure tailnets</li> <li>Set up access controls and permissions</li> </ol>"},{"location":"installation/docker/","title":"Installing ionscale with Docker","text":"<p>This guide will walk you through installing and configuring ionscale using Docker containers. Docker provides a simple and consistent way to deploy ionscale across different environments.</p>"},{"location":"installation/docker/#prerequisites","title":"Prerequisites","text":"<p>Before you begin, make sure you have:</p> <ul> <li>A Linux server (virtual or physical)</li> <li>Docker installed (official Docker installation guide)</li> <li>Root or sudo access</li> <li>A registered domain name pointing to your server</li> <li>Ports 443 (HTTPS) and 3478/UDP (STUN) open in your firewall</li> <li>Basic familiarity with the Linux command line</li> </ul>"},{"location":"installation/docker/#domain-and-dns-configuration","title":"Domain and DNS configuration","text":"<p>ionscale requires a domain name to function properly. This enables secure HTTPS connections and proper Tailscale device discovery.</p> <ol> <li> <p>Configure an A record in your domain's DNS settings: <pre><code>ionscale.example.com \u2192 YOUR_SERVER_IP\n</code></pre> (Replace \"example.com\" with your actual domain and \"YOUR_SERVER_IP\" with your server's public IP address)</p> </li> <li> <p>Verify the DNS record has propagated: <pre><code>dig ionscale.example.com\n</code></pre> The command should return your server's public IP address.</p> </li> </ol>"},{"location":"installation/docker/#container-setup","title":"Container setup","text":""},{"location":"installation/docker/#creating-a-directory-structure","title":"Creating a directory structure","text":"<p>Create a dedicated directory for ionscale files:</p> <pre><code>mkdir -p ionscale/data\ncd ./ionscale\n</code></pre>"},{"location":"installation/docker/#generating-a-configuration-file","title":"Generating a configuration file","text":"<p>First, set up environment variables for the configuration:</p> <pre><code>export IONSCALE_ACME_EMAIL=\"your-email@example.com\" # Used for Let's Encrypt notifications\nexport IONSCALE_DOMAIN=\"ionscale.example.com\" # Your ionscale domain\nexport IONSCALE_SYSTEM_ADMIN_KEY=$(docker run --rm ghcr.io/jsiebens/ionscale:0.17.0 genkey -n)\n</code></pre> <p>System admin key</p> <p>The system admin key is a critical security component that provides full administrative access to your ionscale instance. Make sure to save this key securely.</p> <p>Alternatively, you can configure ionscale without a system admin key by using an OIDC provider and setting up system admin accounts through the OIDC configuration. See the Authentication with OIDC documentation for details.</p> <p>Now create the configuration file:</p> <pre><code>cat > ./config.yaml <<EOF\nlisten_addr: \":443\"\npublic_addr: \"${IONSCALE_DOMAIN}:443\"\nstun_public_addr: \"${IONSCALE_DOMAIN}:3478\"\n\ntls:\n acme: true\n acme_email: \"${IONSCALE_ACME_EMAIL}\"\n\nkeys:\n system_admin_key: \"${IONSCALE_SYSTEM_ADMIN_KEY}\"\n\ndatabase:\n url: \"/data/ionscale.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)\"\n\nlogging:\n level: info\nEOF\n</code></pre>"},{"location":"installation/docker/#running-the-container","title":"Running the container","text":"<p>Start the ionscale container with the following command:</p> <pre><code>docker run -d \\\n --name ionscale \\\n --restart unless-stopped \\\n -v $(pwd)/config.yaml:/etc/ionscale/config.yaml \\\n -v $(pwd)/data:/data \\\n -p 443:443 \\\n -p 3478:3478/udp \\\n ghcr.io/jsiebens/ionscale:0.17.0 server --config /etc/ionscale/config.yaml\n</code></pre> <p>This command:</p> <ul> <li>Creates a persistent container named \"ionscale\"</li> <li>Mounts your configuration file and data directory</li> <li>Maps the required ports to the host</li> <li>Automatically restarts the container if it stops unexpectedly</li> </ul>"},{"location":"installation/linux/","title":"Linux installation","text":"<p>This guide walks you through installing ionscale directly on a Linux server. This approach gives you more control over the installation and is suitable for production environments.</p>"},{"location":"installation/linux/#prerequisites","title":"Prerequisites","text":"<p>Before you begin, make sure you have:</p> <ul> <li>A Linux server (virtual or physical)</li> <li>Root or sudo access</li> <li>A registered domain name pointing to your server</li> <li>Ports 443 (HTTPS) and 3478/UDP (STUN) open in your firewall</li> <li>Basic familiarity with the Linux command line</li> </ul>"},{"location":"installation/linux/#domain-and-dns-configuration","title":"Domain and DNS configuration","text":"<p>ionscale requires a domain name to function properly. This enables secure HTTPS connections and proper Tailscale device discovery.</p> <ol> <li> <p>Configure an A record in your domain's DNS settings: <pre><code>ionscale.example.com \u2192 YOUR_SERVER_IP\n</code></pre> (Replace \"example.com\" with your actual domain and \"YOUR_SERVER_IP\" with your server's public IP address)</p> </li> <li> <p>Verify the DNS record has propagated: <pre><code>dig ionscale.example.com\n</code></pre> The command should return your server's public IP address.</p> </li> </ol>"},{"location":"installation/linux/#quick-deployment","title":"Quick deployment","text":"<p>If you prefer an automated deployment, you can use our installation script:</p> <pre><code># Download the script\ncurl -fsSL https://raw.githubusercontent.com/jsiebens/ionscale/main/scripts/install.sh -o install.sh\nchmod +x install.sh\n\n# Run the script (interactive mode)\n./install.sh\n</code></pre> <p>The script will prompt you for: 1. Your domain name for ionscale 2. Your email address (for Let's Encrypt notifications)</p> <p>For non-interactive installation, set the required environment variables:</p> <pre><code>export IONSCALE_DOMAIN=\"ionscale.example.com\"\nexport IONSCALE_ACME_EMAIL=\"your-email@example.com\"\n./install.sh\n</code></pre> <p>The script automatically:</p> <ol> <li>Determines your system architecture</li> <li>Creates a dedicated service user</li> <li>Downloads and installs the latest ionscale binary</li> <li>Generates a secure system admin key</li> <li>Creates necessary configuration files</li> <li>Sets up and starts the systemd service</li> </ol> <p>For a detailed explanation of each step, continue reading the manual installation instructions below.</p>"},{"location":"installation/linux/#system-preparation","title":"System preparation","text":""},{"location":"installation/linux/#create-a-dedicated-service-user","title":"Create a dedicated service user","text":"<p>For security reasons, ionscale should run under a dedicated, unprivileged system user:</p> <pre><code># Create service user\nsudo useradd --system --no-create-home --shell /bin/false ionscale\n\n# Create directories\nsudo mkdir -p /etc/ionscale\nsudo mkdir -p /var/lib/ionscale\n\n# Set appropriate permissions\nsudo chown ionscale:ionscale /etc/ionscale\nsudo chown ionscale:ionscale /var/lib/ionscale\n</code></pre>"},{"location":"installation/linux/#installation","title":"Installation","text":""},{"location":"installation/linux/#download-and-install-the-binary","title":"Download and install the binary","text":"<p>Install the ionscale binary on your system:</p> <pre><code># Download the latest version (adjust for your CPU architecture)\nsudo curl -o \"/usr/local/bin/ionscale\" \\\n -sfL \"https://github.com/jsiebens/ionscale/releases/download/v0.17.0/ionscale_linux_amd64\"\n\n# Make it executable\nsudo chmod +x \"/usr/local/bin/ionscale\"\n\n# Verify installation\nionscale version\n</code></pre>"},{"location":"installation/linux/#configuration","title":"Configuration","text":"<ol> <li>Generate a system admin key and store it in an environment file:</li> </ol> <pre><code>sudo tee /etc/default/ionscale >/dev/null <<EOF\nIONSCALE_KEYS_SYSTEM_ADMIN_KEY=$(ionscale genkey -n)\nEOF\n</code></pre> <p>System admin key</p> <p>The system admin key is a critical security component that provides full administrative access to your ionscale instance. Make sure to save this key securely.</p> <p>Alternatively, you can configure ionscale without a system admin key by using an OIDC provider and setting up system admin accounts through the OIDC configuration. See the Authentication with OIDC documentation for details.</p> <ol> <li>Set up environment variables for the configuration:</li> </ol> <pre><code>export IONSCALE_ACME_EMAIL=\"your-email@example.com\" # For Let's Encrypt notifications\nexport IONSCALE_DOMAIN=\"ionscale.example.com\" # Your ionscale domain\n</code></pre> <ol> <li>Create the configuration file:</li> </ol> <pre><code>sudo tee /etc/ionscale/config.yaml >/dev/null <<EOF\nlisten_addr: \":443\"\npublic_addr: \"${IONSCALE_DOMAIN}:443\"\nstun_public_addr: \"${IONSCALE_DOMAIN}:3478\"\n\ntls:\n acme: true\n acme_email: \"${IONSCALE_ACME_EMAIL}\"\n\ndatabase:\n url: \"/var/lib/ionscale/ionscale.db?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)\"\n\nkeys:\n system_admin_key: \"\\${IONSCALE_KEYS_SYSTEM_ADMIN_KEY}\"\n\nlogging:\n level: info\nEOF\n</code></pre>"},{"location":"installation/linux/#setting-up-systemd-service","title":"Setting up systemd service","text":"<p>Create a systemd service file to manage the ionscale process:</p> <pre><code>sudo tee /etc/systemd/system/ionscale.service >/dev/null <<EOF\n[Unit]\nDescription=ionscale - a Tailscale control server\nRequires=network-online.target\nAfter=network.target\n\n[Service]\nEnvironmentFile=/etc/default/ionscale\nUser=ionscale\nGroup=ionscale\nExecStart=/usr/local/bin/ionscale server --config /etc/ionscale/config.yaml\nRestart=on-failure\nRestartSec=10s\nAmbientCapabilities=CAP_NET_BIND_SERVICE\n\n[Install]\nWantedBy=multi-user.target\nEOF\n</code></pre> <p>The <code>AmbientCapabilities=CAP_NET_BIND_SERVICE</code> line allows ionscale to bind to privileged ports (443) without running as root.</p>"},{"location":"installation/linux/#starting-ionscale","title":"Starting ionscale","text":"<p>Enable and start the ionscale service:</p> <pre><code># Reload systemd to recognize the new service\nsudo systemctl daemon-reload\n\n# Enable service to start on boot\nsudo systemctl enable ionscale\n\n# Start the service\nsudo systemctl start ionscale\n\n# Check status\nsudo systemctl status ionscale\n</code></pre> <p>If everything started successfully, you should see an \"active (running)\" status.</p>"},{"location":"overview/features/","title":"Supported features","text":"<p>ionscale implements key Tailscale features to provide a complete control server experience. This page outlines the major features that ionscale supports.</p>"},{"location":"overview/features/#multi-tailnet-support","title":"Multi-tailnet support","text":"<p>ionscale allows you to create and manage multiple tailnets (Tailscale private networks) from a single server:</p> <ul> <li>Create isolated networks for different teams or environments</li> <li>Manage separate tailnets for personal and organizational use</li> <li>Configure each tailnet with its own ACLs and settings</li> </ul>"},{"location":"overview/features/#user-management","title":"User management","text":"<ul> <li>Multi-user support: Multiple users can access and use the same tailnet based on permissions</li> <li>OIDC integration: Optional but recommended for user authentication and management</li> </ul>"},{"location":"overview/features/#authentication","title":"Authentication","text":"<ul> <li>Auth keys: Generate and manage pre-authentication keys for devices</li> <li>Device tagging: Apply tags to devices for better management and ACL control</li> </ul>"},{"location":"overview/features/#network-control","title":"Network control","text":"<ul> <li>Access control lists (ACLs): Define fine-grained rules for who can access what</li> <li>Subnet routers: Connect existing networks to your tailnet</li> <li>Exit nodes: Configure nodes to act as VPN exit points</li> </ul>"},{"location":"overview/features/#dns-management","title":"DNS management","text":"<ul> <li>MagicDNS: Automatic DNS for tailnet devices</li> <li>Split DNS: Route specific DNS queries to specific resolvers</li> <li>Custom nameservers: Configure any DNS servers for your tailnet</li> </ul>"},{"location":"overview/features/#https-and-certificates","title":"HTTPS and certificates","text":"<ul> <li>HTTPS certificates: Automatic SSL/TLS certificates for devices</li> <li>DNS provider integration: Support for various DNS providers to facilitate ACME challenges</li> <li>Tailscale Serve: Share web services easily with HTTPS</li> </ul>"},{"location":"overview/features/#ssh","title":"SSH","text":"<ul> <li>Tailscale SSH: Built-in SSH server support</li> <li>SSH policy management: Control who can SSH into which devices</li> </ul>"},{"location":"overview/features/#derp","title":"DERP","text":"<ul> <li>Embedded DERP server</li> <li>Custom DERP maps: Configure your own DERP servers</li> </ul>"},{"location":"overview/features/#file-sharing","title":"File sharing","text":"<ul> <li>Taildrop: Send files directly between tailnet devices</li> </ul>"},{"location":"overview/features/#feature-status","title":"Feature status","text":"<p>Most features are fully implemented and compatible with the official Tailscale clients. As ionscale is continuously developed, new features from Tailscale are regularly added.</p> <p>If you find any issues with specific features or have requests for additional functionality, please check the project repository for the latest updates or to submit feedback.</p>"}]} |