1"use strict";(self.webpackChunkgatsby_starter_default=self.webpackChunkgatsby_starter_default||[]).push([[944],{67526:function(e,t,a){a.r(t),a.d(t,{Head:function(){return m},default:function(){return g}});var n=a(28453),l=a(96540);function s(e){const t=Object.assign({h1:"h1",a:"a",span:"span",p:"p",h2:"h2",ul:"ul",li:"li",h3:"h3",em:"em"},(0,n.R)(),e.components);return l.createElement(l.Fragment,null,l.createElement(t.h1,{id:"thruster-http2-proxy-on-control-plane",style:{position:"relative"}},l.createElement(t.a,{href:"#thruster-http2-proxy-on-control-plane","aria-label":"thruster http2 proxy on control plane permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Thruster HTTP/2 Proxy on Control Plane"),"\n",l.createElement(t.p,null,l.createElement(t.a,{href:"https://github.com/basecamp/thruster"},"Thruster")," is Basecamp's zero-config HTTP/2 proxy for\nRuby web applications. It provides HTTP/2 support, asset caching, compression, and early\nhints. Running it on Control Plane requires settings that differ from a standalone (e.g.,\nVPS) deployment, and getting them wrong produces a confusing ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">502 Bad Gateway</code>'}}),' with a\n"protocol error" message.'),"\n",l.createElement(t.p,null,"This page documents the configuration that works."),"\n",l.createElement(t.h2,{id:"tldr",style:{position:"relative"}},l.createElement(t.a,{href:"#tldr","aria-label":"tldr permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"TL;DR"),"\n",l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"Workload port: ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http</code>'}})," (not ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">http2</code>'}}),")."),"\n",l.createElement(t.li,null,"Dockerfile ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">CMD</code>'}})," runs Thruster: ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">CMD ["bundle", "exec", "thrust", "bin/rails", "server"]</code>'}}),"."),"\n",l.createElement(t.li,null,"End users still get HTTP/2; Control Plane's load balancer handles TLS termination."),"\n"),"\n",l.createElement(t.h2,{id:"why-protocol-http-and-not-http2",style:{position:"relative"}},l.createElement(t.a,{href:"#why-protocol-http-and-not-http2","aria-label":"why protocol http and not http2 permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Why ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http</code>'}}
1)," and not ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">http2</code>'}})),"\n",l.createElement(t.h3,{id:"standalone-thruster-eg-vps",style:{position:"relative"}},l.createElement(t.a,{href:"#standalone-thruster-eg-vps","aria-label":"standalone thruster eg vps permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Standalone Thruster (e.g., VPS)"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">User â HTTPS/HTTP2 â Thruster â HTTP/1.1 â Rails\n (Thruster handles TLS + HTTP/2)</code></pre></div>'}}),"\n",l.createElement(t.h3,{id:"control-plane--thruster",style:{position:"relative"}},l.createElement(t.a,{href:"#control-plane--thruster","aria-label":"control plane thruster permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Control Plane + Thruster"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">User â HTTPS/HTTP2 â Control Plane LB â HTTP/1.1 â Thruster â HTTP/1.1 â Rails\n (LB handles TLS) (protocol: http) (caching, compression)</code></pre></div>'}}),"\n",l.createElement(t.p,null,"In the diagram above, ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http</code>'}})," is the workload port setting that governs the\nLBâThruster hop; ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">caching, compression</code>'}})," describes what Thruster contributes in this\npath."),"\n",l.createElement(t.p,null,"On Control Plane, the load balancer terminates TLS and speaks HTTP/2 to the browser â\nso Thruster never sees TLS or HTTP/2 on its incoming side. This is the opposite of a\nstandalone (VPS) deployment, where Thruster itself handles TLS and HTTP/2. Setting\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http2</code>'}})," on the workload port tells the load balancer to expect HTTP/2 from\nthe container, which Thruster does not emit on that hop, and protocol negotiation fails\nwith ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">502 Bad Gateway</code>'}}),"."),"\n",l.createElement(t.p,null,"Even with ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http</code>'}}),", end users still get:"),"\n",l.createElement(t.ul,null,"\n",l.createElement(t.li,null,"HTTP/2 to the browser (from the Control Plane load balancer)"),"\n",l.createElement(t.li,null,"HTTP/2 multiplexing (from the Control Plane load balancer)"),"\n",l.createElement(t.li,null,"Asset caching and compression (from Thruster)"),"\n",l.createElement(t.li,null,"Efficient static file serving (from Thruster)"),"\n",l.createElement(t.li,null,"Early Hints (103) from Thruster (reaches the browser only if the load balancer forwards 103 responses)"),"\n"),"\n",l.createElement(t.h2,{id:"workload-template",style:{position:"relative"}}
1,l.createElement(t.a,{href:"#workload-template","aria-label":"workload template permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Workload template"),"\n",l.createElement(t.p,null,"In ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">.controlplane/templates/rails.yml</code>'}}),":"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">ports</span><span class="token punctuation">:</span>\n <span class="token punctuation">-</span> <span class="token key atrule">number</span><span class="token punctuation">:</span> <span class="token number">3000</span>\n <span class="token key atrule">protocol</span><span class="token punctuation">:</span> http <span class="token comment"># Required when fronting Rails with Thruster. Do not use http2.</span></code></pre></div>'}}),"\n",l.createElement(t.h2,{id:"dockerfile",style:{position:"relative"}},l.createElement(t.a,{href:"#dockerfile","aria-label":"dockerfile permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Dockerfile"),"\n",l.createElement(t.p,null,"The container's ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">CMD</code>'}})," must launch Thruster. On Control Plane/Kubernetes the Dockerfile\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">CMD</code>'}})," determines container startup â the ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">Procfile</code>'}})," is not used (unlike Heroku)."),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="dockerfile"><pre class="language-dockerfile"><code class="language-dockerfile"><span class="token comment"># .controlplane/Dockerfile</span>\n<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"bundle"</span>, <span class="token string">"exec"</span>, <span class="token string">"thrust"</span>, <span class="token string">"bin/rails"</span>, <span class="token string">"server"</span>]</span></code></pre></div>'}}),"\n",l.createElement(t.h2,{id:"troubleshooting",style:{position:"relative"}},l.createElement(t.a,{href:"#troubleshooting","aria-label":"troubleshooting permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Troubleshooting"),"\n",l.createElement(t.h3,{id:"502-bad-gateway-with-protocol-error",style:{position:"relative"}},l.createElement(t.a,{href:"#502-bad-gateway-with-protocol-error","aria-label":"502 bad gateway with protocol error permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">502 Bad Gateway</code>'}}),' with "protocol error"'),"\n",l.createElement(t.p,null,"The workload port is set to ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http2</code>'}}),". Change it to ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">protocol: http</code>'}})," in\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">
1rails.yml</code>'}}),", then push the workload spec."),"\n",l.createElement(t.p,null,l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cpflow apply-template</code>'}})," rewrites the workload from the template. If you have tuned\nCPU, memory, autoscaling, firewall, or other workload fields directly in the\nControl Plane UI (or via ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cpln</code>'}}),") without mirroring those changes back into\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">rails.yml</code>'}}),", those edits will be reset. Either reconcile ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">rails.yml</code>'}})," with the live\nspec first, or change the port field in place:"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="sh"><pre class="language-sh"><code class="language-sh"><span class="token comment"># Option A â apply the full template (resets any drift between rails.yml and the live spec):</span>\ncpflow apply-template rails <span class="token parameter variable">-a</span> <span class="token operator"><</span>app<span class="token operator">></span>\n\n<span class="token comment"># Option B â edit only the port protocol in place (preserves UI-tuned fields):</span>\ncpln workload edit <span class="token operator"><</span>workload<span class="token operator">></span> <span class="token parameter variable">--gvc</span> <span class="token operator"><</span>gvc<span class="token operator">></span> <span class="token parameter variable">--org</span> <span class="token operator"><</span>org<span class="token operator">></span>\n<span class="token comment"># change spec.containers[].ports[].protocol from http2 to http</span></code></pre></div>'}}),"\n",l.createElement(t.p,null,"Inspect the current spec before choosing if you're unsure what would change:"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="sh"><pre class="language-sh"><code class="language-sh">cpln workload get <span class="token operator"><</span>workload<span class="token operator">></span> <span class="token parameter variable">--gvc</span> <span class="token operator"><</span>gvc<span class="token operator">></span> <span class="token parameter variable">--org</span> <span class="token operator"><</span>org<span class="token operator">></span> <span class="token parameter variable">-o</span> yaml</code></pre></div>'}}),"\n",l.createElement(t.p,null,"Note: ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cpflow deploy-image</code>'}})," alone is not sufficient â it only updates the container\nimage reference and does not modify the workload's port configuration. Run it\n",l.createElement(t.em,null,"after")," the protocol change has been applied if you also want to ship a new image."),"\n",l.createElement(t.p,null,"The remaining troubleshooting commands use the raw Control Plane CLI (",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cpln</code>'}}),") rather\nthan ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cpflow</code>'}}),"; see\n",l.createElement(t.a,{href:"https://shakadocs.controlplane.com/quickstart/quick-start-3-cli#getting-started-with-the-cli"},"the Control Plane CLI quickstart"),"\nif you don't already have it installed."),"\n",l.createElement(t.h3,{id:"verify-thruster-is-the-process-running-as-pid-1",style:{position:"relative"}},l.createElement(t.a,{href:"#verify-thruster-is-the-process-running-as-pid-1","aria-label":"verify thruster is the process running as pid 1 permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Verify Thruster is the process running as PID 1"),"\n",l.createElement(t.p,null,l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">/proc/1/cmdline</code>'}})," stores arguments NUL-separated with no trailing newline, so pipe it\nthrough ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">tr</code>'}})," to make the output readable:"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="sh"><pre class="language-sh"><code class="language-sh">cpln workload <span class="token builtin class-name">exec</span> <span class="token operator"><</span>
1workload<span class="token operator">></span> <span class="token parameter variable">--gvc</span> <span class="token operator"><</span>gvc<span class="token operator">></span> <span class="token parameter variable">--org</span> <span class="token operator"><</span>org<span class="token operator">></span> <span class="token parameter variable">--location</span> <span class="token operator"><</span>location<span class="token operator">></span> <span class="token punctuation">\\</span>\n -- <span class="token function">sh</span> <span class="token parameter variable">-c</span> <span class="token string">"tr \'<span class="token entity" title="\\0">\\0</span>\' \' \' < /proc/1/cmdline && echo"</span></code></pre></div>'}}),"\n",l.createElement(t.p,null,"You should see ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">thrust</code>'}})," in the output. If you see ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">rails</code>'}})," or ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">puma</code>'}})," directly, the\nDockerfile ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">CMD</code>'}})," is not invoking Thruster."),"\n",l.createElement(t.h3,{id:"test-http-connectivity-through-thruster",style:{position:"relative"}},l.createElement(t.a,{href:"#test-http-connectivity-through-thruster","aria-label":"test http connectivity through thruster permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Test HTTP connectivity through Thruster"),"\n",l.createElement(t.p,null,"This hits Thruster on port 3000 â not Rails directly. A ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">200 OK</code>'}})," confirms the\nThruster â Rails path within the container is healthy."),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="sh"><pre class="language-sh"><code class="language-sh">cpln workload <span class="token builtin class-name">exec</span> <span class="token operator"><</span>workload<span class="token operator">></span> <span class="token parameter variable">--gvc</span> <span class="token operator"><</span>gvc<span class="token operator">></span> <span class="token parameter variable">--org</span> <span class="token operator"><</span>org<span class="token operator">></span> <span class="token parameter variable">--location</span> <span class="token operator"><</span>location<span class="token operator">></span> <span class="token punctuation">\\</span>\n -- <span class="token function">curl</span> <span class="token parameter variable">-s</span> localhost:3000</code></pre></div>'}}),"\n",l.createElement(t.h3,{id:"inspect-the-workload-port-configuration",style:{position:"relative"}},l.createElement(t.a,{href:"#inspect-the-workload-port-configuration","aria-label":"inspect the workload port configuration permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}}
1)),"Inspect the workload port configuration"),"\n",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="sh"><pre class="language-sh"><code class="language-sh">cpln workload get <span class="token operator"><</span>workload<span class="token operator">></span> <span class="token parameter variable">--gvc</span> <span class="token operator"><</span>gvc<span class="token operator">></span> <span class="token parameter variable">--org</span> <span class="token operator"><</span>org<span class="token operator">></span> <span class="token parameter variable">-o</span> json <span class="token operator">|</span> jq <span class="token string">\'.spec.containers[].ports\'</span></code></pre></div>'}}),"\n",l.createElement(t.h2,{id:"reference-implementation",style:{position:"relative"}},l.createElement(t.a,{href:"#reference-implementation","aria-label":"reference implementation permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Reference implementation"),"\n",l.createElement(t.p,null,"A working setup lives in the\n",l.createElement(t.a,{href:"https://github.com/shakacode/react-webpack-rails-tutorial"},"react-webpack-rails-tutorial"),"\nrepository â see\n",l.createElement(t.a,{href:"https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/templates/rails.yml"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">.controlplane/templates/rails.yml</code>'}})),"\non the ",l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">master</code>'}})," branch."),"\n",l.createElement(t.h2,{id:"further-reading",style:{position:"relative"}},l.createElement(t.a,{href:"#further-reading","aria-label":"further reading permalink",className:"anchor before"},l.createElement(t.span,{dangerouslySetInnerHTML:{__html:'<svg aria-hidden="true" height="20" version="1.1" viewBox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>'}})),"Further reading"),"\n",l.createElement(t.ul,null,"\n",l.createElement(t.li,null,l.createElement(t.a,{href:"https://github.com/basecamp/thruster"},"Thruster on GitHub")),"\n",l.createElement(t.li,null,l.createElement(t.a,{href:"https://world.hey.com/dhh/rails-8-with-thruster-by-default-c953f5e3"},"DHH on Rails 8 with Thruster")),"\n"))}var r=function(e){void 0===e&&(e={});const{wrapper:t}=Object.assign({},(0,n.R)(),e.components);return t?l.createElement(t,e,l.createElement(s,e)):s(e)},o=a(63679),c=a(95197),i=a(47388),p=a(23690),h=a(14487);const d=o.default.p.withConfig({displayName:"doc-article__RedirectFallback",componentId:"sc-tic2w5-0"})(["padding:2rem;"]),u=e=>{let{data:t,location:a,children:n}=e;const{headings:s}=t.article.childMdx,r=(0,c.X9)(a.pathname),[o,p]=l.useState(null),u=a.pathname.split("/"),g=u.indexOf("docs"),m=-1===g?a.pathname.length:u.slice(0,g+1).join("/").length,v=a.pathname.slice(0,m),k=a.pathname.slice(m+1).replace(/\/$/,"").split("/").filter((e=>""!==e)),f=k.length>1?k.slice(0,-1).join("/"):"";l.useEffect((()=>{if(!r)return;const{hash:e}=window.location;p(e);const t=""+r+e;window.location.href!==t&&window.location.replace(t)}),[r]);const y=null===r||null===o?null:""+r+o;return l.createElement(l.Fragment,null,null!==y?l.createElement(d,{role:"status","aria-live":"polite"},"Redirecting..."," ",l.createElement("a",{href:y,target:"_blank",rel:"noopener noreferrer"},"Click here if not redirected.")):l.createElement(i.A,{main:l.createElement(h.A,{body:n,headings:s,transformUrl:e=>{if(e.startsWith("http")||e.startsWith("#"))return e;const t=e.replace(/\.md$/,"/");
1if(t.startsWith("./"))return v+(""===f?"":"/"+f)+t.slice(1);if(t.startsWith("../")){if(""===f)return""+v+t.slice(2);const e=f.split("/").slice(0,-1).join("/");return v+(""===e?"":"/"+e)+t.slice(2)}return v+"/"+(""===f?"":f+"/")+t}})}))};function g(e){return l.createElement(u,e,l.createElement(r,e))}const m=e=>{let{data:t,location:a,pageContext:n}=e;const{headings:s}=t.article.childMdx,{siteUrl:r}=t.site.siteMetadata,{repoDisplayName:o}=n,i=s.find((e=>1===e.depth)),h=(0,c.X9)(a.pathname)||""+r.replace(/\/+$/,"")+a.pathname;return l.createElement(p.A,{title:i?i.value:o,description:i?i.value:o+" documentation",isArticle:!0,canonical:h,pathname:a.pathname})}}}]); 2//# sourceMappingURL=component---src-template-doc-article-tsx-content-file-path-cache-gatsby-source-git-control-plane-flow-docs-thruster-md-6325bb0115edf9f07a34.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.