{"captainVersion":2,"dockerCompose":{"services":{"$$cap_appname-signal":{"containerHttpPort":"80","dockerfileLines":["FROM debian:bookworm-slim","RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*","RUN useradd -r -m -d /home/hopsignal -s /usr/sbin/nologin hopsignal","WORKDIR /home/hopsignal","RUN curl -fsSL -o /usr/local/bin/hopsignal https://www.hoptodesk.com/servers/hopsignal.fil && chmod 755 /usr/local/bin/hopsignal && touch /home/hopsignal/fedlist.txt && chown -R hopsignal:hopsignal /home/hopsignal","USER hopsignal","EXPOSE 80","CMD [\"hopsignal\", \"--ADDR\", \"0.0.0.0:80\", \"--FEDLIST\", \"/home/hopsignal/fedlist.txt\", \"--FEDADDR\", \"0.0.0.0:82\", \"--FEDPWD\", \"123456789\", \"--LOGFILE\", \"/home/hopsignal/hs.log\"]"]},"$$cap_appname":{"image":"nginx:1.27-alpine","command":["/bin/sh","-c","set -eu\nrm -rf /usr/share/nginx/html/*\nmkdir -p \"/usr/share/nginx/html/${HOP_CONFIG_SECRET_PATH}\"\ncat > \"/usr/share/nginx/html/${HOP_CONFIG_SECRET_PATH}/api.json\" <<JSON\n{\n  \"turnservers\": [\n    {\n      \"protocol\": \"turn\",\n      \"host\": \"${HOP_TURN_HOST}\",\n      \"port\": \"${HOP_TURN_PORT}\",\n      \"username\": \"${HOP_TURN_USERNAME}\",\n      \"password\": \"${HOP_TURN_PASSWORD}\"\n    }\n  ],\n  \"rendezvous\": {\n    \"host\": \"${HOP_SIGNAL_HOST}\",\n    \"port\": \"${HOP_SIGNAL_PORT}\"\n  },\n  \"rendezvousssl\": {\n    \"host\": \"${HOP_SIGNAL_HOST}\",\n    \"port\": \"${HOP_SIGNAL_PORT}\"\n  },\n  \"winversion\": \"1.0.0\",\n  \"macversion\": \"1.0.0\",\n  \"linuxversion\": \"1.0.0\",\n  \"none\": \"none\"\n}\nJSON\nexec nginx -g 'daemon off;'\n"],"environment":{"HOP_SIGNAL_HOST":"$$cap_appname-signal.$$cap_root_domain","HOP_SIGNAL_PORT":"443","HOP_TURN_HOST":"$$cap_appname-turn.$$cap_root_domain","HOP_TURN_PORT":"$$cap_TURN_PORT","HOP_TURN_USERNAME":"$$cap_TURN_USERNAME","HOP_TURN_PASSWORD":"$$cap_TURN_PASSWORD","HOP_CONFIG_SECRET_PATH":"$$cap_CONFIG_SECRET_PATH"},"containerHttpPort":"80"},"$$cap_appname-turn":{"image":"coturn/coturn:$$cap_COTURN_VERSION","ports":["$$cap_TURN_PORT:3478","$$cap_TURN_RELAY_PORT:$$cap_TURN_RELAY_PORT"],"command":["turnserver","--no-cli","--log-file=stdout","--lt-cred-mech","--realm=$$cap_TURN_REALM","--user=$$cap_TURN_USERNAME:$$cap_TURN_PASSWORD","--listening-ip=0.0.0.0","--listening-port=3478","--min-port=$$cap_TURN_RELAY_PORT","--max-port=$$cap_TURN_RELAY_PORT","--external-ip=$$cap_TURN_PUBLIC_IP","--fingerprint","--no-multicast-peers","--no-tls","--no-dtls"],"notExposeAsWebApp":"true"}}},"variables":[{"id":"$$cap_CONFIG_SECRET_PATH","label":"Config secret path","defaultValue":"$$cap_gen_random_hex(16)","validRegex":"/^[a-zA-Z0-9_.-]+$/","description":"Secret URL path for api.json. Keep it private and do not include slashes."},{"id":"$$cap_TURN_PUBLIC_IP","label":"TURN public IP","defaultValue":"","validRegex":"/^([0-9]{1,3}\\.){3}[0-9]{1,3}$/","description":"Public IPv4 address of this CapRover server."},{"id":"$$cap_TURN_PORT","label":"TURN port","defaultValue":"3478","validRegex":"/^[0-9]+$/","description":"External TURN listener port. CapRover publishes both TCP and UDP."},{"id":"$$cap_TURN_RELAY_PORT","label":"TURN relay port","defaultValue":"49152","validRegex":"/^[0-9]+$/","description":"Single relay allocation port for personal use. Add more ports later if needed."},{"id":"$$cap_TURN_REALM","label":"TURN realm","defaultValue":"your-domain.com","validRegex":"/^[a-zA-Z0-9.-]+$/","description":"coturn authentication realm. Use your CapRover root domain, for example your-domain.com."},{"id":"$$cap_TURN_USERNAME","label":"TURN username","defaultValue":"hoptodesk","validRegex":"/^[a-zA-Z0-9_.-]+$/","description":"Username published in api.json."},{"id":"$$cap_TURN_PASSWORD","label":"TURN password","defaultValue":"$$cap_gen_random_hex(24)","validRegex":"/^.{12,}$/","description":"Password published in api.json. Keep it private."},{"id":"$$cap_COTURN_VERSION","label":"coturn image version","defaultValue":"latest","validRegex":"/^([a-zA-Z0-9_.-])+$/","description":"Docker tag for coturn/coturn."}],"instructions":{"start":"Deploy a personal HopToDesk network on your CapRover server.\n\nThis one-click app creates three CapRover apps. If you enter \"hoptodesk\" as the App Name on your-domain.com, the public endpoints will be:\n- hoptodesk.your-domain.com/<config-secret-path>/api.json for HopToDesk clients\n- hoptodesk-signal.your-domain.com for HopSignal\n- hoptodesk-turn.your-domain.com for TURN\n\nBefore installing:\n1. Make sure wildcard DNS for *.your-domain.com points to this CapRover server, or create DNS records for the three endpoints above.\n2. Open firewall ports 80/tcp, 443/tcp, 3478/tcp, 3478/udp, 49152/tcp, and 49152/udp, unless you change the TURN ports below.\n3. Set TURN public IP to the public IPv4 address of this server.","end":"HopToDesk personal network deployed.\n\nNext steps:\n1. Enable HTTPS for the signal app and verify WebSocket support is enabled.\n2. Enable HTTPS for the main app.\n3. Verify https://<app-name>.your-domain.com/<config-secret-path>/api.json returns JSON.\n4. On iPad, set HopToDesk Choose Network to https://<app-name>.your-domain.com/<config-secret-path>/api.json.\n5. If relay fails, add more individual relay ports to the TURN service and increase max-port."},"displayName":"HopToDesk Personal Network","isOfficial":false,"description":"Personal HopToDesk HopSignal plus minimal coturn relay and api.json endpoint.","documentation":"https://www.hoptodesk.com/on-premises"}
