<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sharing My Experiment To Create Server Side Tracking (sGTM)]]></title><description><![CDATA[<p dir="auto">I just wanna share my experiment to install sGTM on Cloudron.</p>
<p dir="auto">And I think it works well, and I got this code from Claude AI.</p>
<p dir="auto">You can use this CloudronManifest.json and execute it via Cloudron CLI:</p>
<p dir="auto">And my question is how to make the update process automatically from Cloudron dashboard?</p>
<p dir="auto">Thank you.</p>
<pre><code>{
  "id": "com.example.sgtm",
  "title": "Server-side GTM",
  "author": "Admin",
  "description": "Google server-side Tag Manager (sGTM) tagging server, packaged for Cloudron.",
  "tagline": "Self-hosted sGTM tagging server",
  "version": "1.0.4",
  "dockerImage": "gcr.io/cloud-tagging-10302018/gtm-cloud-image@sha256:688d35c6c54473be42d5128befa4d98a722d76d6fdf9cb84d63b52a3f223a1e6",
  "healthCheckPath": "/healthz",
  "httpPort": 8080,
  "manifestVersion": 2,
  "website": "https://services.example.com",
  "contactEmail": "admin@example.com",
  "tags": [
    "analytics",
    "gtm",
    "tracking"
  ],
  "memoryLimit": 1073741824,
  "addons": {
    "localstorage": {}
  }
}
</code></pre>
<p dir="auto">And this is the <a href="http://README.md" target="_blank" rel="noopener noreferrer nofollow ugc">README.md</a>:</p>
<h1>Server-Side GTM (sGTM) on Cloudron — Setup Guide &amp; Best Practices</h1>
<p dir="auto">This guide explains how to run the official Google image <code>gcr.io/cloud-tagging-10302018/gtm-cloud-image</code> as a custom Cloudron app, <strong>directly without building a Dockerfile</strong>. The image is pinned via the <code>dockerImage</code> field in <code>CloudronManifest.json</code> using an immutable <strong>digest</strong> (<code>@sha256:...</code>). There is no Dockerfile, and no build process is required.</p>
<p dir="auto">You will run TWO apps from the same package:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th style="text-align:left">Role</th>
<th style="text-align:left">Domain (REMEMBER!)</th>
<th style="text-align:left">Required Environment Variables</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Serving</strong></td>
<td style="text-align:left"><code>services.example.com</code></td>
<td style="text-align:left"><code>CONTAINER_CONFIG</code> + <code>PREVIEW_SERVER_URL</code> (no <code>RUN_AS_*</code>)</td>
</tr>
<tr>
<td style="text-align:left"><strong>Preview</strong></td>
<td style="text-align:left"><code>service.example.com</code></td>
<td style="text-align:left"><code>CONTAINER_CONFIG</code> + <code>RUN_AS_PREVIEW_SERVER=true</code></td>
</tr>
</tbody>
</table>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=63dea4eef9f" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ Important: Naming Convention (Easy to mix up!)</h3>
<ul>
<li><strong>"services"</strong> (PLURAL, with an 's') = PRODUCTION / Serving -&gt; serves your <code>gtm.js</code></li>
<li><strong>"service"</strong> (SINGULAR) = PREVIEW / Debug</li>
<li><em>Note: The role is strictly determined by the Environment Variables (ENV VAR), not the domain name. If they ever get swapped, check the variables!</em></li>
</ul>
<h3><img src="https://forum.cloudron.io/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=63dea4eef9f" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ Important: Docker Images (A hard-learned lesson!)</h3>
<ul>
<li><strong>DO NOT</strong> use the <code>:stable</code> tag in <code>dockerImage</code>. Cloudron/Docker caches <code>:stable</code> to the old digest. This means an update might report as "successful," but the old version will still be running (e.g., sticking to 4.3.0 instead of 4.4.0). Using <code>--no-cache</code> DOES NOT help here—that's a build-cache flag, not a pull-cache flag, and this setup doesn't use builds anyway.</li>
<li><strong>USE A DIGEST</strong> (<code>@sha256:...</code>). It is immutable and content-addressed, making it impossible to cache incorrectly. Explicit version tags (e.g., <code>:4.4.0</code>) are also safe; only <code>:stable</code> (and <code>:latest</code>) are dangerous because they are mutable.</li>
<li>Since there is no Dockerfile and no build, setting <code>dockerfileName: null</code> in the app config is the correct approach.</li>
</ul>
<h3>The Correct Serving Path: <code>/gtm.js</code> (NOT <code>/load</code>)</h3>
<p dir="auto">The server only serves the default <code>/gtm.js</code> path. Custom paths like <code>/load</code> WILL NOT work (returning a 400/Not Found error). In your GTM "Web Container" client, it doesn't matter if you fill the Tag serving path with <code>/load</code> or leave it empty—it won't affect anything, as the server will always use the default <code>/gtm.js</code>.</p>
<p dir="auto"><strong>The first-party URL used by your site (via GTM4WP):</strong><br />
<code>https://services.example.com/gtm.js?id=GTM-XXXXXXX</code><br />
<em>(The <code>?id=</code> parameter is MANDATORY; without it, you will get an error, which is completely normal).</em></p>
<hr />
<h2>1) Check &amp; Fix Server Roles (If your first-party <code>/gtm.js</code> isn't working)</h2>
<p dir="auto">Check the environment variables for both apps:</p>
<pre><code class="language-bash">cloudron env list --app services.example.com
cloudron env list --app service.example.com
</code></pre>
<p dir="auto"><strong>PRODUCTION (services) MUST HAVE:</strong></p>
<ul>
<li><code>CONTAINER_CONFIG</code> = (your configuration string)</li>
<li><code>PREVIEW_SERVER_URL</code> = <code>https://service.example.com</code></li>
<li><strong>NO</strong> <code>RUN_AS_PREVIEW_SERVER</code> variable</li>
</ul>
<p dir="auto">If your <code>services</code> app was accidentally set as preview, fix it:</p>
<pre><code class="language-bash">cloudron env unset --app services.example.com RUN_AS_PREVIEW_SERVER
cloudron env set   --app services.example.com PREVIEW_SERVER_URL='https://service.example.com'
cloudron restart   --app services.example.com
</code></pre>
<p dir="auto"><strong>PREVIEW (service) MUST HAVE:</strong></p>
<ul>
<li><code>CONTAINER_CONFIG</code> = (your configuration string)</li>
<li><code>RUN_AS_PREVIEW_SERVER</code> = <code>true</code></li>
</ul>
<p dir="auto"><strong>Test it:</strong> Visit <code>https://services.example.com/gtm.js?id=GTM-XXXXXXX</code> -&gt; It should output JavaScript code.</p>
<p dir="auto"><em>NOTE: <code>CONTAINER_CONFIG</code> and sensitive tokens are NOT stored in this repository. Always set them via <code>cloudron env set</code>, keeping them out of Git.</em></p>
<hr />
<h2>2) Updating the Image to the Latest Version</h2>
<p dir="auto">Because the image is pinned via <code>dockerImage</code> (not a Dockerfile build), updating simply means changing the image reference in <code>CloudronManifest.json</code> and deploying. You DO NOT need <code>--no-cache</code>, and there is no Dockerfile to edit.</p>
<p dir="auto"><strong>Steps:</strong></p>
<ol>
<li>
<p dir="auto"><strong>Find the latest version &amp; digest:</strong></p>
<ul>
<li>Go to Google Cloud &gt; Artifact Registry &gt; package <code>gtm-cloud-image</code> (project <code>cloud-tagging-10302018</code>, repo <code>gcr.io</code>), and open the Overview tab.</li>
<li>Look at the Tags: find the latest version (e.g., <code>4.5.0</code>). Copy the "Digest" value (<code>sha256:...</code>) from the version that also holds the <code>stable</code> tag.</li>
<li><em>Alternative:</em> Check Google's server-side release notes for version numbers.</li>
</ul>
</li>
<li>
<p dir="auto"><strong>Edit <code>CloudronManifest.json</code>:</strong></p>
<ul>
<li>Increase the <code>version</code> (e.g., <code>1.0.3</code> -&gt; <code>1.0.4</code>) — MUST be increased with every update.</li>
<li>Change <code>dockerImage</code> to the new digest:<br />
<code>"gcr.io/cloud-tagging-10302018/gtm-cloud-image@sha256:&lt;NEW_DIGEST&gt;"</code><br />
<em>(If you prefer readability, you can use the version tag: <code>...gtm-cloud-image:4.5.0</code>)</em></li>
</ul>
</li>
<li>
<p dir="auto"><strong>Commit &amp; push to your Git repository.</strong></p>
</li>
<li>
<p dir="auto"><strong>Deploy BOTH apps from the repo folder</strong> (from any machine with the Cloudron CLI installed):</p>
<pre><code class="language-bash">git clone https://git.example.com/username/sgtm-cloudron.git   # first time only
cd sgtm-cloudron
git pull                                                       # if already cloned
cloudron update --app services.example.com                     # PRODUCTION
cloudron update --app service.example.com                      # PREVIEW
</code></pre>
<p dir="auto">Cloudron will read the <code>dockerImage</code> from the local manifest and pull that image directly. A different digest equals a different image, guaranteeing a fresh pull.</p>
</li>
</ol>
<p dir="auto"><strong>Quick Alternative without editing the manifest (Ad-hoc):</strong><br />
This is valid but leaves your repo out-of-sync with what's actually running. If you use this, please update your manifest afterward!</p>
<pre><code class="language-bash">cloudron update --app services.example.com --image gcr.io/cloud-tagging-10302018/gtm-cloud-image@sha256:&lt;DIGEST&gt;
cloudron update --app service.example.com  --image gcr.io/cloud-tagging-10302018/gtm-cloud-image@sha256:&lt;DIGEST&gt;
</code></pre>
<p dir="auto"><strong>Verification:</strong></p>
<ul>
<li><code>https://services.example.com/healthz</code> -&gt; Should return <code>OK</code></li>
<li><code>https://services.example.com/gtm.js?id=GTM-XXXXXXX</code> -&gt; Should still return JS code</li>
<li>GTM &gt; Admin &gt; Container Settings -&gt; Version number should increase.
<ul>
<li><em>Note: This number is REPORTED via usage beacons triggered by traffic and can be DELAYED up to 24 hours. The preview server rarely gets traffic, so it reports the slowest, and GTM tends to display the oldest version between the two servers. To confirm quickly without waiting: run Preview mode + send a few new requests from the web container, then check the Console (the outdated version warning should disappear).</em></li>
</ul>
</li>
</ul>
<p dir="auto"><em>Update downtime is just a few seconds and WILL NOT affect your site.</em></p>
<hr />
<h2>3) Update Cadence (Security)</h2>
<p dir="auto">The image consists of Node.js + libraries. Google releases periodic security patches. Because this is self-hosted, keeping it updated is your responsibility.</p>
<ul>
<li>Update quarterly.</li>
<li>Update when a version warning appears in the GTM Console.</li>
<li>Update when a major release drops.<br />
Just repeat the steps in <strong>Section 2</strong>.</li>
</ul>
<p dir="auto"><em>Note: The <code>enableAutomaticUpdate</code> feature in Cloudron DOES NOT pull new Google versions on its own—it's only for package versions we publish. Google version updates are always manual via Section 2.</em></p>
<hr />
<h2>4) Files in this Repository</h2>
<ul>
<li><code>CloudronManifest.json</code>: App metadata + pinned image via <code>dockerImage</code> (digest). This is the <strong>SOURCE OF TRUTH</strong> for the running version.</li>
<li><code>README.md</code>: This file.</li>
</ul>
]]></description><link>https://forum.cloudron.io/topic/15825/sharing-my-experiment-to-create-server-side-tracking-sgtm</link><generator>RSS for Node</generator><lastBuildDate>Mon, 24 Aug 2026 03:44:33 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/15825.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 12 Aug 2026 02:28:13 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Sharing My Experiment To Create Server Side Tracking (sGTM) on Wed, 12 Aug 2026 06:16:05 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/inibudi" aria-label="Profile: IniBudi">@<bdi>IniBudi</bdi></a> <a href="/post/128059">said</a>:</p>
<p dir="auto">And my question is how to make the update process automatically from Cloudron dashboard?</p>
</blockquote>
<p dir="auto">Do you mean you want Cloudron to track upstream releases and make new packages and have an update available? If so, there is no such feature. An idea is to automate this in your CI (Cloudron team uses renovate for it's packages).</p>
]]></description><link>https://forum.cloudron.io/post/128062</link><guid isPermaLink="true">https://forum.cloudron.io/post/128062</guid><dc:creator><![CDATA[joseph]]></dc:creator><pubDate>Wed, 12 Aug 2026 06:16:05 GMT</pubDate></item></channel></rss>