Sign in
EN

A custom domain for a playground project

A project published on the playground (https://jumphp.net) can have its own address, e.g. monapp.example.org, served like bin/jumphp deploy does: the project's site (site/) at the root ({{DOMAIN}} = the domain), the game or application in /play/. The HTTPS certificate comes by itself at the first visit.

For the project's owner

  1. Studio → the project → Custom domain → the domain → Add the domain.
  2. At the domain's DNS host, two records (the studio shows them, ready to copy):
    monapp.example.org.          CNAME  apps.jumphp.net.
    _jumphp.monapp.example.org.  TXT    "jumphp-verify=<the studio's token>"
    
    • the CNAME points to the server, without proxy (Cloudflare: grey cloud, "DNS only"): the server must see the TLS connection to get the certificate;
    • the TXT proves the domain is yours;
    • a root domain (no subdomain) cannot have a CNAME: give it the same IP addresses (A / AAAA) as apps.jumphp.net.
  3. Check the DNS (propagation can take minutes; the studio says what is missing: the TXT, or the CNAME).
  4. Depending on the playground's settings, the administrator approves the domain ("Waiting for the administrator"), or it is online as soon as it is verified.
  5. Open https://monapp.example.org/: the first visit makes the certificate (a few seconds).

Disabling the domain cuts it at once; Enable brings it back. A later failed check (CNAME removed) takes it offline. The domain always serves the published version, and nothing of the portal (no studio, no sign-in, no cookie). The game asks its TCP tickets from its own origin and opens wss://<the domain>/tcp: nothing to set.

For the playground's administrator

Administration → Partner sites and domains: every domain, its state, Check the DNS, Approve / remove the approval, Block (the owner cannot restore it), Delete.

How it is served: Traefik passes only the served domains through to the playground's Caddy (its HTTP provider reads http://jumphp-playground-internal:9180/api/domains/traefik: a TCP HostSNI(...) passthrough router to jumphp-playground-tls@docker and a port-80 router to jumphp-playground-http@docker). No low-priority HostSNI(*) catch-all: Traefik applies TCP routers before the HTTP routers of the same entry point, so a catch-all would take the TLS of every other site of that Traefik. Caddy (docker/Caddyfile) has an https:// site (CUSTOM_DOMAINS_SITE) with tls { on_demand } and on_demand_tls { ask http://127.0.0.1:9180/api/domains/ask }; /api/domains/ask?domain=x answers 200 only for a served domain (verified, on, not blocked, approved when approval is required, project published).

Settings (deploy/.env): CUSTOM_DOMAINS_SITE (https:// turns it on; default serves nothing), CUSTOM_DOMAINS_TARGET (apps.jumphp.net), CUSTOM_DOMAINS_APPROVAL (1: the administrator approves each domain; 0: the DNS check is enough), TRAEFIK_ENTRYPOINT, TRAEFIK_HTTP_ENTRYPOINT.

Once: apps.jumphp.net A <server IP> (DNS only), Traefik's static configuration providers.http.endpoint: "http://jumphp-playground-internal:9180/api/domains/traefik" (pollInterval: "15s"), then CUSTOM_DOMAINS_SITE=https:// in deploy/.env and a redeploy of the playground.