{"id":20947512,"url":"https://github.com/unredacted/ansible-role-freesocks","last_synced_at":"2026-04-02T02:06:03.736Z","repository":{"id":261174150,"uuid":"843695842","full_name":"unredacted/ansible-role-freesocks","owner":"unredacted","description":"An Ansible role to help with the deployment of new FreeSocks Outline VPN servers","archived":false,"fork":false,"pushed_at":"2026-03-31T01:20:12.000Z","size":153,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-31T03:32:13.315Z","etag":null,"topics":["ansible","ansible-role","cloudflare","fastly","outline-vpn"],"latest_commit_sha":null,"homepage":"https://freesocks.org","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unredacted.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-17T06:15:47.000Z","updated_at":"2026-03-31T01:20:16.000Z","dependencies_parsed_at":"2024-11-05T05:18:46.789Z","dependency_job_id":"a94bef24-3e17-4b11-8586-140bde6f9c92","html_url":"https://github.com/unredacted/ansible-role-freesocks","commit_stats":null,"previous_names":["unredacted/ansible-role-freesocks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/unredacted/ansible-role-freesocks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unredacted%2Fansible-role-freesocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unredacted%2Fansible-role-freesocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unredacted%2Fansible-role-freesocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unredacted%2Fansible-role-freesocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unredacted","download_url":"https://codeload.github.com/unredacted/ansible-role-freesocks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unredacted%2Fansible-role-freesocks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31294398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T01:43:37.129Z","status":"online","status_checked_at":"2026-04-02T02:00:08.535Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","cloudflare","fastly","outline-vpn"],"created_at":"2024-11-19T00:11:51.390Z","updated_at":"2026-04-02T02:06:03.723Z","avatar_url":"https://github.com/unredacted.png","language":"Jinja","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ansible-role-freesocks\n\nAn Ansible role for deploying and managing Outline VPN servers for [FreeSocks](https://freesocks.org/). This role supports both new server deployments and migrations between servers, with features including:\n\n- Automated Outline server installation and configuration\n- Pluggable provider architecture for DNS, tunnel, and KV store\n- Cloudflare integration (DNS, Tunnel, KV) with more providers coming soon\n- Hostname rotation for DNS blocking bypass\n- Server migration capabilities\n\n## Requirements\n\n- Debian-based Linux system (tested on Debian only)\n- Python 3.x\n- Docker (will be installed by the role)\n- Provider-specific requirements (see Provider Configuration)\n\n## Provider Configuration\n\nThe role uses a pluggable provider architecture. All providers must be explicitly set via `--extra-vars`.\n\n| Provider | Options | Purpose |\n|----------|---------|---------|\n| `dns_provider` | `cloudflare` | DNS record management |\n| `tunnel_provider` | `cloudflare`, `none` | Secure tunnel for API/Prometheus access |\n| `kv_provider` | `cloudflare` | Server endpoint storage |\n\n### Cloudflare Provider Requirements\n\nWhen using Cloudflare providers, you need:\n- API token with appropriate permissions\n- Account ID and Zone ID(s)\n- KV namespaces (for `kv_provider: cloudflare`)\n- Access Team configuration (for Prometheus access via tunnel)\n\n## Role Variables\n\n### Required Variables\n\n```yaml\n# Provider Configuration (required via --extra-vars)\ndns_provider: \"cloudflare\"\ntunnel_provider: \"cloudflare\"  # or \"none\" for direct port access\nkv_provider: \"cloudflare\"\n\n# Environment Mode (required via --extra-vars)  \nenvironment_mode: \"prod\"  # or \"dev\"\n\n# Operation Mode\noperation_mode: \"deploy\"  # or \"migrate\"\n\n# Cloudflare Configuration (when using Cloudflare providers)\ncloudflare_api_endpoint: \"https://api.cloudflare.com/client/v4\"\ncloudflare_api_token: \"your-api-token\"  # API Token (not Global API Key)\ncloudflare_account_id: \"your-account-id\"\ncloudflare_zone_id: \"your-zone-id\"\ncloudflare_access_team_name: \"your-team-name\"\ncloudflare_access_aud_tag: \"your-aud-tag\"\n\n# KV Namespace Configuration\ncloudflare_api_kv_namespace_prod: \"your-prod-api-kv-namespace\"\ncloudflare_prom_kv_namespace_prod: \"your-prod-prom-kv-namespace\"\ncloudflare_api_kv_namespace_dev: \"your-dev-api-kv-namespace\"\ncloudflare_prom_kv_namespace_dev: \"your-dev-prom-kv-namespace\"\n\n# Domain Configuration\n# Zone IDs are looked up from domain_providers based on the domain\n# Optionally include per-domain credentials for multi-account setups\ndomain_providers:\n  example.com:\n    dns_provider: cloudflare\n    tunnel_provider: none\n    zone_id: \"your-zone-id-for-com\"\n  example.app:\n    dns_provider: cloudflare\n    tunnel_provider: none\n    zone_id: \"your-zone-id-for-app\"\n  # Domain on a different Cloudflare account\n  other-domain.com:\n    dns_provider: cloudflare\n    tunnel_provider: none\n    zone_id: \"zone-id-for-other-account\"\n    # Override credentials for this domain\n    cloudflare_api_token: \"your-api-token-for-other-account\"\n    cloudflare_account_id: \"account-id-for-other-account\"  # Needed for tunnels\n\n# Active domain for operations (typically set via deploy_target_domain or change_target_domain)\nbase_domain: \"example.com\"\napi_domain: \"example.com\"\nprom_domain: \"example.com\"\nkv_hostname_prefix: \"outline\"\n\n# Envoy Mappings (for multi-IP DNS records)\nenvoy_mappings:\n  outline1-ams:\n    ipv4: [\"1.2.3.4\", \"5.6.7.8\"]\n    ipv6: [\"2001:db8::1\", \"2001:db8::2\"]\n```\n\n### Optional Variables\n\n```yaml\n# Server Configuration\noutline_keys_port: 443\noutline_api_port: 8443\ncloudflared_os_version: \"bookworm\"\nhostname_extension: \"\"\n\n# Custom hostname override (optional)\n# If set, uses this instead of auto-generating random hostname\ncustom_hostname: \"my-server\"  # Example: results in my-server.example.com\n\n# Number of words in randomly generated hostnames\nhostname_word_count: 3  # Default: 3 (e.g., apple-banana-cherry)\n\n# DNS Proxy (Cloudflare orange cloud, Fastly shield, etc.)\n# When true, traffic is proxied through the CDN\ndns_proxied: false  # Set to true for CDN proxy mode\n\n# Migration Settings\nmigrate_delete_source: false\nsource_hostname: \"\"\ndestination_hostname: \"\"\n```\n\n### WebSocket (WSS) Support\n\nEnable Shadowsocks over WebSocket for improved censorship resistance. This tunnels Shadowsocks traffic over HTTPS, making it appear as regular web traffic.\n\n```yaml\n# Enable WSS support\noutline_wss_enabled: true\n\n# Caddy configuration for automatic HTTPS\noutline_caddy_auto_https: true\noutline_caddy_email: \"admin@example.com\"\noutline_caddy_domain: \"\"  # Defaults to server hostname\n\n# WebSocket path configuration\n# Random paths use dictionary words (like hostnames) for natural-looking URLs\noutline_wss_random_paths: true  # Set to false to use custom paths\noutline_wss_random_path_min_words: 3  # Minimum words (e.g., /apple-banana-cherry)\noutline_wss_random_path_max_words: 5  # Maximum words (random in range)\n\n# Custom paths (used when outline_wss_random_paths is false)\noutline_wss_tcp_path: \"/tcp\"\noutline_wss_udp_path: \"/udp\"\n\n# Internal WebSocket server port (not externally exposed)\noutline_wss_server_port: 8080\n\n# API Proxy - enables valid TLS for API access (for control planes, etc.)\noutline_api_proxy_path: \"/api\"  # API available at https://domain/api/...\n\n# Hostname suffixes for API and Prometheus endpoints\n# Empty when using Caddy proxy (everything goes through port 443)\n# Set to \"-api\"/\"-prom\" for legacy separate subdomains\napi_hostname_suffix: \"\"   # e.g., \"\" -\u003e abc123.domain.com, \"-api\" -\u003e abc123-api.domain.com\nprom_hostname_suffix: \"\"\n```\n\n\u003e **Important:** When using WSS, set `outline_keys_port` to a non-443 port (e.g., 853) \n\u003e so that Caddy can use port 443 for HTTPS/WebSocket traffic.\n\n### slipstream DNS Tunnel Support\n\nEnable DNS tunneling for extreme censorship resistance. Traffic is tunneled through DNS queries via recursive resolvers (e.g., Yandex DNS on Russia's allowlist).\n\n**Note:** slipstream builds from source, requiring Rust on the target server. The build can take several minutes.\n\n#### Configuration\n\n```yaml\n# Enable slipstream DNS tunnel\nslipstream_enabled: true\n\n# Mode: \"shadowsocks\" (default) or \"raw\"\n# - shadowsocks: Tunnel to local Shadowsocks (client needs ss-local)\n# - raw: Direct SOCKS5 proxy via microsocks (no ss-local needed)\nslipstream_mode: \"shadowsocks\"\n\n# Client resolvers (Yandex DNS on Russia allowlist)\nslipstream_resolver: \"77.88.8.8:53\"\nslipstream_resolver_backup: \"77.88.8.1:53\"\n\n# Version and repository\nslipstream_version: \"main\"\nslipstream_repo_url: \"https://github.com/Mygod/slipstream-rust.git\"\n\n# DNS listen port (default: 53)\nslipstream_dns_port: 53\n\n# Raw mode: SOCKS5 proxy port\nslipstream_socks_port: 1080\n```\n\n**Required DNS Variables** (must be set via `--extra-vars`):\n```yaml\nslipstream_base_domain: \"your-dns.com\"  # REQUIRED - Must be in domain_providers\nslipstream_subdomain: \"dns1\"             # REQUIRED - Tunnel subdomain\nslipstream_ns_hostname: \"ns1\"            # REQUIRED - Nameserver hostname\nslipstream_create_dns_records: true      # Optional - Auto-create DNS records (default: true)\n```\n\n#### DNS Setup (Automatic)\n\nWhen `slipstream_create_dns_records: true` (default), the role automatically creates:\n\n```dns\ndns1.your-dns.com.  IN NS    ns1.your-dns.com.\nns1.your-dns.com.   IN A     \u003cserver-ipv4\u003e\nns1.your-dns.com.   IN AAAA  \u003cserver-ipv6\u003e\n```\n\n**Natural-Looking Subdomain Examples:**\n- `dns1`, `dns2` - looks like DNS infrastructure\n- `mail1`, `mail2` - looks like mail servers  \n- `ns1`, `ns2` - looks like nameservers\n- `api1`, `cdn1` - looks like infrastructure\n\n**Multiple Servers:** Use different subdomains for each server:\n```bash\n# Server 1: dns1.your-dns.com\n--extra-vars \"slipstream_subdomain=dns1 slipstream_ns_hostname=ns1\"\n\n# Server 2: dns2.your-dns.com  \n--extra-vars \"slipstream_subdomain=dns2 slipstream_ns_hostname=ns2\"\n```\n\n**Requirements:**\n- `slipstream_base_domain` must exist in `domain_providers` with a valid `zone_id`\n- Cloudflare API credentials must be configured\n\n**Manual Setup** (if `slipstream_create_dns_records: false`):\nCreate the DNS records manually in your DNS provider's dashboard.\n\n#### Mode Comparison\n\n| Feature | `shadowsocks` mode | `raw` mode |\n|---------|-------------------|------------|\n| Server target | outline-ss-server:443 | microsocks (SOCKS5):1080 |\n| Client needs | slipstream-client + ss-local | slipstream-client only |\n| Encryption layers | QUIC + Shadowsocks | QUIC only |\n| Setup complexity | Higher | Simpler |\n| Best for | Outline integration | Standalone proxy |\n\n#### Client Usage: Shadowsocks Mode\n\n```bash\n# Build slipstream-client\ngit clone https://github.com/Mygod/slipstream-rust.git\ncd slipstream-rust \u0026\u0026 git submodule update --init --recursive\ncargo build --release -p slipstream-client\n\n# Start DNS tunnel (use your actual domain from deployment)\n./target/release/slipstream-client \\\n  --tcp-listen-port 7000 \\\n  --resolver 77.88.8.8:53 \\\n  --domain dns1.your-dns.com \\\n  --cert /path/to/server-cert.pem\n\n# Connect ss-local through tunnel\nss-local -s 127.0.0.1 -p 7000 -l 1080 -k \u003cpassword\u003e -m chacha20-ietf-poly1305\n\n# Use SOCKS proxy at 127.0.0.1:1080\n```\n\n#### Client Usage: Raw Mode\n\n```bash\n# Build slipstream-client (same as above)\n# ...\n\n# Start DNS tunnel - this IS your SOCKS proxy!\n./target/release/slipstream-client \\\n  --tcp-listen-port 1080 \\\n  --resolver 77.88.8.8:53 \\\n  --domain dns1.your-dns.com \\\n  --cert /path/to/server-cert.pem\n\n# Configure apps to use SOCKS5 at 127.0.0.1:1080\n# No ss-local needed - slipstream-client IS the proxy!\n```\n\n\n## Quick Reference Guide\n\n### Deploy Mode Examples\n\n```bash\n# Basic Outline server\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\"\n\n# Outline + WebSocket (CDN fronting)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\" \\\n  --extra-vars \"outline_wss_enabled=true\"\n\n# Outline + slipstream (DNS tunnel to SS server)\n# DNS records are auto-created from slipstream_base_domain\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_base_domain=your-dns.com\"\n\n# Outline + slipstream raw (two independent transports)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\"\n\n# slipstream only (raw mode, no Outline)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\" \\\n  --extra-vars \"outline_enabled=false slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\"\n\n# Full stack (all transports)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy environment_mode=prod\" \\\n  --extra-vars \"deploy_target_domain=example.com\" \\\n  --extra-vars \"outline_wss_enabled=true slipstream_enabled=true slipstream_base_domain=your-dns.com\"\n```\n\n### Change Mode Examples\n\n```bash\n# Rotate hostname (same domain)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=change environment_mode=prod\" \\\n  --extra-vars \"change_target_domain=example.com\"\n\n# Change to different domain\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=change environment_mode=prod\" \\\n  --extra-vars \"change_target_domain=example.app\"\n\n# Keep old records\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=change environment_mode=prod\" \\\n  --extra-vars \"change_target_domain=example.app\" \\\n  --extra-vars \"change_delete_old_dns=false change_delete_old_kv=false\"\n```\n\n### Migrate Mode Examples\n\n```bash\n# Migrate server to new host\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=migrate environment_mode=prod\" \\\n  --extra-vars \"source_hostname=old-server source_kv_hostname=apple-banana\" \\\n  --extra-vars \"destination_hostname=new-server destination_kv_hostname=apple-banana\" \\\n  --extra-vars \"dns_provider=cloudflare tunnel_provider=cloudflare kv_provider=cloudflare\"\n\n# Migrate and delete source entries\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=migrate environment_mode=prod\" \\\n  --extra-vars \"source_hostname=old-server source_kv_hostname=apple-banana\" \\\n  --extra-vars \"destination_hostname=new-server destination_kv_hostname=apple-banana\" \\\n  --extra-vars \"migrate_delete_source=true\"\n```\n\n### Update Mode Examples\n\n```bash\n# Add slipstream (raw mode) to existing Outline server\n# DNS records auto-created: dns1.your-dns.com → ns1.your-dns.com → server IP\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\"\n\n# Add slipstream (shadowsocks mode) to existing Outline server\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_base_domain=your-dns.com\"\n\n# Add second slipstream server (dns2.your-dns.com)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\" \\\n  --extra-vars \"slipstream_subdomain=dns2 slipstream_ns_hostname=ns2\"\n\n# Add WebSocket to existing server\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"outline_wss_enabled=true\"\n\n# Add both slipstream and WebSocket\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\" \\\n  --extra-vars \"outline_wss_enabled=true\"\n```\n\n### Component Flags Reference\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `outline_enabled` | `true` | Deploy Outline Shadowsocks server |\n| `outline_wss_enabled` | `false` | Enable WebSocket transport (requires Outline) |\n| `slipstream_enabled` | `false` | Deploy slipstream DNS tunnel |\n| `slipstream_mode` | `shadowsocks` | `shadowsocks` (tunnel to SS) or `raw` (direct SOCKS5) |\n| `slipstream_base_domain` | **required** | Base domain for DNS (must be in domain_providers) |\n| `slipstream_subdomain` | **required** | Tunnel subdomain (dns1, mail1, etc.) |\n| `slipstream_ns_hostname` | **required** | Nameserver hostname (ns1, ns2, etc.) |\n| `slipstream_resolver` | `77.88.8.8:53` | DNS resolver for clients |\n| `force_reinstall_slipstream` | `false` | Force reinstall slipstream even if already installed |\n| `force_reinstall_wss` | `false` | Force reinstall WebSocket even if already installed |\n\n\n\n## Operation Modes\n\n### Deploy Mode\n\nDeploys a server with selected components. Deploy mode is **component-based**, allowing various combinations:\n\n**Component Selection:**\n```yaml\n# Components (set in playbook or via --extra-vars)\noutline_enabled: true         # Outline Shadowsocks server (default: true)\nslipstream_enabled: false     # slipstream DNS tunnel (default: false)\nslipstream_mode: \"shadowsocks\"  # or \"raw\" for standalone SOCKS5\noutline_wss_enabled: false    # WebSocket transport (requires Outline)\n```\n\n**Deployment Combinations:**\n| Combination | Components | Use Case |\n|-------------|------------|----------|\n| Default | Outline only | Standard FreeSocks server |\n| Outline + WSS | Outline + WebSocket | CDN-fronted censorship resistance |\n| Outline + slipstream | Outline + slipstream (SS mode) | DNS tunnel to SS server |\n| slipstream only | slipstream (raw mode) | Standalone DNS tunnel proxy |\n| Full stack | Outline + WSS + slipstream | Maximum transport options |\n\n**Steps:**\n1. Validates component selection and configuration\n2. Generates random hostname for the target domain\n3. Installs base packages\n4. Deploys enabled components (Outline, WebSocket, slipstream)\n5. Sets up DNS records via configured provider\n6. Configures tunnel (if `tunnel_provider != none`)\n7. Updates KV store with server information\n\n**Example Commands:**\n```bash\n# Default: Outline only\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy deploy_target_domain=example.com\"\n\n# Outline + slipstream (shadowsocks mode)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy deploy_target_domain=example.com\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_base_domain=your-dns.com\"\n\n# slipstream only (raw mode - no Outline needed)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=deploy deploy_target_domain=example.com\" \\\n  --extra-vars \"outline_enabled=false slipstream_enabled=true slipstream_mode=raw\"\n```\n\n### Migrate Mode\n\nMigrates an existing Outline server to a new location:\n1. Verifies source server exists in KV store\n2. Verifies /opt/outline doesn't exist on destination\n3. Installs new Outline server\n4. Copies configuration from source to destination\n5. Updates DNS and KV store entries\n6. Optionally deletes source server KV entries\n\n### Change Mode\n\nRotates the hostname on an existing server when the current hostname is blocked by DNS filtering. This mode supports changing to a different domain entirely (e.g., from `example.com` to `example.app`).\n\n1. Validates `change_target_domain` is configured in `domain_providers`\n2. Reads existing API info from server\n3. Generates new random hostname for the target domain\n4. Creates new DNS records using the domain's configured provider\n5. Updates Caddy domain configuration (triggers new TLS certificate)\n6. Updates server hostname setting\n7. Updates local config files (shadowbox_server_config.json, access.txt, Caddy config)\n8. **Restarts container** to apply changes\n9. **Waits for health check** to confirm API accessibility\n10. Updates KV store with new endpoint\n11. Optionally deletes old DNS and KV entries\n\n**Required Configuration:**\n```yaml\n# In your playbook vars\ndomain_providers:\n  example.com:\n    dns_provider: cloudflare\n    tunnel_provider: cloudflare\n    zone_id: \"your-zone-id-for-com\"\n  example.app:\n    dns_provider: cloudflare\n    tunnel_provider: cloudflare\n    zone_id: \"your-zone-id-for-app\"\n  # Future providers (framework ready)\n  # example.org:\n  #   dns_provider: fastly\n  #   tunnel_provider: none\n```\n\n**Required Variable:**\n```yaml\n# Must be passed via --extra-vars\nchange_target_domain: \"example.app\"  # Domain to generate new hostname for\n```\n\n**Optional Settings:**\n```yaml\n# Whether to delete old DNS records after hostname change\nchange_delete_old_dns: true\n# Whether to delete old KV entries after hostname change\nchange_delete_old_kv: true\n```\n\n**Usage:**\n```bash\n# Change hostname to a new random hostname on example.app\nansible-playbook -i inventory playbook.yml \\\n  --extra-vars \"operation_mode=change environment_mode=prod\" \\\n  --extra-vars \"change_target_domain=example.app\"\n```\n\nThis generates something like `apple-banana-cherry.example.app` and uses the Cloudflare provider configured for that domain.\n\n### Update Mode\n\nAdds new components (slipstream, WebSocket) to an **existing** server without reinstalling Outline. Automatically detects the existing hostname and installed components, and updates the KV store.\n\n**Use Cases:**\n- Add slipstream DNS tunnel to existing Outline server\n- Add WebSocket transport to existing Outline server\n- Switch slipstream modes (shadowsocks ↔ raw)\n- Update slipstream configuration (resolvers, domain)\n- **Recover from partial installations** (using force reinstall)\n\n**Idempotent Behavior:**\n- Components already installed are automatically skipped\n- Use `force_reinstall_slipstream=true` or `force_reinstall_wss=true` to reinstall\n\n**Steps:**\n1. Detects existing Outline installation and hostname\n2. Detects existing components (slipstream binary, WebSocket in config)\n3. Installs requested components that aren't already installed (or force reinstall)\n4. Updates KV store with new component configuration\n\n**Usage:**\n```bash\n# Add slipstream raw to existing server\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\" \\\n  --extra-vars \"slipstream_subdomain=dns1 slipstream_ns_hostname=ns1\"\n\n# Force reinstall slipstream (e.g., after partial failure or config change)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"slipstream_enabled=true slipstream_mode=raw slipstream_base_domain=your-dns.com\" \\\n  --extra-vars \"slipstream_subdomain=dns1 slipstream_ns_hostname=ns1\" \\\n  --extra-vars \"force_reinstall_slipstream=true\"\n\n# Force reinstall WebSocket (regenerate config)\nansible-playbook playbook.yml \\\n  --extra-vars \"operation_mode=update environment_mode=prod\" \\\n  --extra-vars \"outline_wss_enabled=true force_reinstall_wss=true\"\n```\n\n\n## Directory Structure\n\n```\ntasks/\n├── main.yml                 # Orchestrator with provider routing\n├── setup/\n│   ├── install.yml          # Base package installation\n│   ├── outline.yml          # Outline server setup\n│   ├── websocket.yml        # WebSocket (WSS) configuration\n│   └── slipstream.yml       # slipstream DNS tunnel setup\n├── change/\n│   └── change.yml           # Hostname change operations\n├── migrate/\n│   ├── migrate.yml          # Migration orchestration\n│   ├── transfer_config.yml  # Config transfer (provider-agnostic)\n│   └── containers.yml       # Container management\n└── providers/\n    └── cloudflare/\n        ├── install.yml      # Cloudflared installation\n        ├── dns.yml          # DNS management\n        ├── tunnel.yml       # Tunnel setup\n        ├── kv.yml           # KV store operations (JSON with slipstream)\n        └── migrate/         # Migration-specific tasks\n\ntemplates/\n└── slipstream-server.service.j2  # slipstream systemd service\n```\n\n## License\n\nGNU General Public License v3.0\n\n## Author Information\n\nThis role is maintained by the [Unredacted](https://unredacted.org/) Team.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funredacted%2Fansible-role-freesocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funredacted%2Fansible-role-freesocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funredacted%2Fansible-role-freesocks/lists"}