<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christopher</title>
    <description>The latest articles on DEV Community by Christopher (@lancer1977).</description>
    <link>https://dev.to/lancer1977</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F894664%2F5a178f79-4425-4716-82c9-4446cad36a6a.jpeg</url>
      <title>DEV Community: Christopher</title>
      <link>https://dev.to/lancer1977</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lancer1977"/>
    <language>en</language>
    <item>
      <title>Blocking Bing at Home with Pi-Hole (Without Breaking Edge)</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Sat, 21 Feb 2026 17:55:11 +0000</pubDate>
      <link>https://dev.to/lancer1977/blocking-bing-at-home-with-pi-hole-without-breaking-edge-21fl</link>
      <guid>https://dev.to/lancer1977/blocking-bing-at-home-with-pi-hole-without-breaking-edge-21fl</guid>
      <description>&lt;p&gt;🚫 Blocking Bing at Home with Pi-hole (Without Breaking Edge)&lt;/p&gt;

&lt;p&gt;Microsoft Bing has a habit of inserting itself into browsers, operating systems, and “helpful” search features — even when you didn’t ask for it.&lt;/p&gt;

&lt;p&gt;This guide shows how to block Bing network-wide using Pi-hole, while still allowing Microsoft Edge, Windows Update, and sync features to work normally.&lt;/p&gt;

&lt;p&gt;🧠 What This Guide Covers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blocking Bing at the DNS level using Pi-hole&lt;/li&gt;
&lt;li&gt;Preventing Bing reinjection in Microsoft Edge&lt;/li&gt;
&lt;li&gt;Keeping Edge updates and Windows Update working&lt;/li&gt;
&lt;li&gt;Optional hardening steps for privacy-focused setups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠 Prerequisites&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working Pi-hole instance&lt;/li&gt;
&lt;li&gt;Pi-hole configured as the primary DNS for your network&lt;/li&gt;
&lt;li&gt;Admin access to Pi-hole&lt;/li&gt;
&lt;li&gt;Optional: Microsoft Edge installed on at least one client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1️⃣ Blocking Bing with Pi-hole (Network-Wide)&lt;/p&gt;

&lt;p&gt;This blocks Bing for every device on your network — desktops, phones, tablets, smart TVs, etc.&lt;/p&gt;

&lt;p&gt;🔒 Domains to Block&lt;/p&gt;

&lt;p&gt;In Pi-hole Admin → Group Management → Domains → Blacklist, add the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bing.com&lt;br&gt;
www.bing.com&lt;br&gt;
api.bing.com&lt;br&gt;
bingapis.com&lt;br&gt;
www.bingapis.com&lt;br&gt;
c.bing.com&lt;br&gt;
th.bing.com&lt;br&gt;
www.msn.com&lt;br&gt;
ntp.msn.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lancer1977/DataSeeds/blob/master/block_lists/bing.list" rel="noopener noreferrer"&gt;https://github.com/lancer1977/DataSeeds/blob/master/block_lists/bing.list&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why These Domains?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bing.com, api.bing.com → core search endpoints&lt;/li&gt;
&lt;li&gt;c.bing.com, th.bing.com → tracking, suggestions, thumbnails&lt;/li&gt;
&lt;li&gt;msn.com, ntp.msn.com → Bing-powered Edge new tab content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This combination stops:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct Bing searches&lt;/li&gt;
&lt;li&gt;Address bar fallback searches&lt;/li&gt;
&lt;li&gt;MSN news / trending reinjection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2️⃣ Domains You Should NOT Block&lt;/p&gt;

&lt;p&gt;Blocking these will break Edge or Windows updates.&lt;/p&gt;

&lt;p&gt;❌ Do NOT block:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;edge.microsoft.com&lt;br&gt;
msedge.api.cdp.microsoft.com&lt;br&gt;
update.microsoft.com&lt;br&gt;
windowsupdate.microsoft.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These are required for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edge updates&lt;/li&gt;
&lt;li&gt;Extension installs&lt;/li&gt;
&lt;li&gt;Profile sync&lt;/li&gt;
&lt;li&gt;Windows Update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3️⃣ Restart Pi-hole DNS&lt;/p&gt;

&lt;p&gt;After adding domains, restart DNS:&lt;/p&gt;

&lt;p&gt;pihole restartdns&lt;/p&gt;

&lt;p&gt;If clients cache DNS aggressively, flush client DNS as well.&lt;/p&gt;

&lt;p&gt;Linux (systemd-resolved)&lt;br&gt;
sudo resolvectl flush-caches&lt;br&gt;
4️⃣ Configure Microsoft Edge to Stop Using Bing&lt;/p&gt;

&lt;p&gt;You can keep Edge — you just need to disable its Bing hooks.&lt;/p&gt;

&lt;p&gt;🔍 Set a Different Search Engine&lt;/p&gt;

&lt;p&gt;Edge → Settings → Privacy, search, and services → Address bar and search&lt;/p&gt;

&lt;p&gt;Set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search engine used in the address bar → DuckDuckGo (or Google)&lt;/li&gt;
&lt;li&gt;Search on new tabs → Address bar&lt;/li&gt;
&lt;li&gt;Address bar search engine suggestions → Off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔕 Disable Bing Reinjection Features&lt;/p&gt;

&lt;p&gt;Edge → Settings → Privacy, search, and services&lt;/p&gt;

&lt;p&gt;Turn OFF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show me search and site suggestions using my typed characters&lt;/li&gt;
&lt;li&gt;Show me personalized ads&lt;/li&gt;
&lt;li&gt;Improve Microsoft products by sending optional diagnostic data&lt;/li&gt;
&lt;li&gt;Search and service improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These settings are commonly used to route searches back to Bing.&lt;/p&gt;

&lt;p&gt;5️⃣ Clean Up the Edge New Tab Page&lt;/p&gt;

&lt;p&gt;Open a new tab → ⚙️ Settings&lt;/p&gt;

&lt;p&gt;Set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout → Focused&lt;/li&gt;
&lt;li&gt;Content → Content off&lt;/li&gt;
&lt;li&gt;Quick links → Off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This disables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MSN news&lt;/li&gt;
&lt;li&gt;Trending Bing searches&lt;/li&gt;
&lt;li&gt;Sponsored tiles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;6️⃣ (Optional) Extra Privacy Hardening&lt;br&gt;
Block Microsoft Search Telemetry&lt;/p&gt;

&lt;p&gt;Add these optionally if you want deeper privacy control:&lt;/p&gt;

&lt;p&gt;self.events.data.microsoft.com&lt;br&gt;
browser.events.data.microsoft.com&lt;/p&gt;

&lt;p&gt;⚠️ This may reduce “smart” suggestions but does not break Edge.&lt;/p&gt;

&lt;p&gt;7️⃣ Verifying It Works&lt;br&gt;
Test DNS Resolution&lt;br&gt;
&lt;code&gt;ping bing.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ping: bing.com: Name or service not known&lt;/li&gt;
&lt;li&gt;Pi-hole Query Log&lt;/li&gt;
&lt;li&gt;Open Query Log&lt;/li&gt;
&lt;li&gt;Filter for bing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requests should show Blocked (gravity)&lt;/p&gt;

&lt;p&gt;✅ Result&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bing is blocked network-wide&lt;/li&gt;
&lt;li&gt;Edge remains fully functional&lt;/li&gt;
&lt;li&gt;Windows Update continues working&lt;/li&gt;
&lt;li&gt;No browser extensions required&lt;/li&gt;
&lt;li&gt;No per-device configuration needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*Note: Made with the help of AI (I'm not this smart!)&lt;/p&gt;

</description>
      <category>networking</category>
      <category>privacy</category>
      <category>tutorial</category>
      <category>pihole</category>
    </item>
    <item>
      <title>Making an Ollama Mesh with Nginx</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Fri, 06 Feb 2026 18:14:53 +0000</pubDate>
      <link>https://dev.to/lancer1977/ollama-mesh-3l5j</link>
      <guid>https://dev.to/lancer1977/ollama-mesh-3l5j</guid>
      <description>&lt;h1&gt;
  
  
  Load Balancing Ollama with NGINX: Handling Long GPU Jobs and Dead Nodes Gracefully
&lt;/h1&gt;

&lt;p&gt;Running Ollama on a single machine is easy. Running &lt;strong&gt;multiple Ollama instances across your LAN&lt;/strong&gt;—and surviving GPU stalls, reboots, or long outages—is where things get interesting.&lt;/p&gt;

&lt;p&gt;This post walks through a &lt;strong&gt;production-grade NGINX upstream configuration&lt;/strong&gt; for Ollama, explains how it behaves under load, and shows how to tune it when one machine might be down for minutes or hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Ollama Needs Special Load Balancing
&lt;/h2&gt;

&lt;p&gt;Ollama workloads are not typical web traffic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests are &lt;strong&gt;long-lived&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Execution time varies wildly (model + prompt dependent)&lt;/li&gt;
&lt;li&gt;GPUs saturate before CPUs&lt;/li&gt;
&lt;li&gt;A “slow” request is not a failure&lt;/li&gt;
&lt;li&gt;Nodes can vanish mid-generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Classic round-robin load balancing performs poorly here.&lt;/p&gt;

&lt;p&gt;What you want instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adaptive request distribution&lt;/li&gt;
&lt;li&gt;Fast eviction of dead nodes&lt;/li&gt;
&lt;li&gt;Minimal retry thrashing&lt;/li&gt;
&lt;li&gt;Connection reuse&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Baseline NGINX Upstream Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;ollama_pool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;least_conn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.169&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.156&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.141&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;keepalive&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;code&gt;least_conn&lt;/code&gt;: The Right Algorithm for GPUs
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;least_conn&lt;/code&gt; routes new requests to the backend with the &lt;strong&gt;fewest active connections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why this works so well for Ollama:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM requests are long-running&lt;/li&gt;
&lt;li&gt;Faster GPUs finish sooner&lt;/li&gt;
&lt;li&gt;Finished nodes naturally get more work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you &lt;strong&gt;implicit weighting&lt;/strong&gt; without hardcoding values.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure Handling for Long Downtime Nodes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.169&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After &lt;strong&gt;2 failures&lt;/strong&gt; within &lt;strong&gt;60 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The node is marked &lt;strong&gt;down for 60 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No traffic is sent during that time&lt;/li&gt;
&lt;li&gt;Afterward, NGINX retries automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For known long outages, consider &lt;code&gt;fail_timeout=300s&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connection Reuse Matters (&lt;code&gt;keepalive&lt;/code&gt;)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;keepalive&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables TCP reuse between NGINX and Ollama.&lt;/p&gt;

&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fewer handshakes&lt;/li&gt;
&lt;li&gt;Lower latency&lt;/li&gt;
&lt;li&gt;Better streaming stability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Requires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Detecting Failures Quickly (Timeouts)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_connect_timeout&lt;/span&gt; &lt;span class="s"&gt;2s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_send_timeout&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proxy_connect_timeout&lt;/code&gt; handles dead hosts fast&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_read_timeout&lt;/code&gt; must be tuned:

&lt;ul&gt;
&lt;li&gt;Streaming → lower OK&lt;/li&gt;
&lt;li&gt;Blocking generations → higher needed&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Retrying Failed Requests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_next_upstream&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt; &lt;span class="s"&gt;timeout&lt;/span&gt; &lt;span class="s"&gt;http_500&lt;/span&gt; &lt;span class="s"&gt;http_502&lt;/span&gt; &lt;span class="s"&gt;http_503&lt;/span&gt; &lt;span class="s"&gt;http_504&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_next_upstream_tries&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NGINX will retry failed requests on other nodes.&lt;/p&gt;

&lt;p&gt;⚠️ LLM responses are not guaranteed idempotent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Planned Maintenance: Disable a Node
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.141&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;down&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload NGINX to immediately remove the node from rotation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recommended Production Baseline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Upstream
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;ollama_pool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;least_conn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.169&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.156&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;192.168.0.141&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11434&lt;/span&gt; &lt;span class="s"&gt;max_fails=2&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=60s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;keepalive&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Proxy Location
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;proxy_connect_timeout&lt;/span&gt; &lt;span class="s"&gt;2s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;proxy_next_upstream&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt; &lt;span class="s"&gt;timeout&lt;/span&gt; &lt;span class="s"&gt;http_500&lt;/span&gt; &lt;span class="s"&gt;http_502&lt;/span&gt; &lt;span class="s"&gt;http_503&lt;/span&gt; &lt;span class="s"&gt;http_504&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_next_upstream_tries&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tune &lt;code&gt;proxy_read_timeout&lt;/code&gt; based on streaming vs blocking usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Setup Does Not Do
&lt;/h2&gt;

&lt;p&gt;This configuration does &lt;strong&gt;not&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share model state&lt;/li&gt;
&lt;li&gt;Provide session stickiness&lt;/li&gt;
&lt;li&gt;Add authentication&lt;/li&gt;
&lt;li&gt;Expose Ollama safely to the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use it on trusted networks or behind TLS + auth.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This setup provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smart GPU-aware load balancing&lt;/li&gt;
&lt;li&gt;Automatic failover&lt;/li&gt;
&lt;li&gt;Graceful handling of dead machines&lt;/li&gt;
&lt;li&gt;Minimal operational overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s a solid foundation for any serious Ollama deployment.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>nginx</category>
      <category>ollama</category>
    </item>
    <item>
      <title>Blazor Behind Nginx – Addendums</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Thu, 05 Feb 2026 16:25:17 +0000</pubDate>
      <link>https://dev.to/lancer1977/blazor-behind-nginx-addendums-22m</link>
      <guid>https://dev.to/lancer1977/blazor-behind-nginx-addendums-22m</guid>
      <description>&lt;h1&gt;
  
  
  Blazor Behind Nginx – Addendums
&lt;/h1&gt;

&lt;p&gt;This document is intended as &lt;strong&gt;add-on material&lt;/strong&gt; to the main article:&lt;br&gt;
&lt;strong&gt;“Fixing Blazor Apps Behind Nginx: Reverse Proxy Headers, WebSockets, and Redirect Hell”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blazor WebAssembly–specific considerations&lt;/li&gt;
&lt;li&gt;Hosting Blazor under a sub-path (e.g. &lt;code&gt;/dashboard&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Addendum 1: Blazor WebAssembly Behind Nginx
&lt;/h2&gt;

&lt;p&gt;Blazor WebAssembly (WASM) behaves very differently from Blazor Server when placed behind Nginx — mostly because &lt;strong&gt;there is no persistent server connection&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Problems Go Away with Blazor WASM
&lt;/h3&gt;

&lt;p&gt;Because Blazor WASM runs entirely in the browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No SignalR&lt;/li&gt;
&lt;li&gt;No WebSockets&lt;/li&gt;
&lt;li&gt;No long-lived server connections&lt;/li&gt;
&lt;li&gt;No proxy timeouts freezing the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removes an entire class of reverse-proxy issues.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;redirects, auth, and absolute URLs can still break&lt;/strong&gt; if forwarded headers are incorrect.&lt;/p&gt;


&lt;h3&gt;
  
  
  Minimal Nginx Config for Blazor WASM
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Port&lt;/span&gt; &lt;span class="nv"&gt;$server_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No WebSocket upgrades or extended timeouts are required.&lt;/p&gt;


&lt;h3&gt;
  
  
  When Blazor WASM Still Breaks
&lt;/h3&gt;

&lt;p&gt;Common failure modes:&lt;/p&gt;
&lt;h4&gt;
  
  
  OAuth / OIDC Redirect Failures
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Wrong scheme (&lt;code&gt;http&lt;/code&gt; vs &lt;code&gt;https&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Incorrect host&lt;/li&gt;
&lt;li&gt;Missing forwarded headers&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  API Calls Fail
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Absolute URLs generated incorrectly&lt;/li&gt;
&lt;li&gt;CORS misconfiguration&lt;/li&gt;
&lt;li&gt;Hardcoded ports or protocols&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Mixed Content Errors
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;App served over HTTPS, APIs resolving to HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are still proxy metadata problems — not Blazor problems.&lt;/p&gt;


&lt;h3&gt;
  
  
  When WASM Is the Better Choice
&lt;/h3&gt;

&lt;p&gt;Choose &lt;strong&gt;Blazor WASM&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don’t need server push&lt;/li&gt;
&lt;li&gt;You don’t need per-user server state&lt;/li&gt;
&lt;li&gt;You want simpler infrastructure&lt;/li&gt;
&lt;li&gt;You want fewer reverse-proxy edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose &lt;strong&gt;Blazor Server&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need tight server control&lt;/li&gt;
&lt;li&gt;You need real-time server interaction&lt;/li&gt;
&lt;li&gt;You’re willing to manage WebSockets correctly&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Addendum 2: Hosting Blazor Under a Sub-Path
&lt;/h2&gt;

&lt;p&gt;Hosting Blazor under a sub-path instead of &lt;code&gt;/&lt;/code&gt; introduces additional complexity.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public URL: &lt;code&gt;https://example.com/dashboard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Kestrel app: running at &lt;code&gt;/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This requires &lt;strong&gt;explicit configuration&lt;/strong&gt; in both Nginx and Blazor.&lt;/p&gt;


&lt;h3&gt;
  
  
  Nginx Sub-Path Proxy Configuration
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/dashboard/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:5000/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Port&lt;/span&gt; &lt;span class="nv"&gt;$server_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_redirect&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trailing slashes matter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_redirect off&lt;/code&gt; prevents broken Location headers&lt;/li&gt;
&lt;li&gt;The path must be consistent everywhere&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Blazor Server: Configure PathBase
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UsePathBase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/dashboard"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This must be applied &lt;strong&gt;before routing and endpoints&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Missing this results in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Broken navigation&lt;/li&gt;
&lt;li&gt;Incorrect links&lt;/li&gt;
&lt;li&gt;Static asset failures&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Blazor WASM: Configure Base Href
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;wwwroot/index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/dashboard/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If incorrect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing fails&lt;/li&gt;
&lt;li&gt;Static assets 404&lt;/li&gt;
&lt;li&gt;JS interop breaks&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Authentication Cookie Gotchas
&lt;/h3&gt;

&lt;p&gt;When hosting under a sub-path, cookies may not be sent correctly.&lt;/p&gt;

&lt;p&gt;Symptoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login works once&lt;/li&gt;
&lt;li&gt;Refresh logs the user out&lt;/li&gt;
&lt;li&gt;Auth state disappears unexpectedly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Root causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cookie path mismatch&lt;/li&gt;
&lt;li&gt;Incorrect redirect URIs&lt;/li&gt;
&lt;li&gt;Missing PathBase configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(This is covered fully in the Keycloak deep dive.)&lt;/p&gt;




&lt;h3&gt;
  
  
  Common Sub-Path Failure Matrix
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Navigation breaks&lt;/td&gt;
&lt;td&gt;Missing PathBase or base href&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static assets 404&lt;/td&gt;
&lt;td&gt;Trailing slash mismatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Login loop&lt;/td&gt;
&lt;td&gt;Cookie path mismatch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redirects drop sub-path&lt;/td&gt;
&lt;td&gt;Proxy redirect rewriting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API calls hit wrong URL&lt;/td&gt;
&lt;td&gt;Absolute path assumptions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Recommendation
&lt;/h3&gt;

&lt;p&gt;If possible, avoid sub-path hosting.&lt;/p&gt;

&lt;p&gt;Prefer subdomains instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dashboard.example.com
api.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dramatically reduces routing, auth, and proxy complexity.&lt;/p&gt;




</description>
      <category>devops</category>
      <category>dotnet</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Get back inserted Id</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Thu, 05 Feb 2026 15:39:53 +0000</pubDate>
      <link>https://dev.to/lancer1977/get-back-inserted-id-81b</link>
      <guid>https://dev.to/lancer1977/get-back-inserted-id-81b</guid>
      <description>&lt;h1&gt;
  
  
  Getting the Inserted ID in SQL Server (INT vs UNIQUEIDENTIFIER)
&lt;/h1&gt;

&lt;p&gt;When inserting rows into SQL Server, it’s common to immediately need the primary key that was just created—whether to return it from an API, insert related records, or log activity.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;correct approach depends on your primary key type&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;INT IDENTITY&lt;/code&gt; primary keys
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UNIQUEIDENTIFIER&lt;/code&gt; (GUID) primary keys
&lt;/li&gt;
&lt;li&gt;Common mistakes to avoid
&lt;/li&gt;
&lt;li&gt;Best-practice SQL patterns
&lt;/li&gt;
&lt;li&gt;How this maps cleanly to Dapper / ADO.NET
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Case 1: INT IDENTITY Primary Keys
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Table definition
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Topics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Image&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ❌ The common mistake
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is &lt;strong&gt;unsafe&lt;/strong&gt;. If triggers or parallel inserts exist, it can return the wrong value.&lt;/p&gt;




&lt;h3&gt;
  
  
  ✅ Correct: SCOPE_IDENTITY()
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Topics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SCOPE_IDENTITY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scoped to your insert&lt;/li&gt;
&lt;li&gt;Safe from triggers&lt;/li&gt;
&lt;li&gt;Cheap and fast&lt;/li&gt;
&lt;li&gt;Returns only the identity value&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  When to use this
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple inserts&lt;/li&gt;
&lt;li&gt;Single-row inserts&lt;/li&gt;
&lt;li&gt;Tables with &lt;code&gt;INT IDENTITY&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Case 2: UNIQUEIDENTIFIER Primary Keys (GUIDs)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Table definition
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Topics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="n"&gt;UNIQUEIDENTIFIER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NEWID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Image&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ❌ Why SCOPE_IDENTITY() does NOT work
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SCOPE_IDENTITY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;UNIQUEIDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SCOPE_IDENTITY()&lt;/code&gt; only works with numeric identity columns.&lt;br&gt;&lt;br&gt;
GUIDs are &lt;strong&gt;not identities&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  ✅ Correct: OUTPUT INSERTED.Id
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Topics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;OUTPUT&lt;/span&gt; &lt;span class="n"&gt;INSERTED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This returns the &lt;strong&gt;actual GUID&lt;/strong&gt; generated by SQL Server.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bonus: Multi-row Inserts
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SCOPE_IDENTITY()&lt;/code&gt; fails here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;Topics&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;OUTPUT&lt;/span&gt; &lt;span class="n"&gt;INSERTED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;TopicBatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns &lt;strong&gt;all generated IDs&lt;/strong&gt; correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dapper Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  INT
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteScalar&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GUID
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteScalar&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PK Type&lt;/th&gt;
&lt;th&gt;Correct Method&lt;/th&gt;
&lt;th&gt;Trigger Safe&lt;/th&gt;
&lt;th&gt;Multi-Row Safe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;INT IDENTITY&lt;/td&gt;
&lt;td&gt;SCOPE_IDENTITY()&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UNIQUEIDENTIFIER&lt;/td&gt;
&lt;td&gt;OUTPUT INSERTED.Id&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;SCOPE_IDENTITY()&lt;/code&gt; only for &lt;code&gt;INT IDENTITY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;OUTPUT INSERTED.Id&lt;/code&gt; for GUIDs&lt;/li&gt;
&lt;li&gt;Never use &lt;code&gt;@@IDENTITY&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Happy querying 🚀&lt;/p&gt;

</description>
      <category>sql</category>
    </item>
    <item>
      <title>NGINX Security</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Fri, 31 Mar 2023 07:05:38 +0000</pubDate>
      <link>https://dev.to/lancer1977/nginx-security-2iei</link>
      <guid>https://dev.to/lancer1977/nginx-security-2iei</guid>
      <description>&lt;h1&gt;
  
  
  Fixing Blazor Apps Behind Nginx: Reverse Proxy Headers, WebSockets, and Redirect Hell
&lt;/h1&gt;

&lt;p&gt;If you’ve ever deployed a Blazor app behind &lt;strong&gt;Nginx&lt;/strong&gt; and thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“It kind of works… but redirects are broken, auth is weird, and the UI randomly stops responding”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;—you’re not alone.&lt;/p&gt;

&lt;p&gt;This post documents the issues I hit running Blazor behind an Nginx reverse proxy, &lt;strong&gt;why they happen&lt;/strong&gt;, and the &lt;strong&gt;minimal set of fixes&lt;/strong&gt; that actually made things stable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Blazor apps (especially &lt;strong&gt;Blazor Server&lt;/strong&gt;) behave badly behind a reverse proxy unless the proxy correctly forwards request metadata.&lt;/p&gt;

&lt;p&gt;Common symptoms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infinite HTTP ↔ HTTPS redirect loops&lt;/li&gt;
&lt;li&gt;Auth callbacks failing (OIDC / OAuth / Twitch / Okta / Keycloak)&lt;/li&gt;
&lt;li&gt;Incorrect absolute URLs being generated&lt;/li&gt;
&lt;li&gt;Blazor Server disconnects or frozen UI&lt;/li&gt;
&lt;li&gt;Client IPs always showing as &lt;code&gt;127.0.0.1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first glance, everything looks fine — the app responds — but things slowly fall apart.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Happens
&lt;/h2&gt;

&lt;p&gt;Nginx terminates TLS and forwards traffic to Kestrel.&lt;br&gt;&lt;br&gt;
By default, &lt;strong&gt;ASP.NET Core has no idea&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What hostname the user actually hit&lt;/li&gt;
&lt;li&gt;Whether the request was HTTPS&lt;/li&gt;
&lt;li&gt;What port was used&lt;/li&gt;
&lt;li&gt;Who the real client IP is&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without that information, ASP.NET Core makes bad assumptions — and Blazor magnifies those mistakes.&lt;/p&gt;


&lt;h2&gt;
  
  
  The First Fix: Forwarded Headers
&lt;/h2&gt;

&lt;p&gt;This is the bare minimum most people discover first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this fixes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Preserves the public hostname&lt;/li&gt;
&lt;li&gt;Preserves client IPs&lt;/li&gt;
&lt;li&gt;Tells ASP.NET Core whether the original request was HTTP or HTTPS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This improves things, but in many cases it does &lt;strong&gt;not fully fix them&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Still having some issues, but this seems to be part of the solution.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s because it is only part of the solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Missing Headers Most Guides Don’t Mention
&lt;/h2&gt;

&lt;p&gt;In practice, you usually also need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Port&lt;/span&gt; &lt;span class="nv"&gt;$server_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some stacks rely on &lt;code&gt;X-Forwarded-Host&lt;/code&gt; more than &lt;code&gt;Host&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Port mismatches can break redirects and auth callbacks&lt;/li&gt;
&lt;li&gt;Multi-proxy setups behave more consistently with explicit forwarding&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Blazor Server-Specific Gotcha: WebSockets (SignalR)
&lt;/h2&gt;

&lt;p&gt;Blazor Server requires WebSockets (SignalR).&lt;br&gt;&lt;br&gt;
Without explicit upgrade headers, the UI may:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load but not respond&lt;/li&gt;
&lt;li&gt;Randomly disconnect&lt;/li&gt;
&lt;li&gt;Freeze after navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You must include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;"upgrade"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Long-Lived Connections Need Timeouts and Buffering Tweaks
&lt;/h2&gt;

&lt;p&gt;Blazor Server keeps long-running connections open.&lt;br&gt;&lt;br&gt;
Default Nginx buffering and timeouts can eventually kill them.&lt;/p&gt;

&lt;p&gt;These settings often help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_send_timeout&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  A “Known-Good” Nginx Config for Blazor Server
&lt;/h2&gt;

&lt;p&gt;This is the configuration that finally stopped the weird behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;"upgrade"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Port&lt;/span&gt; &lt;span class="nv"&gt;$server_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_send_timeout&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assumptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TLS is terminated at Nginx&lt;/li&gt;
&lt;li&gt;Kestrel is running HTTP internally&lt;/li&gt;
&lt;li&gt;You’re hosting at &lt;code&gt;/&lt;/code&gt; (not a sub-path)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Important: Nginx Alone Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Even with perfect headers, &lt;strong&gt;ASP.NET Core must be configured to trust them&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your app doesn’t enable forwarded headers middleware, it will ignore what Nginx sends.&lt;/p&gt;

&lt;p&gt;Typical symptoms when this is missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS redirects still broken&lt;/li&gt;
&lt;li&gt;Auth callbacks still wrong&lt;/li&gt;
&lt;li&gt;Scheme mismatches persist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure forwarded headers are enabled and your proxy/network is trusted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Failure Modes (and What They Mean)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTTP ↔ HTTPS redirect loop&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;X-Forwarded-Proto&lt;/code&gt; not honored&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth callback mismatch&lt;/td&gt;
&lt;td&gt;Host / scheme incorrect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blazor UI freezes/disconnects&lt;/td&gt;
&lt;td&gt;WebSocket upgrade missing or timeouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random disconnects&lt;/td&gt;
&lt;td&gt;Proxy timeouts / buffering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client IP always localhost&lt;/td&gt;
&lt;td&gt;Missing forwarded IP headers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Blazor behind Nginx can be rock-solid, but only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forwarded headers are complete&lt;/li&gt;
&lt;li&gt;WebSockets are explicitly supported (Blazor Server)&lt;/li&gt;
&lt;li&gt;Timeouts are adjusted for long-lived connections&lt;/li&gt;
&lt;li&gt;The app actually trusts the proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most guides cover some of this. Very few cover all of it.&lt;/p&gt;

&lt;p&gt;Hopefully this saves someone else a few hours of head-scratching.&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>linux</category>
    </item>
    <item>
      <title>Easier Lets Encrypt SSL Certs</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Fri, 31 Mar 2023 06:55:27 +0000</pubDate>
      <link>https://dev.to/lancer1977/easier-lets-encrypt-ssl-certs-1g</link>
      <guid>https://dev.to/lancer1977/easier-lets-encrypt-ssl-certs-1g</guid>
      <description>&lt;p&gt;I've been using a combination of Cloudflare and Nginx Proxy Manager to simplify various internal and external services over the past year. Adding SSL to externally exposed sites has been pretty straight forward, add a CNAME record in Cloudflare that points to my router, and my router uses Nginx for a reverse proxy. Simply enough, plus the traffic gets auto wrapped in Cloudflares certs.&lt;/p&gt;

&lt;p&gt;The issue has been adding and maintaining SSL for internal only apps. I've been following the same workflow as external apps but turning on/off the cloudflare record. This also doesn't provide me real SSL from cloudflare anymore and I've had to generate it from letsencrypt while the external port was exposed. Not optimal, and renew breaks in this  pattern.&lt;/p&gt;

&lt;p&gt;Solution: Wildcard certs. This was less that straight forward as I tried to manually use certbot to create a wildcard cert which works, but I still have to manually renew, and the import process is even more long winded. So Nginx Proxy Manager has the ability to create a SSL certificate from the tab, and use LetsEncrypt. &lt;br&gt;
Settings should be as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain name - *.[yourdomain].com&lt;/li&gt;
&lt;li&gt;Tick on Use a DNS Challenge&lt;/li&gt;
&lt;li&gt;I tested cloudflare as my DNS provider but there are a lot of others in the dropdown that work similarly I expect. Once you select this it will want a token. Grab that from Cloudflare -&amp;gt; My Profile -&amp;gt; Api Tokens and create a new custom token.&lt;/li&gt;
&lt;li&gt;Call it whatever you like, imortant part is the permissions. They should be set to [Zone] [Zone Settings][Edit],&lt;/li&gt;
&lt;li&gt;Include whichever zones you want, and continue to summary below. &lt;/li&gt;
&lt;li&gt;Agree to the terms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now update/add endpoints and use this new cert. It hasn't been long enough to require renewal but it should follow the same renew pattern as the non-wildcard certs.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Register for Notifications on Android SDK 33</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Mon, 20 Mar 2023 14:14:43 +0000</pubDate>
      <link>https://dev.to/lancer1977/register-for-notifications-on-android-sdk-33-ao9</link>
      <guid>https://dev.to/lancer1977/register-for-notifications-on-android-sdk-33-ao9</guid>
      <description>&lt;p&gt;Problem: Notifications are not being received after upgrading to Android SDK 33.&lt;/p&gt;

&lt;p&gt;Solution: In Android SDK 33 you now have to request permissions to display Notifications. Asking for POST_NOTIFICATIONS alone wasn't sufficient, and some of these maybe overkill but this is what worked for me.&lt;/p&gt;

&lt;p&gt;To get the notifications permission, you need to first request permission for the following items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private string[] PermissionsForNotifications =
            {
                Manifest.Permission.ReceiveBootCompleted,
                Manifest.Permission.WakeLock,
                Manifest.Permission.Vibrate,
                Manifest.Permission.Internet,
                Manifest.Permission.AccessNetworkState,
                Manifest.Permission.PostNotifications,
                Manifest.Permission.ForegroundService,
                "com.google.android.c2dm.permission.RECEIVE",                "com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE",                "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS",
                "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"
            };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When calling the registration it seemed the Channel ID was also required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private int RequestNotificationId = 1000;
ActivityCompat.RequestPermissions(CurrentActivity, PermissionsForNotifications, RequestNotificationId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Blazor WASM Linking</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Fri, 10 Feb 2023 18:09:35 +0000</pubDate>
      <link>https://dev.to/lancer1977/blazor-wasm-linking-3hik</link>
      <guid>https://dev.to/lancer1977/blazor-wasm-linking-3hik</guid>
      <description>&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;:&lt;br&gt;
Your WASM application works fine in debug, but when you deploy you start seeing issues where methods and other such things are missing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Possible Solution&lt;/strong&gt;: Blazor WASM is similar to Xamarin development in that you want to ensure your app is as small as possible. To that goal, by default the build will strip out any perceived unneeded code from your project. This can have some unforeseen consequences unfortunately. To avoid this consider adding the following properties to your project file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disable ALL linking&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;PropertyGroup&amp;gt; 
&amp;lt;BlazorWebAssemblyEnableLinking&amp;gt;false&amp;lt;/BlazorWebAssemblyEnableLinking&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Disable linking in a more nuanced fasion&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;BlazorLinkerDescriptor Include="LinkerConfig.xml" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you go with the LinkerConfig.xml please review the reference for guides on how to populate the LinkerConfig.xml&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt; &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/configure-linker?view=aspnetcore-3.1" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/configure-linker?view=aspnetcore-3.1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blazor</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>SQL Primary Keys</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Sun, 05 Feb 2023 04:57:24 +0000</pubDate>
      <link>https://dev.to/lancer1977/sql-primary-keys-65l</link>
      <guid>https://dev.to/lancer1977/sql-primary-keys-65l</guid>
      <description>&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;:&lt;br&gt;
You need to add a primary Key to a table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: &lt;br&gt;
Heres a few types I've run across.&lt;/p&gt;

&lt;h1&gt;
  
  
  Manual Primary Key
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CREATE TABLE [dbo].[HtmlDtos]([Id] [int] PRIMARY KEY)&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Auto Sequential Int Primary Key
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CREATE TABLE [dbo].[HtmlDtos]([Id] [int] IDENTITY(1,1) PRIMARY KEY)&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Auto Sequential GUID PK
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CREATE TABLE [dbo].[HtmlDtos] ([Id] UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY)&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Auto Random GUID PK
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;CREATE TABLE [dbo].[HtmlDtos]([Id] UNIQUEIDENTIFIER DEFAULT NEWID() PRIMARY KEY)&lt;/code&gt;&lt;/p&gt;

</description>
      <category>codenewbie</category>
      <category>learning</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>SonarQube Docker with PostGres issues</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Wed, 25 Jan 2023 15:05:19 +0000</pubDate>
      <link>https://dev.to/lancer1977/sonarqube-docker-with-postgres-issues-167f</link>
      <guid>https://dev.to/lancer1977/sonarqube-docker-with-postgres-issues-167f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Created a new docker container for SonarQube and it failed with the error:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: &lt;/p&gt;

&lt;p&gt;edit the file /etc/sysctl.conf&lt;br&gt;
change or add a line &lt;code&gt;vm.max_map_count=262144&lt;/code&gt;&lt;br&gt;
then run &lt;code&gt;sysctl --system&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/41064572/docker-elk-vm-max-map-count" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/41064572/docker-elk-vm-max-map-count&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Get the last directory a file with bash</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Wed, 25 Jan 2023 15:04:45 +0000</pubDate>
      <link>https://dev.to/lancer1977/get-the-last-directory-a-file-with-bash-3g5d</link>
      <guid>https://dev.to/lancer1977/get-the-last-directory-a-file-with-bash-3g5d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;br&gt;
You need to get the last directory a file is in,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt; (one of many I'm sure):&lt;br&gt;
using the full filename "/path/to/file/filename.txt"&lt;br&gt;
&lt;code&gt;dirname /path/to/file/filename.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;this produces &lt;em&gt;/path/to/file&lt;/em&gt;, then we use shell replacement as such:&lt;br&gt;
&lt;code&gt;echo ${INPUT##*/}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;which produces &lt;br&gt;
&lt;code&gt;file&lt;/code&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating Multi-platform nugets for Xamarin</title>
      <dc:creator>Christopher</dc:creator>
      <pubDate>Tue, 24 Jan 2023 17:54:25 +0000</pubDate>
      <link>https://dev.to/lancer1977/creating-multi-platform-nugets-for-xamarin-4fci</link>
      <guid>https://dev.to/lancer1977/creating-multi-platform-nugets-for-xamarin-4fci</guid>
      <description>&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;:&lt;br&gt;
You want to create nuget packages that have different dependencies for multiple platforms such as Xamarin iOS and Android and beyond.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;br&gt;
Create a nuspec file that includes dependencies and files that match the platforms you want to target as such.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;package &amp;gt;
  &amp;lt;metadata&amp;gt;
    ... 
 &amp;lt;dependencies&amp;gt;

      &amp;lt;group targetFramework="Xamarin.iOS10"&amp;gt; 
        &amp;lt;dependency id="Microsoft.AspNetCore.SignalR.Client" version="5.0.9" /&amp;gt;
        &amp;lt;dependency id="Microsoft.Extensions.Http" version="5.0.0" /&amp;gt;
        &amp;lt;dependency id="System.Reactive" version="5.0.0" /&amp;gt; 
      &amp;lt;/group&amp;gt;

      &amp;lt;group targetFramework="MonoAndroid10"&amp;gt; 
        &amp;lt;dependency id="Microsoft.AspNetCore.SignalR.Client" version="5.0.9" /&amp;gt;
        &amp;lt;dependency id="Microsoft.Extensions.Http" version="5.0.0" /&amp;gt;
        &amp;lt;dependency id="System.Reactive" version="5.0.0" /&amp;gt; 
      &amp;lt;/group&amp;gt;

      &amp;lt;group targetFramework="net7.0"&amp;gt; 
        &amp;lt;dependency id="Microsoft.AspNetCore.SignalR.Client" version="5.0.9" /&amp;gt;
        &amp;lt;dependency id="Microsoft.Extensions.Http" version="5.0.0" /&amp;gt;
        &amp;lt;dependency id="System.Reactive" version="5.0.0" /&amp;gt; 
      &amp;lt;/group&amp;gt;
    &amp;lt;group targetFramework="netstandard2.1"&amp;gt; 
        &amp;lt;dependency id="Microsoft.AspNetCore.SignalR.Client" version="5.0.9" /&amp;gt;
        &amp;lt;dependency id="Microsoft.Extensions.Http" version="5.0.0" /&amp;gt;
        &amp;lt;dependency id="System.Reactive" version="5.0.0" /&amp;gt; 
      &amp;lt;/group&amp;gt;
    &amp;lt;/dependencies&amp;gt;

  &amp;lt;/metadata&amp;gt;
    &amp;lt;files&amp;gt;    
      &amp;lt;file src="[dllpath]" target="lib\netstandard2.1" /&amp;gt;
      &amp;lt;file src="[dllpath]" target="lib\net7.0" /&amp;gt;
      &amp;lt;file src="[dllpath]" target="lib\MonoAndroid10" /&amp;gt;
      &amp;lt;file src="[dllpath]" target="lib\Xamarin.iOS10" /&amp;gt;
    &amp;lt;/files&amp;gt;
&amp;lt;/package&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
