<?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[Zettabitt]]></title><description><![CDATA[Selective filtllering and remixing of my world feed. Linux &amp; FOSS, ZFS and, well zfs-on-wsl, technology &amp; techno (detroit), science &amp; fiction &amp; ]]></description><link>https://zettabitt.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 10:59:45 GMT</lastBuildDate><atom:link href="https://zettabitt.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[SilverBullet: Cloud-run Deployment (Recipe by Gemini)   [Update with concise guide]]]></title><description><![CDATA[After much research, of PKRs/KMS’s, Zettelkasten, Obsidian, Logseq, Notion, Roam Research, books on Taking Smart Notes, How to Take Effective Notes, and looking at many diagrams and templates, I installed the Obsidian App decided to self-host SilverB...]]></description><link>https://zettabitt.com/silverbullet-cloud-run-deployment-recipe-by-gemini-update-with-concise-guide</link><guid isPermaLink="true">https://zettabitt.com/silverbullet-cloud-run-deployment-recipe-by-gemini-update-with-concise-guide</guid><category><![CDATA[Cloud]]></category><category><![CDATA[zettelkasten]]></category><category><![CDATA[secondbrain]]></category><category><![CDATA[obsidian]]></category><category><![CDATA[silverbullet]]></category><category><![CDATA[deployment]]></category><category><![CDATA[gemini]]></category><category><![CDATA[GCP]]></category><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Sat, 24 May 2025 02:54:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748075647746/595157a2-c3ff-41fa-bf35-e5493608cff1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After much research, of PKRs/KMS’s, Zettelkasten, Obsidian, Logseq, Notion, Roam Research, books on Taking Smart Notes, How to Take Effective Notes, and looking at many diagrams and templates, I <s>installed the Obsidian App</s> decided to self-host SilverBullet…</p>
<blockquote>
<p>SilverBullet is an open source <strong>personal productivity platform</strong> built on <a target="_blank" href="https://silverbullet.md/Markdown">Markdown</a>, turbo charged with the scripting power of <a target="_blank" href="https://silverbullet.md/Space%20Lua">Lua</a>. You <a target="_blank" href="https://silverbullet.md/Install">self host</a> it on your server, access it via any modern browser on any device (desktop, laptop, mobile). Since SilverBullet is built as a <a target="_blank" href="https://silverbullet.md/Local%20First">Local First</a> <a target="_blank" href="https://silverbullet.md/PWA">PWA</a>, it is fully offline capable. Temporarily don’t have network access? No problem, SilverBullet will sync your content when you get back online.</p>
</blockquote>
<p>Offline capable also means, if paying for a cloud service, it can be spun down when you are accessing your notes, saving money compared to a traditional, hire a cloud VM to deploy a Docker Container. I asked Geminia 2.5 Free for advise , which I am about to follow!</p>
<hr />
<h2 id="heading-so-gemini-its-more-than-just-docker-pull-ghcriosilverbulletmdsilverbulletlatesthttpghcriosilverbulletmdsilverbulletlatest-i-take-it">So Gemini, its more than just `docker pull <a target="_blank" href="http://ghcr.io/silverbulletmd/silverbullet:latest">ghcr.io/silverbulletmd/silverbullet:latest</a>` I take it?</h2>
<p><strong>Make me a play-by-play plan please!</strong></p>
<blockquote>
<p>You're right, deploying to Cloud Run is more than just a <code>docker pull</code>! It involves setting up your Google Cloud project, configuring persistent storage, and then deploying your container. It's a fantastic learning opportunity, and I'll walk you through a detailed play-by-play plan.</p>
</blockquote>
<h3 id="heading-play-by-play-plan-silverbullet-on-google-cloud-run"><strong>Play-by-Play Plan: SilverBullet on Google Cloud Run</strong></h3>
<p><strong>Goal:</strong> Deploy SilverBullet from GHCR to Google Cloud Run, with persistent storage in Google Cloud Storage, while staying within the free tier as much as possible.</p>
<p><strong>Assumptions:</strong></p>
<ul>
<li><p>You have a Google Cloud account and have enabled billing (you won't be charged unless you exceed the free tier).</p>
</li>
<li><p>You're comfortable with basic command-line operations (or willing to learn).</p>
</li>
<li><p>You have the <code>gcloud</code> CLI installed and authenticated (if not, install and configure it: <code>gcloud init</code>).</p>
</li>
</ul>
<p>This plan is divided into three main phases: <strong>Setup Google Cloud Resources</strong>, <strong>Deploy SilverBullet</strong>, and <strong>Manage &amp; Monitor</strong>.</p>
<hr />
<h3 id="heading-phase-1-setup-google-cloud-resources-one-time-setup"><strong>Phase 1: Setup Google Cloud Resources (One-Time Setup)</strong></h3>
<p><strong>1. Set Your Google Cloud Project</strong></p>
<ul>
<li><p><strong>Action:</strong> If you haven't already, select or create a Google Cloud project. All your resources will live within this project.</p>
<ul>
<li><p><strong>Via Console:</strong> Go to the Google Cloud Console (<a target="_blank" href="https://console.cloud.google.com/">console.cloud.google.com</a>), click on the project dropdown at the top, and select "New Project" or an existing one.</p>
</li>
<li><p>**Via <code>gcloud</code> CLI:**Bash</p>
<pre><code class="lang-plaintext">  gcloud projects list # List your projects
  gcloud config set project YOUR_PROJECT_ID # Set your current project
</code></pre>
<p>  (Replace <code>YOUR_PROJECT_ID</code> with the actual ID you choose or see in the console.)</p>
</li>
</ul>
</li>
</ul>
<p><strong>2. Create a Google Cloud Storage (GCS) Bucket for Notes</strong></p>
<p>SilverBullet needs a place to store your Markdown files persistently. Cloud Run instances are ephemeral. GCS is the ideal, free-tier-friendly solution.</p>
<ul>
<li><p><strong>Action:</strong> Create a GCS bucket.</p>
<ul>
<li><p><strong>Via Console:</strong></p>
<ol>
<li><p>Go to <strong>Cloud Storage &gt; Buckets</strong> in the Google Cloud Console.</p>
</li>
<li><p>Click <strong>"CREATE BUCKET"</strong>.</p>
</li>
<li><p><strong>Name your bucket:</strong> Choose a globally unique name (e.g., <code>silverbullet-notes-YOUR-UNIQUE-SUFFIX</code>).</p>
</li>
<li><p><strong>Choose a region:</strong> Select a "Region" (not "Multi-region" or "Dual-region") for cost-effectiveness and to align with the free tier (e.g., <code>us-central1</code>, <code>us-east1</code>, or <code>us-west1</code>).</p>
</li>
<li><p><strong>Choose a storage class:</strong> Select <strong>Standard</strong> for balanced performance and cost.</p>
</li>
<li><p><strong>Access Control:</strong> Keep "Uniform" for simpler permissions.</p>
</li>
<li><p>Click <strong>"CREATE"</strong>.</p>
</li>
</ol>
</li>
<li><p>**Via <code>gcloud</code> CLI:**Bash</p>
<pre><code class="lang-plaintext">  gcloud storage buckets create gs://silverbullet-notes-YOUR-UNIQUE-SUFFIX --project=YOUR_PROJECT_ID --location=us-central1 --uniform-bucket-level-access
</code></pre>
<p>  (Replace <code>YOUR_UNIQUE_SUFFIX</code> and <code>YOUR_PROJECT_ID</code>. Choose a region from <code>us-central1</code>, <code>us-east1</code>, or <code>us-west1</code> for free tier eligibility.)</p>
</li>
</ul>
</li>
</ul>
<p><strong>3. Grant Permissions to Your Cloud Run Service Account</strong></p>
<p>Your Cloud Run service will need permission to read and write to your GCS bucket. Cloud Run services run as a default service account (or one you specify).</p>
<ul>
<li><p><strong>Action:</strong> Grant the "Storage Object Admin" role to your Cloud Run service account on your GCS bucket.</p>
<ul>
<li><p><strong>Identify Cloud Run Service Account:</strong></p>
<ul>
<li><p>The default Compute Engine service account is usually <code>YOUR_PROJECT_NUMBER-compute@developer.gserviceaccount.com</code>. You can find your project number in the Google Cloud Console Dashboard.</p>
</li>
<li><p>Alternatively, when you deploy a Cloud Run service for the first time, it creates a service account like <code>YOUR_PROJECT_ID@appspot.gserviceaccount.com</code> or <code>SERVICE_NAME@YOUR_PROJECT_ID.iam.gserviceaccount.com</code>. You can verify this in <strong>IAM &amp; Admin &gt; Service Accounts</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Grant Role (Recommended via Console for simplicity):</strong></p>
<ol>
<li><p>Go to <strong>Cloud Storage &gt; Buckets</strong>.</p>
</li>
<li><p>Click on your <code>silverbullet-notes-YOUR-UNIQUE-SUFFIX</code> bucket.</p>
</li>
<li><p>Go to the <strong>PERMISSIONS</strong> tab.</p>
</li>
<li><p>Click <strong>"GRANT ACCESS"</strong>.</p>
</li>
<li><p>In "New principals," paste your Cloud Run service account email.</p>
</li>
<li><p>In "Select a role," search for <code>Storage Object Admin</code> and select it.</p>
</li>
<li><p>Click <strong>"SAVE"</strong>.</p>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-phase-2-deploy-silverbullet-to-cloud-run"><strong>Phase 2: Deploy SilverBullet to Cloud Run</strong></h3>
<p>This is where you bring the SilverBullet Docker image to life on Cloud Run.</p>
<p><strong>Learning Objective:</strong> Understand Cloud Run deployment process, environment variables, and how to use Cloud Storage as a volume mount.</p>
<p><strong>1. Determine SilverBullet's Storage Configuration</strong></p>
<p>SilverBullet's Docker image typically uses environment variables to configure its storage backend. The documentation for SilverBullet (check the "Install/Configuration" section on their website) shows that it uses <code>SB_FOLDER</code> to specify the local path where notes are stored.</p>
<p>When using Cloud Storage volume mounts in Cloud Run, the bucket will appear as a regular filesystem path inside the container. So, you'll likely need to set <code>SB_FOLDER</code> to that mount path.</p>
<ul>
<li><strong>Crucial step:</strong> While the original SilverBullet documentation states "Right now the only supported backend is to use your local disk," Google Cloud Run's "Cloud Storage FUSE" feature <em>makes</em> a GCS bucket <em>appear</em> as a local disk. This is the key. The path you define as your volume mount will be the <code>SB_FOLDER</code>.</li>
</ul>
<p><strong>2. Deploy SilverBullet to Cloud Run</strong></p>
<p>You'll use the <code>gcloud run deploy</code> command.</p>
<ul>
<li><p><strong>Action:</strong> Deploy the SilverBullet Docker image.</p>
<ul>
<li><p><strong>Via</strong> <code>gcloud</code> CLI (Recommended for initial deployment):</p>
<p>  Bash</p>
<pre><code class="lang-plaintext">  gcloud run deploy silverbullet-notes \
    --image docker.io/zefhemel/silverbullet:latest \
    --region us-central1 \
    --platform managed \
    --allow-unauthenticated \
    --min-instances 0 \
    --max-instances 1 \
    --cpu 0.5 \
    --memory 512Mi \
    --add-volume name=silverbullet-storage,type=cloud-storage,bucket=silverbullet-notes-YOUR-UNIQUE-SUFFIX \
    --add-volume-mount volume=silverbullet-storage,mount-path=/space \
    --set-env-vars SB_FOLDER=/space,SB_USER=your_username:your_password
</code></pre>
<p>  <strong>Let's break down this command:</strong></p>
<ul>
<li><p><code>gcloud run deploy silverbullet-notes</code>: Deploys a new Cloud Run service named <code>silverbullet-notes</code>.</p>
</li>
<li><p><code>--image docker.io/zefhemel/silverbullet:latest</code>: Specifies the Docker image to use from Docker Hub (GCP tier 1 provider, ghcr requires more providisonas Tier 2)</p>
</li>
<li><p><code>--region us-central1</code>: Choose a region close to you, preferably one of the US free tier regions (<code>us-central1</code>, <code>us-east1</code>, <code>us-west1</code>).</p>
</li>
<li><p><code>--platform managed</code>: Specifies that you're using the fully managed Cloud Run platform.</p>
</li>
<li><p><code>--allow-unauthenticated</code>: Makes your SilverBullet instance publicly accessible on the internet. <strong>IMPORTANT:</strong> SilverBullet has built-in user authentication. <strong>Do not skip the</strong> <code>SB_USER</code> environment variable for security. For a personal app, this is acceptable. If you need stricter access, you'd integrate with Identity-Aware Proxy (IAP), which adds complexity and may incur more costs.</p>
</li>
<li><p><code>--min-instances 0</code>: <strong>Crucial for free tier!</strong> This tells Cloud Run to scale down to zero instances when there's no traffic, so you don't pay for idle time.</p>
</li>
<li><p><code>--max-instances 1</code>: Limits the maximum number of instances. For personal use, one is enough.</p>
</li>
<li><p><code>--cpu 0.5 --memory 512Mi</code>: AllocThis detailed plan should get your SilverBullet personal knowledge base up and running on Google Cloud Run, leveraging the free tier effectively. Good luck, and enjoy your decentralized note-taking! This comprehensive plan should empower you to successfully deploy and manage your personal SilverBullet knowledge base on Google Cloud Run, making it accessible from anywhere while keeping costs in check. Enjoy your journey into Zettelkasten with SilverBullet!</p>
<p>  Thanks Gemini! Lets see how it goes. Follow me for further updates.ates 0.5 vCPU and 512 MiB of memory. This is a reasonable starting point for SilverBullet and helps stay within the free tier.</p>
</li>
<li><p><code>--add-volume name=silverbullet-storage,type=cloud-storage,bucket=silverbullet-notes-YOUR-UNIQUE-SUFFIX</code>: This is the magic! It creates a volume named <code>silverbullet-storage</code> that is backed by your GCS bucket. Replace <code>silverbullet-notes-YOUR-UNIQUE-SUFFIX</code> with your actual bucket name.</p>
</li>
<li><p><code>--add-volume-mount volume=silverbullet-storage,mount-path=/space</code>: Mounts the <code>silverbullet-storage</code> volume inside your container at the <code>/space</code> path. This means anything SilverBullet writes to <code>/space</code> will be stored in your GCS bucket.</p>
</li>
<li><p><code>--set-env-vars SB_FOLDER=/space,SB_USER=your_username:your_password</code>:</p>
<ul>
<li><p><code>SB_FOLDER=/space</code>: Tells SilverBullet to use the mounted GCS bucket (which appears as <code>/space</code> inside the container) as its storage location.</p>
</li>
<li><p><code>SB_USER=your_username:your_password</code>: <strong>This is critical for security.</strong> Replace <code>your_username</code> and <code>your_password</code> with strong, unique credentials. This provides basic authentication for your SilverBullet instance.</p>
</li>
</ul>
</li>
<li><p><strong>Important Note on</strong> <code>--set-env-vars</code> for <code>SB_USER</code>: Environment variables for secrets are generally discouraged for production. However, for a personal, free-tier focused project where you're already allowing unauthenticated access to the Cloud Run endpoint (relying on SilverBullet's internal auth), this is a common and acceptable compromise. For more robust secret management in a real production scenario, you'd use Google Secret Manager and integrate it with your Cloud Run service.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>    <strong>3. Wait for Deployment and Get URL</strong></p>
<ul>
<li><p><strong>Action:</strong> Monitor the deployment.</p>
<ul>
<li><p>The <code>gcloud run deploy</code> command will show progress and, upon success, provide the URL of your deployed service.</p>
</li>
<li><p>In the console, you'll see the service status. Once it's green, the URL will be visible.</p>
</li>
</ul>
</li>
</ul>
<p><strong>4. Access SilverBullet</strong>Troubleshooting (Common Issues)</p>
<p>"Service Unavailable" / "Error 500":</p>
<p>Check Cloud Run logs: In the Cloud Run console, click on your service, then go to the "Logs" tab. This is your first stop for debugging. Look for errors during startup or requests.</p>
<p>Check environment variables: Ensure SB_FOLDER is set correctly to /space and SB_USER has valid credentials.</p>
<p>Check GCS bucket permissions: Is your Cloud Run service account able to access the GCS bucket? Go to the GCS bucket's permissions and verify the Storage Object Admin role.</p>
<p>Notes not saving: Likely a GCS permission issue or incorrect SB_FOLDER setting.</p>
<p>Exceeding Free Tier: Check your billing reports. The common culprits are:</p>
<p>Not scaling to zero: Ensure --min-instances 0 is set.</p>
<p>Large GCS usage: If you're storing many large f</p>
<ul>
<li><p>This detailed plan should get your SilverBullet personal knowledge base up and running on Google Cloud Run, leveraging the free tier effectively. Good luck, and enjoy your decentralized note-taking! This comprehensive plan should empower you to successfully deploy and manage your personal SilverBullet knowledge base on Google Cloud Run, making it accessible from anywhere while keeping costs in check. Enjoy your journey into Zettelkasten with SilverBullet!</p>
<p>  Thanks Gemini! Lets see how it goes. Follow me for further updates.<strong>Action:</strong> Open the provided URL in your web browser.</p>
<ul>
<li><p>You should be prompted for the username and password you set with <code>SB_USER</code>.</p>
</li>
<li><p>Log in, and you'll see your SilverBullet instance! Start creating notes.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-phase-3-manage-amp-monitor-ongoing"><strong>Phase 3: Manage &amp; Monitor (Ongoing)</strong></h3>
<p><strong>1. Verify Persistent Storage</strong></p>
<ul>
<li><p><strong>Action:</strong> Create a test note in SilverBullet.</p>
</li>
<li><p><strong>Action:</strong> Go to your GCS bucket (<code>silverbullet-notes-YOUR-UNIQUE-SUFFIX</code>) in the Google Cloud Console.</p>
</li>
<li><p><strong>Verification:</strong> You should see your Markdown files (and any other SilverBullet-generated files like <code>.silverbullet.db</code>) appearing in the bucket's file list. This confirms your storage is persistent.</p>
</li>
</ul>
<p><strong>2. Monitor Usage and Billing</strong></p>
<ul>
<li><p><strong>Action:</strong> Regularly check your Google Cloud Billing page.</p>
<ul>
<li><p>Go to <strong>Billing</strong> in the Google Cloud Console.</p>
</li>
<li><p>Under "Reports," you can filter by product (Cloud Run, Cloud Storage) to see your usage.</p>
</li>
<li><p>Set up <strong>Budget Alerts</strong> to notify you if your spending approaches a certain threshold (e.g., $1-$5) to avoid surprises. This is highly recommended.</p>
<ol>
<li><p>In the Billing section, go to <strong>Budgets &amp; alerts</strong>.</p>
</li>
<li><p>Click <strong>"CREATE BUDGET"</strong>.</p>
</li>
<li><p>Name your budget, set a target amount (e.g., $5), and select "All products" or specifically "Cloud Run" and "Cloud Storage."</p>
</li>
<li><p>Configure alerts to notify you at different percentages of your budget.</p>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<p><strong>3. Updating SilverBullet</strong></p>
<p>If SilverBullet releases a new version, you'll want to update your Cloud Run service.</p>
<ul>
<li><p><strong>Action:</strong> Redeploy with the new image tag.</p>
<ul>
<li><p>You can simply run the same <code>gcloud run deploy</code> command as before, but change <code>ghcr.io/silverbulletmd/silverbullet:latest</code> to <code>ghcr.io/silverbulletmd/silverbullet:NEW_VERSION_TAG</code> (e.g., <code>:0.9.0</code>).</p>
</li>
<li><p>Cloud Run handles zero-downtime deployments, so your old version will keep serving until the new one is ready.</p>
</li>
</ul>
</li>
</ul>
<p><strong>4. Troubleshooting (Common Issues)</strong></p>
<ul>
<li><p><strong>"Service Unavailable" / "Error 500"</strong>:</p>
<ul>
<li><p>Check Cloud Run logs: In the Cloud Run console, click on your service, then go to the "Logs" tab. This is your first stop for debugging. Look for errors during startup or requests.</p>
</li>
<li><p>Check environment variables: Ensure <code>SB_FOLDER</code> is set correctly to <code>/space</code> and <code>SB_USER</code> has valid credentials.</p>
</li>
<li><p>Check GCS bucket permissions: Is your Cloud Run service account able to access the GCS bucket? Go to the GCS bucket's permissions and verify the <code>Storage Object Admin</code> role.</p>
</li>
</ul>
</li>
<li><p><strong>Notes not saving:</strong> Likely a GCS permission issue or incorrect <code>SB_FOLDER</code> setting.</p>
</li>
<li><p>UPDATE - WORKING<strong>Exceeding Free Tier:</strong> Check your billing reports. The common culprits are:</p>
<ul>
<li><p><strong>Not scaling to zero:</strong> Ensure <code>--min-instances 0</code> is set.</p>
</li>
<li><p><strong>Large GCS usage:</strong> If you're storing many large files or constantly rewriting files in GCS, you might exceed the 5GB free tier or operations limits.</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-update-my-peronal-silverbullet-is-in-the-cloud">UPDATE - My peronal SilverBullet is in the Cloud!</h2>
<h3 id="heading-google-cloud-run-for-silverbullet-abbreviated-community-guide"><strong>Google Cloud Run for SilverBullet: Abbreviated Community Guide</strong></h3>
<p><strong>I. Provision Storage</strong></p>
<ul>
<li><p><strong>Console GUI:</strong></p>
<ol>
<li><p>Go to <strong>Cloud Storage &gt; Buckets</strong>.</p>
</li>
<li><p>Click <strong>"CREATE BUCKET"</strong>.</p>
</li>
<li><p><strong>Name:</strong> <code>bucket-for-mynotes-app</code> (or your unique name).</p>
</li>
<li><p><strong>Region:</strong> <code>us-central1</code> (or <code>us-east1</code>, <code>us-west1</code>).</p>
</li>
<li><p><strong>Storage Class:</strong> Standard. <strong>Access Control:</strong> Uniform.</p>
</li>
<li><p>Click <strong>"CREATE"</strong>.</p>
</li>
<li><p>Go to the created bucket's <strong>PERMISSIONS</strong> tab.</p>
</li>
<li><p>Click <strong>"GRANT ACCESS"</strong>.</p>
</li>
<li><p><strong>New principals:</strong> Enter your Cloud Run service account email (e.g., <a target="_blank" href="mailto:YOUR_PROJECT_NUMBER-compute@developer.gserviceaccount.com"><code>YOUR_PROJECT_NUMBER-compute@developer.gserviceaccount.com</code></a>).</p>
</li>
<li><p><strong>Role:</strong> <code>Storage Object Admin</code>.</p>
</li>
<li><p>Click <strong>"SAVE"</strong>.</p>
</li>
</ol>
</li>
<li><p><strong>Cloud Shell CLI:</strong></p>
<p>  Bash</p>
<pre><code class="lang-plaintext">  # Create GCS bucket
  gcloud storage buckets create gs://bucket-for-mynotes-app \
    --project=silverbullet-notes-app \
    --location=us-central1 \
    --uniform-bucket-level-access

  # Grant permissions to Cloud Run service account (replace YOUR_PROJECT_NUMBER)
  gcloud storage buckets add-iam-policy-binding gs://bucket-for-mynotes-app \
    --member="serviceAccount:YOUR_PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
    --role="roles/storage.objectAdmin" \
    --project=silverbullet-notes-app
</code></pre>
</li>
</ul>
<p><strong>II. Deploy Image &amp; Service</strong></p>
<ul>
<li><p><strong>Cloud Shell CLI (Recommended for initial setup with volume mounts and env vars):</strong></p>
<p>  Bash</p>
<pre><code class="lang-plaintext">  # Enable Cloud Run API (if not already enabled)
  gcloud services enable run.googleapis.com

  # Deploy SilverBullet service
  gcloud run deploy silverbullet-notes \
    --image docker.io/zefhemel/silverbullet:latest \
    --project=silverbullet-notes-app \
    --region us-central1 \
    --platform managed \
    --allow-unauthenticated \
    --min-instances 0 \
    --max-instances 1 \
    --cpu 1 \
    --memory 512Mi \
    --add-volume name=silverbullet-data,type=cloud-storage,bucket=bucket-for-mynotes-app \
    --add-volume-mount volume=silverbullet-data,mount-path=/space \
    --set-env-vars SB_FOLDER=/space,SB_USER=your_username:your_password \
    --port 3000
</code></pre>
<p>  <em>Replace</em> <code>your_username:your_password</code> with your actual SilverBullet credentials.</p>
</li>
<li><p><strong>Console GUI:</strong></p>
<ol>
<li><p>Go to <strong>Cloud Run &gt; Services</strong>.</p>
</li>
<li><p>Click <strong>"CREATE SERVICE"</strong>.</p>
</li>
<li><p><strong>Container image URL:</strong> <a target="_blank" href="http://docker.io/zefhemel/silverbullet:latest"><code>docker.io/zefhemel/silverbullet:latest</code></a>.</p>
</li>
<li><p><strong>Service name:</strong> <code>silverbullet-notes</code>.</p>
</li>
<li><p><strong>Region:</strong> <code>us-central1</code>.</p>
</li>
<li><p><strong>Authentication:</strong> "Allow unauthenticated invocations".</p>
</li>
<li><p>Expand <strong>"Container(s), volumes, networking, security"</strong>.</p>
</li>
<li><p><strong>Container tab:</strong> CPU: <code>1</code> vCPU, Memory: <code>512</code> MiB. Min instances: <code>0</code>, Max instances: <code>1</code>. Container port: <code>3000</code>.</p>
</li>
<li><p><strong>Volumes tab:</strong> Add Cloud Storage bucket volume (<code>silverbullet-data</code> -&gt; <code>bucket-for-mynotes-app</code>). Add Volume Mount (<code>silverbullet-data</code> -&gt; <code>/space</code>).</p>
</li>
<li><p><strong>Variables &amp; Secrets tab:</strong> Add <code>SB_FOLDER</code>\=<code>/space</code> and <code>SB_USER</code>\=<code>your_username:your_password</code>.</p>
</li>
<li><p>Click <strong>"CREATE"</strong>.</p>
</li>
</ol>
</li>
</ul>
<p><strong>III. Monitor Usage &amp; Costs</strong></p>
<ul>
<li><p><strong>Console GUI:</strong></p>
<ol>
<li><p>Go to <strong>Billing &gt; Reports</strong>. Filter by Cloud Run and Cloud Storage.</p>
</li>
<li><p>Go to <strong>Billing &gt; Budgets &amp; alerts</strong>.</p>
</li>
<li><p>Click <strong>"CREATE BUDGET"</strong>. Set a low budget (e.g., $5) and alert thresholds for "All products".</p>
</li>
</ol>
</li>
</ul>
<p><strong>IV. Maintain Service &amp; Image</strong></p>
<ul>
<li><p><strong>Change or Upgrade Image Version (Redeploy):</strong></p>
<ul>
<li><p>**Cloud Shell CLI:**Bash</p>
<pre><code class="lang-plaintext">  gcloud run deploy silverbullet-notes \
    --image docker.io/zefhemel/silverbullet:[NEW_VERSION_TAG_OR_LATEST] \
    --project=silverbullet-notes-app \
    --region us-central1 \
    --platform managed \
    --allow-unauthenticated \
    --min-instances 0 \
    --max-instances 1 \
    --cpu 1 \
    --memory 512Mi \
    --add-volume name=silverbullet-data,type=cloud-storage,bucket=bucket-for-mynotes-app \
    --add-volume-mount volume=silverbullet-data,mount-path=/space \
    --set-env-vars SB_FOLDER=/space,SB_USER=mike:t1nkerB3ll3! \
    --port 3000
</code></pre>
<p>  <em>Replace</em> <code>[NEW_VERSION_TAG_OR_LATEST]</code> with the specific version or <code>latest</code>.</p>
</li>
<li><p><strong>Console GUI:</strong></p>
<ol>
<li><p>Go to <strong>Cloud Run &gt; Services</strong>. Click <code>silverbullet-notes</code>.</p>
</li>
<li><p>Click <strong>"Edit &amp; Deploy new revision"</strong>.</p>
</li>
<li><p>Update <strong>"Container image URL"</strong> with the new tag.</p>
</li>
<li><p>Click <strong>"Deploy"</strong>.</p>
</li>
</ol>
</li>
</ul>
</li>
<li><p><strong>Manually Stop Service (Delete Service Endpoint):</strong></p>
<ul>
<li><p>**Cloud Shell CLI:**Bash</p>
<pre><code class="lang-plaintext">  gcloud run services delete silverbullet-notes \
    --region us-central1 \
    --project silverbullet-notes-app \
    --quiet
</code></pre>
</li>
<li><p><strong>Console GUI:</strong></p>
<ol>
<li><p>Go to <strong>Cloud Run &gt; Services</strong>.</p>
</li>
<li><p>Check the box next to <code>silverbullet-notes</code>.</p>
</li>
<li><p>Click <strong>"DELETE"</strong> at the top.</p>
</li>
<li><p>Confirm deletion. <em>(Note: Deleting the service endpoint does NOT delete your GCS bucket or its data.)</em></p>
</li>
</ol>
</li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-useful-gcloud-cloud-shell-cli-commands-for-exploration">Useful <code>gcloud</code> Cloud Shell CLI Commands for Exploration</h3>
<p>Bash</p>
<pre><code class="lang-plaintext"># General help for gcloud commands
gcloud COMMAND --help

# List your GCP projects
gcloud projects list

# Set the current project for subsequent commands (replace NAME)
gcloud config set project silverbullet-notes-app

# List your Cloud Storage buckets
gcloud storage buckets list

# List your Cloud Run services
gcloud run services list --region=us-central1 # Specify region

# List service accounts in your project
gcloud iam service-accounts list --project=silverbullet-notes-app

# Get details about a specific Cloud Run service
gcloud run services describe silverbullet-notes --region=us-central1
</code></pre>
<hr />
<p><strong>Gemini 2.5 (free) on Cloud run free-tier</strong><br /><em>Checked and confirmed by human, 2025.05.24</em></p>
<hr />
<h3 id="heading-google-cloud-run-free-tier-for-silverbullet">Google Cloud Run Free Tier for SilverBullet</h3>
<p>Cloud Run’s free tier is designed for low-usage applications and offers the following monthly allowances:</p>
<ul>
<li><p><strong>CPU Usage:</strong> First 180,000 vCPU-seconds per month.</p>
</li>
<li><p><strong>Memory Usage:</strong> First 360,000 GiB-seconds per month.</p>
</li>
<li><p><strong>Requests:</strong> First 2 million requests per month.</p>
</li>
<li><p><strong>Networking (Egress):</strong> First 1 GB of outbound data transfer from North America per month.</p>
</li>
</ul>
<p><strong>How this applies to SilverBullet:</strong></p>
<ul>
<li><p><strong>Pay-per-use:</strong> The key advantage of Cloud Run is that when your SilverBullet instance isn’t actively being used (i.e., you’re not accessing it), it scales down to zero instances, and you don’t pay for idle time. This is critical for keeping costs low.</p>
</li>
<li><p><strong>CPU and Memory:</strong> SilverBullet is a lightweight application, so it likely won’t consume a lot of CPU or memory unless you’re constantly accessing it or performing heavy operations. For typical personal use (a few hours a day, occasional queries), you should easily stay within the free tier limits for CPU and memory.</p>
</li>
<li><p><strong>Requests:</strong> 2 million requests per month is a huge allowance for a personal knowledge base. Each time you load a page, save a note, or run a query, it counts as a request. Unless you have extremely frequent automated processes or share it with a massive audience, you’ll stay well within this limit.</p>
</li>
<li><p><strong>Networking (Egress):</strong> This is the data transfer out of Google Cloud. For a personal note-taking app, your egress will mostly be the text and any images you embed. 1 GB is generally sufficient for personal use. If you store many large images or frequently sync a massive local space, you might start to approach this limit.</p>
</li>
</ul>
<p><strong>Potential Cost Factors to Watch Out For:</strong></p>
<ul>
<li><p><strong>Persistent Storage:</strong> SilverBullet stores its data as Markdown files. Cloud Run itself is stateless, meaning any data stored directly on the container instance will be lost when the instance scales down or is redeployed. To persist your notes, you’ll need a separate storage solution.</p>
<ul>
<li><p><strong>Cloud Storage:</strong> This is the most common and cost-effective option for file storage on Google Cloud. The free tier for Cloud Storage offers <strong>5 GB-months of Standard Storage</strong> (in US regions), 5,000 Class A operations, and 50,000 Class B operations, and 100 GB of outbound data transfer from North America. This is usually plenty for personal notes. SilverBullet could be configured to use a Google Cloud Storage bucket for its “space” (where the Markdown files live).</p>
</li>
<li><p><strong>Cloud SQL (or other databases):</strong> While SilverBullet doesn’t use a traditional relational database, if you were to consider other applications in the future that do, Cloud SQL would be a significant cost. The free tier for Cloud SQL is very limited.</p>
</li>
</ul>
</li>
<li><p><strong>Continuous Usage:</strong> If you were to configure Cloud Run to <em>never</em> scale down to zero (e.g., for very low latency access at all times), you would incur continuous charges for CPU and memory, which would quickly exceed the free tier. For a personal app, this is generally not necessary as SilverBullet’s “Local First PWA” design allows for offline use and synchronization.</p>
</li>
<li><p><strong>Tier 2 Regions:</strong> Google Cloud regions are divided into pricing tiers. Tier 1 regions (like some in the US and Europe) are generally cheaper. If you deploy to a Tier 2 region (e.g., some in South America or Asia), costs beyond the free tier would be higher.</p>
</li>
<li><p><strong>Serverless VPC Access:</strong> If you need to connect your Cloud Run service to resources within a Virtual Private Cloud (VPC), there might be additional compute charges for the Serverless VPC Access connector. For a basic SilverBullet setup, this is unlikely to be needed.</p>
</li>
</ul>
<h3 id="heading-prerequisites-for-deployment">Prerequisites for Deployment</h3>
<ol>
<li><p><strong>Google Cloud Account:</strong> If you don’t have one, sign up for a Google Cloud account. New customers often get a $300 free credit, which is a great buffer while you get started.</p>
</li>
<li><p><strong>Enable Billing:</strong> Even for free tier services, you need to enable billing on your Google Cloud project. This allows Google to track your usage and apply the free tier credits automatically. You won’t be charged unless you exceed the free tier.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Hashing Files on the Windows Command Line]]></title><description><![CDATA[Part of my modular PowerShell setup series and the ongoing saga of lost awesome software tools.


🧰 The Setup
If you’ve ever right-clicked a file in Windows expecting a “Generate Hash” option only to find... nothing — you’re not alone. I used to hav...]]></description><link>https://zettabitt.com/hashing-files-on-the-windows-command-line</link><guid isPermaLink="true">https://zettabitt.com/hashing-files-on-the-windows-command-line</guid><category><![CDATA[Powershell]]></category><category><![CDATA[cmd]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[Windows]]></category><category><![CDATA[profile]]></category><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Thu, 22 May 2025 05:01:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747891651681/54768d1a-300f-45f3-9b11-bff905676fa9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<blockquote>
<p><em>Part of my modular PowerShell setup series and the ongoing saga of lost awesome software tools.</em></p>
</blockquote>
<hr />
<h3 id="heading-the-setup">🧰 The Setup</h3>
<p>If you’ve ever right-clicked a file in Windows expecting a “Generate Hash” option only to find... nothing — you’re not alone. I used to have a perfect little portable tool with shell integration for hashing. But one day, it vanished from my <code>C:\Portables</code> directory. Instead of chasing it down, I found myself diving back into old-school command-line tools and realized a lot can still be done with built-ins like <code>certutil</code>.</p>
<p>This post is about:</p>
<ul>
<li><p>Wrapping a simple hashing utility in PowerShell</p>
</li>
<li><p>Understanding how and why hashing works</p>
</li>
<li><p>Kicking off a few side quests around crypto, profiles, and home-labbing</p>
</li>
</ul>
<hr />
<h3 id="heading-the-classic-cmd-one-liner">⚙️ The Classic CMD One-liner</h3>
<pre><code class="lang-plaintext">echo|set /p="foobar" &gt; %TMP%\hash.txt | certutil -hashfile %TMP%\hash.txt SHA256 | findstr /v "hash"
</code></pre>
<p>This hashes the string <code>foobar</code> using SHA256 <strong>without appending a newline</strong>. That’s crucial. Using <code>echo "foobar"</code> would hash <code>foobar\n</code>, which is a different hash.</p>
<hr />
<h3 id="heading-step-by-step-explained">🧪 Step-by-step (explained)</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Component</td><td>Explanation</td></tr>
</thead>
<tbody>
<tr>
<td><code>echo</code></td><td>set /p="foobar"`</td></tr>
<tr>
<td><code>&gt; %TMP%\hash.txt</code></td><td>Writes the string to a temp file.</td></tr>
<tr>
<td><code>certutil -hashfile file SHA256</code></td><td>Uses Windows’ built-in tool to hash the file.</td></tr>
<tr>
<td><code>findstr /v "hash"</code></td><td>Filters out extra output, leaving just the hash line.</td></tr>
</tbody>
</table>
</div><p>Supported algorithms:</p>
<ul>
<li><p><code>MD2</code>, <code>MD4</code>, <code>MD5</code></p>
</li>
<li><p><code>SHA1</code>, <code>SHA256</code>, <code>SHA384</code>, <code>SHA512</code></p>
</li>
</ul>
<hr />
<h3 id="heading-powershell-wrapper-hash-string">🧱 PowerShell Wrapper: Hash-String</h3>
<p>Put this in <code>~\Documents\PowerShell\PSProfile.d\hash.ps1</code>:</p>
<pre><code class="lang-plaintext">powershellCopyEditfunction Hash-String {
    param (
        [Parameter(Mandatory)]
        [string]$InputString,

        [ValidateSet("MD5", "SHA1", "SHA256", "SHA384", "SHA512")]
        [string]$Algorithm = "SHA256"
    )

    $tmpFile = [System.IO.Path]::GetTempFileName()
    [System.IO.File]::WriteAllText($tmpFile, $InputString)

    certutil -hashfile $tmpFile $Algorithm |
        Where-Object { $_ -notmatch "hash of|certutil" }

    Remove-Item $tmpFile
}
</code></pre>
<p>Usage:</p>
<pre><code class="lang-plaintext">powershellCopyEditHash-String -InputString "foobar" -Algorithm SHA256
</code></pre>
<hr />
<h3 id="heading-why-hashes-matter">🧬 Why Hashes Matter</h3>
<ul>
<li><p>✅ <strong>Verify downloads</strong> with SHA256 hashes</p>
</li>
<li><p>✅ <strong>Secure passwords</strong> with irreversible hashing</p>
</li>
<li><p>✅ <strong>Digital signatures &amp; TLS/SSL</strong></p>
</li>
<li><p>✅ <strong>Git, blockchains, Merkle Trees</strong>... it's all hashes.</p>
</li>
</ul>
<p>Hashes are the checksum of our digital lives.</p>
<hr />
<h3 id="heading-modular-profiles-with-psprofiled">🗂 Modular Profiles with <code>PSProfile.d</code></h3>
<p>Like <code>/etc/profile.d</code> on Linux, I’m modularizing my Windows shell setup:</p>
<pre><code class="lang-plaintext">powershellCopyEdit# In $PROFILE
Get-ChildItem "$HOME\Documents\PowerShell\PSProfile.d" -Filter *.ps1 |
    ForEach-Object { . $_.FullName }
</code></pre>
<p>Drop your tools in <code>PSProfile.d</code> and you’ve got a portable, composable shell setup.</p>
<hr />
<h3 id="heading-side-quest-active-directory-certs-amp-more">🏗 Side Quest: Active Directory, Certs &amp; More</h3>
<p>Working with <code>certutil</code> reminded me I really should stand up a <strong>Windows Server 2019 VM</strong> inside my Proxmox cluster and finally add a domain controller to my home network.</p>
<p>Why?</p>
<ul>
<li><p>Local DNS, SSO, and central auth</p>
</li>
<li><p>Experiment with GPOs and PKI</p>
</li>
<li><p>Self-signed internal CA to play with smartcards or TLS</p>
</li>
</ul>
<hr />
<h3 id="heading-teaser-sha-3-and-the-weird-math">🔮 Teaser: SHA-3 and the Weird Math</h3>
<p>Everyone knows about MD5 and SHA-2. But <strong>SHA-3</strong> (based on Keccak) is something else entirely — a "sponge function" that's mathematically quite different. I'm planning a whole future post on it once I get my head around the math and its growing role in post-quantum cryptography and hardware implementations.</p>
<hr />
<h3 id="heading-tldr">🧩 TL;DR</h3>
<ul>
<li><p>Hash files or strings in Windows using <code>certutil</code></p>
</li>
<li><p>PowerShell makes it portable and repeatable</p>
</li>
<li><p>Modular shell setups are 🔥</p>
</li>
<li><p>Hashes underpin almost all of modern digital life</p>
</li>
<li><p>And this is just the beginning...</p>
</li>
</ul>
<hr />
<p>Got feedback? Need a GUI hash tool or want to explore digital signatures or SHA-3 next? Let me know. I’m building out a full FOSS-friendly workflow for Windows, Linux, and hybrid setups.</p>
]]></content:encoded></item></channel></rss>