{
  "manifest_version": "1.0.0",
  "template": {
    "id": "f9f8cce6-75ee-4212-a783-50c093d1c875",
    "slug": "minecraft-server-1",
    "name": "Minecraft Server",
    "description": "Paper Minecraft server with web console and plugins for friends",
    "url": "https://railway.com/deploy/minecraft-server-1",
    "upstream": {
      "image": "caddy:2.11.4-alpine"
    }
  },
  "services": [
    {
      "name": "Caddy",
      "source": {
        "image": "caddy:2.11.4-alpine"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "Crafty Controller",
      "source": {
        "image": "arcadiatechnology/crafty-4:4.10.8"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "tcp_ports": [
        25565
      ],
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "PORT",
      "service": "Caddy",
      "description": "Port Caddy listens on; matches the Caddy service's public HTTP proxy.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "CRAFTY_HOST",
      "service": "Caddy",
      "description": "Private hostname of the Crafty Controller service; Caddy proxies the panel to it over Railway's private network.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "TZ",
      "service": "Crafty Controller",
      "description": "Optional IANA timezone for panel and Minecraft server timestamps.",
      "secret": false,
      "strategy": "default",
      "default": "Etc/UTC"
    },
    {
      "key": "RAILWAY_RUN_UID",
      "service": "Crafty Controller",
      "description": "Runs the image launcher as root so it can prepare the root-owned Railway volume, then Crafty drops to its upstream user.",
      "secret": false,
      "strategy": "default",
      "default": "0"
    },
    {
      "key": "CRAFTY_ADMIN_PASSWORD",
      "service": "Crafty Controller",
      "description": "Generated panel password. Sign in as admin; copy this value from the Crafty Controller service's Variables tab.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "minecraft-server-1"
      }
    },
    "cli": "railway deploy --template minecraft-server-1",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "f9f8cce6-75ee-4212-a783-50c093d1c875",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "d83b74c4-7c58-4000-8717-2cef33e94891": {
                  "icon": "https://bogusz.co/external/caddy-icon.png",
                  "name": "Caddy",
                  "deploy": {
                    "startCommand": "/bin/sh -c 'printf \"%s\\n\" \":${PORT} {\" \"  reverse_proxy https://${CRAFTY_HOST}:8443 {\" \"    header_up Host {http.request.host}\" \"    transport http {\" \"      tls_insecure_skip_verify\" \"    }\" \"  }\" \"}\" > /tmp/Caddyfile; exec caddy run --config /tmp/Caddyfile --adapter caddyfile'",
                    "healthcheckPath": "/status",
                    "restartPolicyType": "ALWAYS",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "caddy:2.11.4-alpine"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Port Caddy listens on; matches the Caddy service's public HTTP proxy.",
                      "defaultValue": "8080"
                    },
                    "CRAFTY_HOST": {
                      "isOptional": true,
                      "description": "Private hostname of the Crafty Controller service; Caddy proxies the panel to it over Railway's private network.",
                      "defaultValue": "${{\"Crafty Controller\".RAILWAY_PRIVATE_DOMAIN}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                },
                "ed587e21-a7d9-4e18-92cc-039d9eb52e3b": {
                  "icon": "https://bogusz.co/external/crafty-controller-icon.png",
                  "name": "Crafty Controller",
                  "deploy": {
                    "startCommand": "/bin/sh -c 'set -eu; cd /; mv /crafty /image-crafty; root=/data/root2; hold=/data/.crafty-state; mkdir -p \"$hold\"; if [ -d \"$root/app/config\" ] && [ ! -e \"$hold/config\" ]; then mv \"$root/app/config\" \"$hold/config\"; fi; for d in backups logs servers import; do if [ -d \"$root/$d\" ] && [ ! -e \"$hold/$d\" ]; then mv \"$root/$d\" \"$hold/$d\"; fi; done; rm -rf \"$root\"; mkdir \"$root\"; cp -aL /image-crafty/. \"$root/\"; seeded=0; rm -rf \"$root/app/config\"; if [ -d \"$hold/config\" ]; then mv \"$hold/config\" \"$root/app/config\"; else cp -a \"$root/app/config_original\" \"$root/app/config\"; rm -f \"$root/app/config/default.json\"; umask 077; printf '\"'\"'{\"username\":\"admin\",\"password\":\"%s\"}\\n'\"'\"' \"$CRAFTY_ADMIN_PASSWORD\" > \"$root/app/config/default.json\"; chown crafty:root \"$root/app/config/default.json\"; seeded=1; fi; for d in backups logs servers import; do rm -rf \"$root/$d\"; if [ -d \"$hold/$d\" ]; then mv \"$hold/$d\" \"$root/$d\"; else mkdir \"$root/$d\"; chown crafty:root \"$root/$d\"; chmod g+rwx \"$root/$d\"; fi; done; image_hash=$(sha256sum /image-crafty/main.py | cut -d \" \" -f1); runtime_hash=$(sha256sum \"$root/main.py\" | cut -d \" \" -f1); [ \"$image_hash\" = \"$runtime_hash\" ]; printf \"Image refresh verified: main.py sha256=%s\\n\" \"$runtime_hash\"; if [ \"$seeded\" = 1 ]; then (while [ ! -s \"$root/app/config/default-creds.txt\" ]; do sleep 1; done; rm -f \"$root/app/config/default.json\" \"$root/app/config/default-creds.txt\"; [ ! -e \"$root/app/config/default.json\" ]; printf \"Credential seed removed after admin creation\\n\") & else [ ! -e \"$root/app/config/default.json\" ]; printf \"Credential seed absent: persisted admin state reused\\n\"; fi; ln -s \"$root\" /crafty; cd /crafty; exec ./docker_launcher.sh -d -i'",
                    "healthcheckPath": null,
                    "restartPolicyType": "ALWAYS",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "arcadiatechnology/crafty-4:4.10.8"
                  },
                  "variables": {
                    "TZ": {
                      "isOptional": true,
                      "description": "Optional IANA timezone for panel and Minecraft server timestamps.",
                      "defaultValue": "Etc/UTC"
                    },
                    "RAILWAY_RUN_UID": {
                      "isOptional": true,
                      "description": "Runs the image launcher as root so it can prepare the root-owned Railway volume, then Crafty drops to its upstream user.",
                      "defaultValue": "0"
                    },
                    "CRAFTY_ADMIN_PASSWORD": {
                      "isOptional": true,
                      "description": "Generated panel password. Sign in as admin; copy this value from the Crafty Controller service's Variables tab.",
                      "defaultValue": "{{CRAFTY_ADMIN_PASSWORD}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {
                      "25565": {}
                    }
                  },
                  "volumeMounts": {
                    "ed587e21-a7d9-4e18-92cc-039d9eb52e3b": {
                      "mountPath": "/data"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "Caddy",
      "method": "GET",
      "path": "/status",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 2,
    "needs_volume": true
  },
  "generated_at": "2026-09-04T05:44:27.711Z",
  "generator_version": "0.1.0",
  "status": "validated",
  "validated_at": "2026-09-04T04:59:56.594Z",
  "success_rate_30d": 1,
  "validation": {
    "last_run_id": "run_d8bd7975a83341c38330",
    "checks": [
      {
        "name": "workflow_completed",
        "passed": true
      },
      {
        "name": "all_services_deployed",
        "passed": true
      },
      {
        "name": "healthcheck",
        "passed": true
      },
      {
        "name": "stays_up",
        "passed": true
      }
    ],
    "typical_ready_seconds": 144
  }
}
