<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>DockYARP</title><link>https://gcelet.github.io/DockYARP/</link><description>Recent content on DockYARP</description><generator>Hugo</generator><language>en-US</language><atom:link href="https://gcelet.github.io/DockYARP/index.xml" rel="self" type="application/rss+xml"/><item><title>Getting started</title><link>https://gcelet.github.io/DockYARP/docs/getting-started/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/getting-started/</guid><description>&lt;h2 id="run-the-proxy"&gt;Run the proxy&lt;/h2&gt;
&lt;p&gt;DockYARP watches the Docker socket and routes to containers based on their labels. Its runtime image is
non-root, so it cannot open &lt;code&gt;/var/run/docker.sock&lt;/code&gt; directly — it reaches the Docker API through a read-only
&lt;a href="https://github.com/Tecnativa/docker-socket-proxy"&gt;socket proxy&lt;/a&gt; instead:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockerproxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tecnativa/docker-socket-proxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;CONTAINERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockyarp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/gcelet/dockyarp &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# or dockyarp:local for a local build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;80:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;443:8443&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__Enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__DockerEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tcp://dockerproxy:2375&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;certs:/certs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;dockerproxy]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;certs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The admin API and dashboard are off by default (&lt;code&gt;AdminApi:Surface: Disabled&lt;/code&gt;) — see
&lt;a href="https://gcelet.github.io/DockYARP/docs/examples/#dedicated-admin-host-with-its-own-https-certificate"&gt;Examples&lt;/a&gt; to turn them on.&lt;/p&gt;</description></item><item><title>Configuration</title><link>https://gcelet.github.io/DockYARP/docs/configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/configuration/</guid><description>&lt;p&gt;DockYARP is configured two ways: &lt;strong&gt;container configuration&lt;/strong&gt; (per backend, nginx-proxy compatible) and
&lt;strong&gt;application configuration&lt;/strong&gt; (the proxy&amp;rsquo;s own settings). For what these settings &lt;em&gt;do&lt;/em&gt; at runtime, see
&lt;a href="../features/"&gt;Features&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="container-configuration-labels-or-environment-variables"&gt;Container configuration (labels or environment variables)&lt;/h2&gt;
&lt;p&gt;Every key below can be set as a &lt;strong&gt;container label&lt;/strong&gt; &lt;em&gt;or&lt;/em&gt; as an &lt;strong&gt;environment variable&lt;/strong&gt; on the same container.
When a key is set both ways, the &lt;strong&gt;environment variable wins&lt;/strong&gt; — environment variables are nginx-proxy&amp;rsquo;s
canonical channel and the label is the fallback. The &lt;code&gt;VIRTUAL_*&lt;/code&gt;, &lt;code&gt;LETSENCRYPT_*&lt;/code&gt;, &lt;code&gt;CERT_NAME&lt;/code&gt;, &lt;code&gt;SSL_POLICY&lt;/code&gt;,
&lt;code&gt;HTTPS_METHOD&lt;/code&gt;, &lt;code&gt;HSTS&lt;/code&gt;, &lt;code&gt;NETWORK_ACCESS&lt;/code&gt;, &lt;code&gt;SERVER_TOKENS&lt;/code&gt;, and &lt;code&gt;EXTERNAL_HTTPS_PORT&lt;/code&gt; keys are nginx-proxy
compatible; DockYARP&amp;rsquo;s own keys use the &lt;code&gt;DOCKYARP_&lt;/code&gt; prefix.&lt;/p&gt;</description></item><item><title>Features</title><link>https://gcelet.github.io/DockYARP/docs/features/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/features/</guid><description>&lt;p&gt;DockYARP&amp;rsquo;s runtime behavior, feature by feature. See &lt;a href="../configuration/"&gt;Configuration&lt;/a&gt; for the labels,
environment variables, and application settings referenced here.&lt;/p&gt;
&lt;h2 id="discovery"&gt;Discovery&lt;/h2&gt;
&lt;p&gt;DockYARP watches the Docker daemon and builds its routes from each container&amp;rsquo;s labels/environment variables,
reconciling live as containers start and stop.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Health-aware&lt;/strong&gt;: a container failing its Docker health check is excluded, so healthy replicas keep serving.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network selection&lt;/strong&gt;: on multi-network setups, &lt;code&gt;Docker:PreferredNetwork&lt;/code&gt; picks the backend address;
&lt;code&gt;Docker:ProxyNetworks&lt;/code&gt; restricts selection to a network the proxy shares (reachable), and &lt;code&gt;Docker:HostAddress&lt;/code&gt;
reaches host-network backends (which have no container IP).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPv6&lt;/strong&gt;: the edge listens dual-stack by default (IPv6 &lt;strong&gt;and&lt;/strong&gt; IPv4 clients are served — no toggle needed, unlike
nginx-proxy&amp;rsquo;s opt-in &lt;code&gt;ENABLE_IPV6&lt;/code&gt;). Set &lt;code&gt;Docker:PreferIpv6&lt;/code&gt; to forward to a backend&amp;rsquo;s IPv6 address when it has one
(nginx-proxy &lt;code&gt;PREFER_IPV6_NETWORK&lt;/code&gt;); a single family is used per backend, so there are no duplicate endpoints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filtering&lt;/strong&gt;: &lt;code&gt;Docker:ContainerFilters&lt;/code&gt; scopes discovery with Docker-native filters (for example, only
containers labelled &lt;code&gt;dockyarp.enable=true&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="routing--load-balancing"&gt;Routing &amp;amp; load balancing&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Matching&lt;/strong&gt;: requests route by &lt;code&gt;Host&lt;/code&gt; (and an optional path prefix). An exact host beats a wildcard
(&lt;code&gt;*.example.com&lt;/code&gt;); &lt;code&gt;DOCKYARP_PRIORITY&lt;/code&gt; orders same-host routes (higher wins).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiport&lt;/strong&gt;: &lt;code&gt;VIRTUAL_HOST_MULTIPORTS&lt;/code&gt; maps host → path → port on a single container.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path rewrite&lt;/strong&gt;: &lt;code&gt;VIRTUAL_DEST=/&lt;/code&gt; strips the &lt;code&gt;VIRTUAL_PATH&lt;/code&gt; prefix before forwarding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regex paths&lt;/strong&gt;: a &lt;code&gt;~&lt;/code&gt;-prefixed &lt;code&gt;VIRTUAL_PATH&lt;/code&gt; (for example &lt;code&gt;~^/(app1|alt1)/&lt;/code&gt;) matches by regular expression; a
prefix path beats a regex path, and &lt;code&gt;VIRTUAL_DEST&lt;/code&gt; does not apply to a regex path.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replicas &amp;amp; policy&lt;/strong&gt;: containers sharing a &lt;code&gt;VIRTUAL_HOST&lt;/code&gt; form one cluster; &lt;code&gt;DOCKYARP_LB&lt;/code&gt; selects the
load-balancing policy — &lt;code&gt;round-robin&lt;/code&gt; (default), &lt;code&gt;least-requests&lt;/code&gt;, &lt;code&gt;power-of-two-choices&lt;/code&gt;, &lt;code&gt;random&lt;/code&gt;, or
&lt;code&gt;first-alphabetical&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Default host &amp;amp; fallback&lt;/strong&gt;: &lt;code&gt;Routing:DefaultHost&lt;/code&gt; catches unknown hosts; otherwise an unmatched request gets
&lt;code&gt;Routing:DefaultResponseStatusCode&lt;/code&gt; (404 by default), or an optional redirect via &lt;code&gt;Routing:DefaultResponseLocation&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tls--acme"&gt;TLS &amp;amp; ACME&lt;/h2&gt;
&lt;p&gt;DockYARP terminates TLS and can obtain certificates automatically.&lt;/p&gt;</description></item><item><title>Examples</title><link>https://gcelet.github.io/DockYARP/docs/examples/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/examples/</guid><description>&lt;p&gt;Task-oriented recipes. Each builds on the &lt;strong&gt;base stack&lt;/strong&gt; below and uses real labels/environment variables — see
&lt;a href="../configuration/"&gt;Configuration&lt;/a&gt; for every key and &lt;a href="../features/"&gt;Features&lt;/a&gt; for the behavior.&lt;/p&gt;
&lt;h2 id="base-stack"&gt;Base stack&lt;/h2&gt;
&lt;p&gt;DockYARP&amp;rsquo;s runtime image is non-root and cannot open &lt;code&gt;/var/run/docker.sock&lt;/code&gt; directly — a read-only Docker
socket proxy is &lt;strong&gt;required&lt;/strong&gt;, not optional hardening, for it to reach the Docker API at all. Add the backend
services from the recipes below to this &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockerproxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tecnativa/docker-socket-proxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;CONTAINERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockyarp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/gcelet/dockyarp &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# or dockyarp:local for a local build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;80:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;443:8443&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__Enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__DockerEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tcp://dockerproxy:2375&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;certs:/certs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./config:/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;dockerproxy]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;certs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The admin API and dashboard are off by default (&lt;code&gt;AdminApi:Surface: Disabled&lt;/code&gt;) — see
&lt;a href="https://gcelet.github.io/DockYARP/docs/examples/#dedicated-admin-host-with-its-own-https-certificate"&gt;Dedicated admin host&lt;/a&gt; below to turn them on.&lt;/p&gt;</description></item><item><title>Migrating from nginx-proxy</title><link>https://gcelet.github.io/DockYARP/docs/migrating-from-nginx-proxy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/migrating-from-nginx-proxy/</guid><description>&lt;p&gt;DockYARP is built as an nginx-proxy equivalent — most of what an nginx-proxy operator already knows carries
over directly. This page covers two migration paths and, separately, the two things operators worry about most:
your existing certificates, and being able to roll back if something goes wrong. For the exhaustive
feature-by-feature comparison, see the &lt;a href="https://github.com/gcelet/DockYARP/blob/develop/openspec/backlog/parity.md"&gt;parity matrix&lt;/a&gt; in the
repository rather than this page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Either path&lt;/strong&gt;: only the nginx-proxy stack itself is replaced. Every backend service keeps its existing
&lt;code&gt;VIRTUAL_HOST&lt;/code&gt;/&lt;code&gt;LETSENCRYPT_HOST&lt;/code&gt;-style labels or environment variables unchanged — DockYARP reads the same
keys (see &lt;a href="../configuration/"&gt;Configuration&lt;/a&gt;) — so no other stack&amp;rsquo;s configuration needs to change.&lt;/p&gt;</description></item><item><title>Architecture</title><link>https://gcelet.github.io/DockYARP/docs/architecture/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/architecture/</guid><description>&lt;p&gt;DockYARP is a .NET application built on &lt;strong&gt;YARP&lt;/strong&gt; (reverse proxy) and &lt;strong&gt;Kestrel&lt;/strong&gt; (web server), using
&lt;strong&gt;Docker.DotNet&lt;/strong&gt; for discovery and &lt;strong&gt;ACME&lt;/strong&gt; for certificates.&lt;/p&gt;
&lt;h2 id="flow"&gt;Flow&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Discovery&lt;/strong&gt; watches the Docker daemon (initial listing + event stream) and produces a normalized view of
the running containers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mapping&lt;/strong&gt; turns labelled containers into a routing model (routes + clusters), applying precedence, health
awareness, and reachability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;YARP&lt;/strong&gt; is driven from that model: routes and clusters are updated live as containers change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS/ACME&lt;/strong&gt; provisions and renews certificates for hosts that declare them; Kestrel selects the right
certificate per SNI host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security middleware&lt;/strong&gt; applies HTTPS enforcement, HSTS, headers, access control, and auth.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="modules"&gt;Modules&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Project&lt;/th&gt;
					&lt;th&gt;Responsibility&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.Core&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Domain models, interfaces, stores (leaf project).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.Docker&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Docker discovery + label mapping.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.Tls&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;ACME + certificates.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.Security&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;HTTPS enforcement, auth, access control.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.AdminApi&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Admin / observability endpoints.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;DockYarp.App&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;ASP.NET host: YARP, DI, pipeline.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="design-principle"&gt;Design principle&lt;/h2&gt;
&lt;p&gt;Reverse-proxy behavior is built on &lt;strong&gt;YARP extension points&lt;/strong&gt; (match policies, transforms, dynamic config) and
web-server behavior on &lt;strong&gt;Kestrel / ASP.NET Core&lt;/strong&gt; — DockYARP does not reimplement a proxy layer on top of them.&lt;/p&gt;</description></item><item><title>Deployment</title><link>https://gcelet.github.io/DockYARP/docs/deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/deployment/</guid><description>&lt;h2 id="docker-compose"&gt;Docker Compose&lt;/h2&gt;
&lt;p&gt;DockYARP&amp;rsquo;s runtime image is non-root and cannot open &lt;code&gt;/var/run/docker.sock&lt;/code&gt; directly — it reaches the Docker API
through a read-only &lt;a href="https://github.com/Tecnativa/docker-socket-proxy"&gt;socket proxy&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockerproxy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tecnativa/docker-socket-proxy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;CONTAINERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockyarp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/gcelet/dockyarp &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# or dockyarp:local for a local build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;80:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;443:8443&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__Enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;Docker__DockerEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tcp://dockerproxy:2375&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;dockyarp-certs:/certs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;dockerproxy]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;web&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;VIRTUAL_HOST=app.example.io&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;VIRTUAL_PORT=8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;LETSENCRYPT_HOST=app.example.io&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;LETSENCRYPT_EMAIL=admin@example.io&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dockyarp-certs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="notes"&gt;Notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Only the socket proxy mounts &lt;code&gt;/var/run/docker.sock&lt;/code&gt;, and read-only (&lt;code&gt;:ro&lt;/code&gt;); DockYARP itself never touches it.&lt;/li&gt;
&lt;li&gt;Persist the certificate directory (here &lt;code&gt;/certs&lt;/code&gt;) so ACME certificates survive restarts.&lt;/li&gt;
&lt;li&gt;Publish host ports &lt;strong&gt;80&lt;/strong&gt; and &lt;strong&gt;443&lt;/strong&gt; onto the container&amp;rsquo;s &lt;strong&gt;8080&lt;/strong&gt;/&lt;strong&gt;8443&lt;/strong&gt; (its non-root defaults); port 80
also serves the ACME HTTP-01 challenge and HTTP→HTTPS redirects.&lt;/li&gt;
&lt;li&gt;Scope discovery on busy hosts with &lt;code&gt;Docker:ContainerFilters&lt;/code&gt; (e.g. only containers carrying a given label).&lt;/li&gt;
&lt;li&gt;The admin API and dashboard are off by default (&lt;code&gt;AdminApi:Surface: Disabled&lt;/code&gt;) — see
&lt;a href="https://gcelet.github.io/DockYARP/docs/examples/#dedicated-admin-host-with-its-own-https-certificate"&gt;Examples&lt;/a&gt; to turn them on behind a
dedicated host.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Reachability, host-network backends, and multi-network setups are covered under
&lt;a href="https://gcelet.github.io/DockYARP/docs/configuration/"&gt;Configuration&lt;/a&gt; (&lt;code&gt;Docker:ProxyNetworks&lt;/code&gt;, &lt;code&gt;Docker:HostAddress&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Contributing</title><link>https://gcelet.github.io/DockYARP/docs/contributing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/contributing/</guid><description>&lt;p&gt;DockYARP is developed &lt;strong&gt;spec-first&lt;/strong&gt; with &lt;a href="https://github.com/Fission-AI/OpenSpec"&gt;OpenSpec&lt;/a&gt;. Every change —
feature, fix, or refinement — follows the same loop.&lt;/p&gt;
&lt;h2 id="environment-setup"&gt;Environment setup&lt;/h2&gt;
&lt;p&gt;Required for any contribution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet/10.0"&gt;.NET 10 SDK&lt;/a&gt;&lt;/strong&gt; — or skip installing it: &lt;code&gt;build.ps1&lt;/code&gt; /
&lt;code&gt;build.sh&lt;/code&gt; (Fallout) fetch the SDK pinned by &lt;code&gt;global.json&lt;/code&gt; automatically if it&amp;rsquo;s missing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt;&lt;/strong&gt; — needed to run the &lt;strong&gt;OpenSpec CLI&lt;/strong&gt;
(&lt;code&gt;npx @fission-ai/openspec@latest&lt;/code&gt;), the tool every change goes through (propose / apply / archive). This repo
has no other Node dependency outside the docs site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://git-scm.com/"&gt;git&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;&lt;/strong&gt; — only required for &lt;code&gt;./build.ps1 E2E&lt;/code&gt;. The unit/integration gate
(&lt;code&gt;./build.ps1 Test&lt;/code&gt;) needs none.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="using-claude-code"&gt;Using Claude Code&lt;/h3&gt;
&lt;p&gt;Optional, on top of the above — not a second toolchain. The checked-in &lt;code&gt;.mcp.json&lt;/code&gt; (git / microsoft-docs /
docker / aspire MCP servers) auto-enables via &lt;code&gt;.claude/settings.json&lt;/code&gt;, and &lt;code&gt;.claude/commands/opsx/*&lt;/code&gt; +
&lt;code&gt;.claude/skills/openspec-*&lt;/code&gt; wire the &lt;code&gt;/opsx:*&lt;/code&gt; slash commands to the OpenSpec CLI above. None of this is
required to contribute — the OpenSpec CLI works standalone from any editor or agent.&lt;/p&gt;</description></item><item><title>Releasing</title><link>https://gcelet.github.io/DockYARP/docs/releasing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://gcelet.github.io/DockYARP/docs/releasing/</guid><description>&lt;p&gt;Cutting a release is a small number of manual, &lt;a href="https://gitversion.net/"&gt;GitVersion&lt;/a&gt;-informed steps. Once the
tag is pushed, everything else — changelog, GitHub Release, image publish — runs automatically.&lt;/p&gt;
&lt;h2 id="first-release-only"&gt;First release only&lt;/h2&gt;
&lt;p&gt;DockYARP develops &lt;a href="https://gitversion.net/docs/learn/branching-strategies/gitflow"&gt;GitFlow&lt;/a&gt;-style: pre-1.0,
work happens directly on &lt;code&gt;develop&lt;/code&gt;, and &lt;code&gt;main&lt;/code&gt; does not exist yet. &lt;code&gt;main&lt;/code&gt; is created &lt;strong&gt;once&lt;/strong&gt;, at the first
release:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout develop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git pull
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout -b main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push -u origin main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From then on, &lt;code&gt;main&lt;/code&gt; exists permanently and this step is never repeated.&lt;/p&gt;</description></item></channel></rss>