{
  "manifest_version": "1.0.0",
  "template": {
    "id": "760bd692-ed86-483d-b6f3-1748db72d9d9",
    "slug": "flipt-v2-envoy-grpc-web",
    "name": "Flipt v2 + Envoy (gRPC-Web)",
    "description": "Feature flags with Flipt v2 behind an Envoy gRPC-Web proxy",
    "url": "https://railway.com/deploy/flipt-v2-envoy-grpc-web",
    "upstream": {
      "repo_url": "https://github.com/agafonovim/railway-templates"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "Redis",
      "source": {
        "image": "redis:8.2"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    },
    {
      "name": "Envoy",
      "source": {
        "repo": "https://github.com/agafonovim/railway-templates"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "Flipt",
      "source": {
        "image": "flipt/flipt:v2.11.0"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/opt/flipt",
      "http": true
    }
  ],
  "required_inputs": [
    {
      "key": "REDISHOST",
      "service": "Redis",
      "description": "Private hostname other services use to reach Redis.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "REDISPORT",
      "service": "Redis",
      "description": "Port Redis listens on.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "REDISUSER",
      "service": "Redis",
      "description": "Redis username. This is the default ACL user.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "REDIS_URL",
      "service": "Redis",
      "description": "Connection string for connecting to redis using the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDISPASSWORD",
      "service": "Redis",
      "description": "Alias of REDIS_PASSWORD, kept for clients that expect this name.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "Redis",
      "description": "Password generated for the Redis default user.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "PORT",
      "service": "Envoy",
      "description": "Port Envoy listens on. Railway routes the public domain and the healthcheck to this port.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "FLIPT_UPSTREAM_HOST",
      "service": "Envoy",
      "description": "Private hostname of the Flipt service that Envoy proxies gRPC traffic to.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "FLIPT_UPSTREAM_PORT",
      "service": "Envoy",
      "description": "Flipt's gRPC port that Envoy proxies to.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "Flipt",
      "description": "Port Railway routes the public domain and the healthcheck to. Matches FLIPT_SERVER_HTTP_PORT.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RAILWAY_RUN_UID",
      "service": "Flipt",
      "description": "Runs the container as root so Flipt can write to the mounted volume. The image's non-root user cannot.",
      "secret": false,
      "strategy": "default",
      "default": "0"
    },
    {
      "key": "FLIPT_SERVER_HOST",
      "service": "Flipt",
      "description": "Address Flipt binds to. Brackets are required; a bare :: yields an invalid listen address.",
      "secret": false,
      "strategy": "default",
      "default": "[::]"
    },
    {
      "key": "FLIPT_SERVER_GRPC_PORT",
      "service": "Flipt",
      "description": "Port for Flipt's gRPC API, used by Envoy and by backend services on the private network.",
      "secret": false,
      "strategy": "default",
      "default": "9000"
    },
    {
      "key": "FLIPT_SERVER_HTTP_PORT",
      "service": "Flipt",
      "description": "Port for Flipt's UI and REST API.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "FLIPT_META_TELEMETRY_ENABLED",
      "service": "Flipt",
      "description": "Whether Flipt reports anonymous usage telemetry to its maintainers.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "FLIPT_AUTHENTICATION_REQUIRED",
      "service": "Flipt",
      "description": "Requires credentials for Flipt's API and UI. Evaluation is exempted separately.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "FLIPT_ENVIRONMENTS_DEFAULT_NAME",
      "service": "Flipt",
      "description": "Key and display name of the single built-in environment. Clients send this as environment_key.",
      "secret": false,
      "strategy": "default",
      "default": "production"
    },
    {
      "key": "FLIPT_STORAGE_DEFAULT_BACKEND_PATH",
      "service": "Flipt",
      "description": "Directory holding the Git repository of flag state. Points at the mounted volume.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FLIPT_STORAGE_DEFAULT_BACKEND_TYPE",
      "service": "Flipt",
      "description": "Storage backend. local keeps flag state on disk; the default, memory, loses it on restart.",
      "secret": false,
      "strategy": "default",
      "default": "local"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_DOMAIN",
      "service": "Flipt",
      "description": "Domain the login session cookie is registered on. Required once any login method is enabled.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_SECURE",
      "service": "Flipt",
      "description": "Marks the login session cookies HTTPS-only.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_CSRF_KEY",
      "service": "Flipt",
      "description": "Secret used to sign CSRF tokens during the login flow.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "FLIPT_AUTHENTICATION_EXCLUDE_EVALUATION",
      "service": "Flipt",
      "description": "Leaves flag evaluation reachable without credentials while the rest of Flipt stays protected.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_STORAGE_TYPE",
      "service": "Flipt",
      "description": "Where login sessions are kept. redis survives restarts; memory signs everyone out on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "redis"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_SCOPES",
      "service": "Flipt",
      "description": "OAuth scopes requested from GitHub. read:org is required for the organization check to run.",
      "secret": false,
      "strategy": "default",
      "default": "read:org"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_ENABLED",
      "service": "Flipt",
      "description": "Turns on signing in to the Flipt UI with GitHub.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_ID",
      "service": "Flipt",
      "description": "Client ID of the GitHub OAuth App. Its callback URL is https://<your-flipt-domain>/auth/v1/method/github/callback.",
      "secret": false,
      "strategy": "ask_user"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_HOST",
      "service": "Flipt",
      "description": "Hostname of the Redis that holds login sessions.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_MODE",
      "service": "Flipt",
      "description": "Redis topology, single or cluster. Required whenever Redis session storage is used.",
      "secret": false,
      "strategy": "default",
      "default": "single"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_PORT",
      "service": "Flipt",
      "description": "Port of the Redis that holds login sessions.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_SECRET",
      "service": "Flipt",
      "description": "Client secret of the same GitHub OAuth App.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_PASSWORD",
      "service": "Flipt",
      "description": "Password for the Redis that holds login sessions.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_REDIRECT_ADDRESS",
      "service": "Flipt",
      "description": "Public address GitHub redirects back to after sign-in.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "FLIPT_AUTHENTICATION_METHODS_GITHUB_ALLOWED_ORGANIZATIONS",
      "service": "Flipt",
      "description": "Space-separated GitHub organizations allowed to sign in. Leaving it empty lets any GitHub account in.",
      "secret": false,
      "strategy": "ask_user"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "flipt-v2-envoy-grpc-web"
      }
    },
    "cli": "railway deploy --template flipt-v2-envoy-grpc-web",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "760bd692-ed86-483d-b6f3-1748db72d9d9",
            "serializedConfig": {
              "services": {
                "e685569d-a8e0-4525-82a8-5baf6590d13d": {
                  "icon": "https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg",
                  "name": "Redis",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH\""
                  },
                  "source": {
                    "image": "redis:8.2"
                  },
                  "variables": {
                    "REDISHOST": {
                      "isOptional": false,
                      "description": "Private hostname other services use to reach Redis.",
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "REDISPORT": {
                      "isOptional": false,
                      "description": "Port Redis listens on.",
                      "defaultValue": "6379"
                    },
                    "REDISUSER": {
                      "isOptional": false,
                      "description": "Redis username. This is the default ACL user.",
                      "defaultValue": "default"
                    },
                    "REDIS_URL": {
                      "isOptional": false,
                      "description": "Connection string for connecting to redis using the private network",
                      "defaultValue": "redis://${{ REDISUSER }}:${{ REDIS_PASSWORD }}@${{ REDISHOST }}:${{ REDISPORT }}"
                    },
                    "REDISPASSWORD": {
                      "isOptional": false,
                      "description": "Alias of REDIS_PASSWORD, kept for clients that expect this name.",
                      "defaultValue": "${{REDIS_PASSWORD}}"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Password generated for the Redis default user.",
                      "defaultValue": "{{REDIS_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "e685569d-a8e0-4525-82a8-5baf6590d13d": {
                      "mountPath": "/data"
                    }
                  },
                  "haTemplateCode": "redis-ha"
                },
                "e96ff80b-fd23-49fb-aca6-7d82d04c5dd6": {
                  "name": "Envoy",
                  "deploy": {
                    "healthcheckPath": "/healthz"
                  },
                  "source": {
                    "repo": "agafonovim/railway-templates",
                    "rootDirectory": "/flipt/envoy"
                  },
                  "variables": {
                    "PORT": {
                      "description": "Port Envoy listens on. Railway routes the public domain and the healthcheck to this port.",
                      "defaultValue": "8080"
                    },
                    "FLIPT_UPSTREAM_HOST": {
                      "description": "Private hostname of the Flipt service that Envoy proxies gRPC traffic to.",
                      "defaultValue": "${{Flipt.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "FLIPT_UPSTREAM_PORT": {
                      "description": "Flipt's gRPC port that Envoy proxies to.",
                      "defaultValue": "${{Flipt.FLIPT_SERVER_GRPC_PORT}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                },
                "eb6e41bc-2b17-4dc7-b0d9-fe99885ce040": {
                  "name": "Flipt",
                  "deploy": {
                    "healthcheckPath": "/health"
                  },
                  "source": {
                    "image": "flipt/flipt:v2.11.0"
                  },
                  "variables": {
                    "PORT": {
                      "description": "Port Railway routes the public domain and the healthcheck to. Matches FLIPT_SERVER_HTTP_PORT.",
                      "defaultValue": "${{FLIPT_SERVER_HTTP_PORT}}"
                    },
                    "RAILWAY_RUN_UID": {
                      "description": "Runs the container as root so Flipt can write to the mounted volume. The image's non-root user cannot.",
                      "defaultValue": "0"
                    },
                    "FLIPT_SERVER_HOST": {
                      "description": "Address Flipt binds to. Brackets are required; a bare :: yields an invalid listen address.",
                      "defaultValue": "[::]"
                    },
                    "FLIPT_SERVER_GRPC_PORT": {
                      "description": "Port for Flipt's gRPC API, used by Envoy and by backend services on the private network.",
                      "defaultValue": "9000"
                    },
                    "FLIPT_SERVER_HTTP_PORT": {
                      "description": "Port for Flipt's UI and REST API.",
                      "defaultValue": "8080"
                    },
                    "FLIPT_META_TELEMETRY_ENABLED": {
                      "description": "Whether Flipt reports anonymous usage telemetry to its maintainers.",
                      "defaultValue": "false"
                    },
                    "FLIPT_AUTHENTICATION_REQUIRED": {
                      "description": "Requires credentials for Flipt's API and UI. Evaluation is exempted separately.",
                      "defaultValue": "true"
                    },
                    "FLIPT_ENVIRONMENTS_DEFAULT_NAME": {
                      "description": "Key and display name of the single built-in environment. Clients send this as environment_key.",
                      "defaultValue": "production"
                    },
                    "FLIPT_STORAGE_DEFAULT_BACKEND_PATH": {
                      "description": "Directory holding the Git repository of flag state. Points at the mounted volume.",
                      "defaultValue": "${{RAILWAY_VOLUME_MOUNT_PATH}}"
                    },
                    "FLIPT_STORAGE_DEFAULT_BACKEND_TYPE": {
                      "description": "Storage backend. local keeps flag state on disk; the default, memory, loses it on restart.",
                      "defaultValue": "local"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_DOMAIN": {
                      "description": "Domain the login session cookie is registered on. Required once any login method is enabled.",
                      "defaultValue": "${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_SECURE": {
                      "description": "Marks the login session cookies HTTPS-only.",
                      "defaultValue": "true"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_CSRF_KEY": {
                      "description": "Secret used to sign CSRF tokens during the login flow.",
                      "defaultValue": "{{FLIPT_AUTHENTICATION_SESSION_CSRF_KEY}}"
                    },
                    "FLIPT_AUTHENTICATION_EXCLUDE_EVALUATION": {
                      "description": "Leaves flag evaluation reachable without credentials while the rest of Flipt stays protected.",
                      "defaultValue": "true"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_STORAGE_TYPE": {
                      "description": "Where login sessions are kept. redis survives restarts; memory signs everyone out on redeploy.",
                      "defaultValue": "redis"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_SCOPES": {
                      "description": "OAuth scopes requested from GitHub. read:org is required for the organization check to run.",
                      "defaultValue": "read:org"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_ENABLED": {
                      "description": "Turns on signing in to the Flipt UI with GitHub.",
                      "defaultValue": "true"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_ID": {
                      "description": "Client ID of the GitHub OAuth App. Its callback URL is https://<your-flipt-domain>/auth/v1/method/github/callback.",
                      "defaultValue": "{{FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_ID}}"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_HOST": {
                      "description": "Hostname of the Redis that holds login sessions.",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_MODE": {
                      "description": "Redis topology, single or cluster. Required whenever Redis session storage is used.",
                      "defaultValue": "single"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_PORT": {
                      "description": "Port of the Redis that holds login sessions.",
                      "defaultValue": "${{Redis.REDISPORT}}"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_SECRET": {
                      "description": "Client secret of the same GitHub OAuth App.",
                      "defaultValue": "{{FLIPT_AUTHENTICATION_METHODS_GITHUB_CLIENT_SECRET}}"
                    },
                    "FLIPT_AUTHENTICATION_SESSION_STORAGE_REDIS_PASSWORD": {
                      "description": "Password for the Redis that holds login sessions.",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_REDIRECT_ADDRESS": {
                      "description": "Public address GitHub redirects back to after sign-in.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "FLIPT_AUTHENTICATION_METHODS_GITHUB_ALLOWED_ORGANIZATIONS": {
                      "description": "Space-separated GitHub organizations allowed to sign in. Leaving it empty lets any GitHub account in.",
                      "defaultValue": "{{FLIPT_AUTHENTICATION_METHODS_GITHUB_ALLOWED_ORGANIZATIONS}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  },
                  "volumeMounts": {
                    "eb6e41bc-2b17-4dc7-b0d9-fe99885ce040": {
                      "mountPath": "/var/opt/flipt",
                      "backupSchedules": [
                        "DAILY"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "Envoy",
      "method": "GET",
      "path": "/healthz",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 3,
    "needs_volume": true
  },
  "generated_at": "2026-09-20T16:14:49.616Z",
  "generator_version": "0.1.0"
}
