<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
    <title>Look Ma, No Code</title>
    <link>https://lookmanocode.com/</link>
    <description>Field notes on self-hosting: run your own services at home, put them online for free, and know when paying is actually worth it.</description>
    <item>
        <title>UGREEN DXP4800 Review: Months of Real Use as a Photo Backup NAS</title>
        <link>https://lookmanocode.com/posts/ugreen-dxp4800-review/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/ugreen-dxp4800-review/</guid>
        <pubDate>Mon, 27 Jul 2026 00:00:00 GMT</pubDate>
        <description>I bought the DXP4800 with a 16TB drive to get our photos off our phones. Here&#39;s what daily use actually feels like, the one mistake that cost me 268GB, and who I&#39;d recommend it to.</description>
        <content:encoded><![CDATA[<p>I didn&#39;t buy this NAS to tinker with. I bought it because our photos were
spread across two phones, both of them slowly filling up, and I wanted one
box at home that quietly held everything. That&#39;s the whole job description:
be a big, safe drive that the family never has to think about.</p>
<p>So this is not a spec-sheet review. It&#39;s what the UGREEN DXP4800 is like to
live with when photo backup is the main thing you ask of it. Mine is the
8GB RAM model, and I put a single 16TB Toshiba enterprise drive in it to
start with.</p>
<h2>Setting it up</h2>
<p>The short version: you can go from box to working photo backup in an
evening without reading a manual. Drives slide in without tools, the UGOS
system walks you through initialization, and the mobile app finds the NAS
on your network and starts backing up the camera roll once you let it.</p>
<p>For a product category that used to assume you enjoyed configuring RAID
levels, that&#39;s genuinely the hard part solved. The people this box is aimed
at will never see a terminal, and nothing in the setup flow pushes them
toward one.</p>
<h2>The photo experience, which is the point</h2>
<p>This is where the DXP4800 earned its keep. The Photos app does the things
you&#39;d hope: albums, a timeline, and automatic backup from the phone in the
background. What surprised me was the speed — browsing the library from my
phone feels close to browsing photos stored on the phone itself. Thumbnails
load fast enough that you stop noticing there&#39;s a network in between, and
that matters more than any listed feature, because a photo library that
feels slow is a photo library nobody opens.</p>
<p>Full-size photos leave the phone, space comes back, and the pictures are
still one tap away. That was the promise, and it holds.</p>
<h2>The mistake that cost me 268GB</h2>
<p>One honest warning from my own use. The scheduled automatic backup never
gave me a single duplicate. But early on I also did big one-time imports by
hand — dumping an old phone&#39;s library onto the NAS in one go, then later
doing something similar again. Those manual dumps overlapped with what the
app had already backed up, and by the time I audited the library I had
about 268GB of duplicates sitting on the drive.</p>
<p>The lesson is boring but real: pick one pipeline and let it run. Let the
app do its scheduled backup, and treat manual bulk imports as a one-time
migration you do once, carefully, not a habit. The NAS won&#39;t stop you from
importing the same photos twice — cleaning that up afterwards is your
problem, and at hundreds of gigabytes it&#39;s a real chore.</p>
<h2>Remote access</h2>
<p>Away from home, the UGREEN app reaches the NAS through the company&#39;s
ug.link relay, and for photos on the go it has been fine — no router
settings, no fixed IP, it just works. If you ever outgrow it and want your
own domain in front of services on the NAS, that&#39;s solvable for free too,
and I wrote up <a href="https://lookmanocode.com/posts/cloudflare-tunnel-home-server/">exactly how I did it with Cloudflare Tunnel</a>.</p>
<h2>What I&#39;d push back on</h2>
<p>Two things, one small and one structural.</p>
<p>The small one: the box invites a second drive, and you should budget for
it sooner than you think. A single 16TB drive holds everything but is also
a single point of failure, and &quot;all our family photos&quot; is exactly the data
you don&#39;t want on one disk. Mirroring was always my plan; the review unit
of one drive is a starting point, not the destination.</p>
<p>The structural one: UGOS is friendly precisely because it&#39;s closed. As long
as you stay inside the official apps, everything is smooth. The moment you
want more — run your own service, schedule your own tasks, use Docker from
the command line — you find that
<a href="https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/">your user can&#39;t touch most of the machine</a>.
There are ways through, and I wrote them up, but be clear about what you&#39;re
buying: an appliance first, a Linux box a distant second.</p>
<h2>Who it&#39;s for</h2>
<p>If your problem is &quot;our photos live on phones and nowhere else,&quot; the
DXP4800 solves it well, and the solved version is pleasant to use daily.
Buy it, put two mirrored drives in it, turn on the app&#39;s automatic backup,
and resist the urge to hand-import things twice.</p>
<p>If your problem is &quot;I want a small home server that happens to have disks,&quot;
look carefully at the UGOS section above first. It can be that, I made it
be that, but the OS will fight you politely the whole way.</p>
<p>No affiliate links in this review — I bought this unit myself, and this
site currently earns nothing from any brand mentioned. If that ever
changes, it will be <a href="https://lookmanocode.com/disclosure/">disclosed here first</a>.</p>
]]></content:encoded>
    </item>
    <item>
        <title>Cloudflare Tunnel: Put a Home Server Online Without a Public IP or Port Forwarding</title>
        <link>https://lookmanocode.com/posts/cloudflare-tunnel-home-server/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/cloudflare-tunnel-home-server/</guid>
        <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
        <description>How Cloudflare Tunnel exposes a service running at home to the public internet for free, why it works behind CGNAT, and the one setting that will hand you a 502 on the first try.</description>
        <content:encoded><![CDATA[<p>Most guides to putting a home service online start with a step you might not
be able to do: log into your router and forward port 443. I couldn&#39;t do it
either, because my connection sits behind carrier-grade NAT — my router&#39;s
&quot;public&quot; address is shared with hundreds of other customers, and forwarding
a port simply isn&#39;t something the ISP lets me do. Your version of the wall
might look different, maybe a public IP that changes every few days or a
landlord&#39;s router you can&#39;t touch, but it works out to the same thing.</p>
<p>Cloudflare Tunnel goes around all of it. Nothing at your house listens for
incoming connections. Instead, a small program on your machine dials <strong>out</strong>
to Cloudflare and keeps that connection open. When someone visits your
domain, the traffic hits Cloudflare first, then rides back down that same
connection into your house. Your firewall stays shut. Your ISP never has to
cooperate.</p>
<p>It&#39;s free, and the HTTPS certificate is included.</p>
<h2>What you need</h2>
<ul>
<li>A domain, with its nameservers pointed at Cloudflare (the free plan is fine)</li>
<li>Any machine at home that stays on: a NAS, a mini PC, a Raspberry Pi</li>
<li>A service already running on that machine, reachable at
<code>http://localhost:&lt;port&gt;</code> from the machine itself</li>
</ul>
<p>That last point matters more than it looks. Get your service working locally
first. If <code>curl http://localhost:3000</code> doesn&#39;t return your page while you&#39;re
sitting on that machine, the tunnel can&#39;t help you. It only carries traffic;
it doesn&#39;t fix a service that isn&#39;t running.</p>
<h2>The mental model</h2>
<p>Three pieces have to line up. Mixing them up is where most of the confusion
comes from, so here they are:</p>
<div class="table-wrap"><table>
<thead>
<tr>
<th>Piece</th>
<th>Lives where</th>
<th>What it does</th>
</tr>
</thead>
<tbody><tr>
<td>Tunnel</td>
<td>Cloudflare&#39;s dashboard, one per machine</td>
<td>The persistent outbound connection</td>
</tr>
<tr>
<td>Connector (<code>cloudflared</code>)</td>
<td>Your machine</td>
<td>Dials out and keeps the tunnel alive</td>
</tr>
<tr>
<td>Public hostname</td>
<td>Cloudflare&#39;s dashboard</td>
<td>Maps <code>app.example.com</code> to a local address</td>
</tr>
</tbody></table></div>
<p>One tunnel can carry many hostnames. So one connector on your NAS can publish
a dozen services on a dozen subdomains. What one tunnel can&#39;t do is span two
machines.</p>
<h2>Create the tunnel</h2>
<p>In the Cloudflare dashboard, go to <strong>Zero Trust → Networks → Tunnels</strong> and
create a tunnel (<a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/">Cloudflare&#39;s own docs</a>
cover the same steps in more detail). Name it after the machine, not the app. You&#39;ll add more apps
later, and a tunnel called &quot;jellyfin&quot; running six other things gets confusing
fast.</p>
<p>Cloudflare hands you a token. Treat it like a password — anyone who has it
can publish services onto your domain.</p>
<p>This is the &quot;remotely managed&quot; style of tunnel, where the routing config
lives in the dashboard instead of a local <code>config.yml</code>. For a home setup
that&#39;s the right default. There&#39;s no config file to lose, and nothing to
re-edit when you add a hostname later. One trade-off worth knowing: the
dashboard is now the source of truth. When you&#39;re wondering &quot;why does this
hostname point there?&quot;, the answer is never in a file on your machine.</p>
<h2>Run the connector</h2>
<p>If you have Docker:</p>
<pre><code class="language-bash">docker run -d --name cloudflared --restart unless-stopped \
  --network host \
  cloudflare/cloudflared:latest tunnel --no-autoupdate run --token &lt;YOUR_TOKEN&gt;
</code></pre>
<p><code>--network host</code> matters. The connector needs to reach services running on
the host itself. Inside a normal bridge network, <code>localhost</code> means the
container — not your machine — and nothing will connect.</p>
<p>If you don&#39;t have Docker, or your NAS won&#39;t let your user anywhere near it,
that&#39;s fine too, because <code>cloudflared</code> is just a single file
(<a href="https://github.com/cloudflare/cloudflared/releases">grab the right build from the releases page</a>)
with no dependencies:</p>
<pre><code class="language-bash"># pick the build matching your architecture
curl -L -o cloudflared \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared
nohup ./cloudflared tunnel --no-autoupdate run --token &lt;YOUR_TOKEN&gt; &gt; cloudflared.log 2&gt;&amp;1 &amp;
</code></pre>
<p>I want to say this plainly, because a lot of NAS tutorials treat Docker as a
requirement: it isn&#39;t. All the container really buys you is a restart policy
and log rotation, so on a locked-down box where
<a href="https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/">you can&#39;t reach the Docker socket</a>,
the bare binary isn&#39;t a fallback at all — it&#39;s the shorter path. I hit
exactly that wall on a UGREEN NAS, and that guide walks through it.</p>
<p>Give it a few seconds and the dashboard should show the connector as healthy.</p>
<h2>Publish a hostname</h2>
<p>Add a public hostname to the tunnel: subdomain <code>app</code>, your domain, and a
service URL of <code>http://localhost:3000</code>.</p>
<p><strong>Use <code>http://</code>, not <code>https://</code>.</strong> This is the one that gets everybody,
including me. Your local service is almost certainly speaking plain HTTP
with no certificate. Tell Cloudflare to reach it over <code>https://</code> and the TLS
handshake fails, so every request comes back as <strong>502 Bad Gateway</strong> — with
nothing in the error hinting that the protocol scheme is the problem. Your
visitors still get real HTTPS. Encryption ends at Cloudflare&#39;s edge, and the
hop from there into your house runs inside the tunnel.</p>
<p>The DNS record gets created for you. There&#39;s nothing to add by hand.</p>
<h2>Check that it actually works</h2>
<pre><code class="language-bash">curl -sI https://app.example.com | head -3
</code></pre>
<p>A 200 means the whole chain works. If you get a 502, check in this order:</p>
<ol>
<li>Does <code>curl http://localhost:3000</code> work <strong>on the machine itself</strong>? If not,
the problem was never the tunnel.</li>
<li>Is the service URL <code>http://</code> and not <code>https://</code>?</li>
<li>Is the port right? A service bound to <code>127.0.0.1</code> while the connector
runs in a bridge network is the same failure wearing a different hat.</li>
</ol>
<p>A 530 or 1033 error means the tunnel itself is down. Check that the
connector process is actually running — not just that you started it once.</p>
<h2>Make it survive a reboot</h2>
<p>A tunnel that dies when the power flickers is a demo, not infrastructure.
With Docker, <code>--restart unless-stopped</code> handles it. Without Docker, use
whatever your system gives you: <code>systemd</code> on a normal Linux box, or the
scheduled-task UI on a NAS that has locked <code>cron</code> away.</p>
<p>Then actually reboot and watch it come back, because &quot;it should come back&quot;
and &quot;it came back&quot; are different claims. The test takes five minutes, and it
saves you from finding out the hard way during a power cut while you&#39;re
traveling.</p>
<h2>What this doesn&#39;t solve</h2>
<p>Your site is now exactly as available as your house. Cloudflare doesn&#39;t
cache HTML by default, so nearly every request travels back to your machine,
which means a power cut, an ISP outage, or someone unplugging the wrong
thing while vacuuming takes the site down with it. For a personal project
that&#39;s a fair trade. For anything where downtime costs money, it&#39;s a real
limit, and no tunnel setting changes it.</p>
<p>One hard number to know before you lean on it: requests through Cloudflare&#39;s
free plan are capped at
<a href="https://developers.cloudflare.com/workers/platform/limits/"><strong>100 MB of upload per request</strong></a>,
and a tunnel can&#39;t opt out. Browsing, streaming, and dashboards will never notice it, but
uploading your phone&#39;s camera roll to your own Immich or Nextcloud hits it
immediately, unless the app splits uploads into smaller chunks. Check that
before you promise yourself off-cloud photo backup through a tunnel.</p>
<p>And nothing here controls who gets in. A public hostname is public. If
you&#39;re exposing something that was never meant to face the internet — a
media server&#39;s admin panel, a database UI — put Cloudflare Access in front
of it before you point the world at it.</p>
<h2>When it&#39;s worth paying</h2>
<p>Free covers more than people expect here: unlimited tunnels, unlimited
hostnames, the certificate, and enough bandwidth that a content site will
never notice a limit. For publishing services from home, there&#39;s genuinely
nothing to buy.</p>
<p>The point where money starts to make sense isn&#39;t traffic, it&#39;s
availability. If &quot;what happens when the power goes out at home?&quot; stops
being an acceptable question, no tunnel feature fixes that — the fix is
moving the service into someone else&#39;s building, which means a cheap VPS.
I&#39;ve written a separate guide on
<a href="https://lookmanocode.com/posts/when-free-self-hosting-stops-being-enough/">when free self-hosting actually runs out</a>,
because that&#39;s a different decision, made for a different reason, and it&#39;s
worth making on purpose instead of drifting into it.</p>
]]></content:encoded>
    </item>
    <item>
        <title>Free Hosting Tiers in 2026: What Got Cut, What Survived, and How to Tell Which Dies Next</title>
        <link>https://lookmanocode.com/posts/free-tier-retreat/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/free-tier-retreat/</guid>
        <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
        <description>A timeline of every major free hosting tier that shrank or died between 2022 and 2026, the short list that survived, and the one structural difference that predicts which is which.</description>
        <content:encoded><![CDATA[<p>If you learned to deploy from a tutorial written before 2023, most of what it
told you about free hosting is now wrong. Not slightly outdated — wrong in the
specific way that costs you an afternoon: the platform still exists, the
signup page still works, and the free tier the tutorial was built around is
gone.</p>
<p>Here is the actual timeline, why it happened, and — more usefully — the pattern
that lets you predict which free tier dies next.</p>
<h2>The casualty list</h2>
<p><strong>Heroku, November 2022.</strong> The original free PaaS, the one every bootcamp
taught, <a href="https://blog.heroku.com/next-chapter">ended free dynos and free Postgres outright</a>. Every &quot;deploy your first
app free on Heroku&quot; tutorial on the internet became a museum piece overnight.</p>
<p><strong>Railway, July 2023.</strong> Positioned as the Heroku successor, then cut its free
plan citing crypto-mining abuse. What remains is
<a href="https://docs.railway.com/pricing/free-trial">a one-time trial credit and a token $1/month of usage</a> — enough to prove your account works, not enough to run
anything.</p>
<p><strong>PlanetScale, April 2024.</strong> The serverless MySQL darling
<a href="https://planetscale.com/docs/plans/hobby-plan-deprecation-faq">removed its Hobby tier entirely</a>,
giving existing free databases weeks to pay or migrate. It
remains a paid-only product today.</p>
<p><strong>Fly.io, October 2024.</strong> New accounts lost the free allowances. The trial for
a new user is now measured in hours, and
<a href="https://fly.io/docs/about/pricing/">a card is required for everyone</a>.</p>
<p><strong>AWS, July 2025.</strong> The famous &quot;12 months free&quot; EC2 for new accounts was
<a href="https://aws.amazon.com/free/">replaced by a credit-based plan</a> that expires
in months and then closes the account. The always-free serverless pieces (Lambda, DynamoDB) survived; the
free VM did not.</p>
<p><strong>Netlify, September 2025.</strong> New accounts
<a href="https://www.netlify.com/pricing/">moved to a credit system</a> whose effective
bandwidth is a fraction of the old 100 GB. The one mercy: it is a hard cap,
so <a href="https://lookmanocode.com/posts/hosting-that-cannot-surprise-bill-you/">it stops rather than bills</a>.</p>
<p><strong>Koyeb, February 2026.</strong> <a href="https://www.koyeb.com/blog/koyeb-is-joining-mistral-ai-to-build-the-future-of-ai-infrastructure">Acquired by Mistral AI</a>
and immediately closed free signups. A free tier can end not because the model failed, but because the
company got bought for its hardware.</p>
<p><strong>Render, April 2026.</strong> Kept its free web services but
<a href="https://render.com/blog/better-pricing-for-fast-growing-teams">cut free bandwidth from 100 GB to 5 GB per month</a>. The tier survives; its usefulness for anything with
an audience does not.</p>
<p><strong>Oracle Cloud, June 2026.</strong> The most generous free VM on the market — 4 ARM
cores and 24 GB of RAM — was
<a href="https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm">quietly halved to 2 cores and 12 GB</a>. Still the
biggest free compute you can get; also a reminder that even the outlier obeys
gravity.</p>
<h2>The survivor list</h2>
<p>Shorter, and worth memorising:</p>
<ul>
<li><strong>Cloudflare</strong> — Pages, Workers, R2, and <a href="https://lookmanocode.com/posts/cloudflare-tunnel-home-server/">Tunnel</a>. Unmetered static bandwidth,
free egress from object storage, no card required. The core limits have not
shrunk in years.</li>
<li><strong>GitHub Pages</strong> — unchanged for a decade, within its non-commercial terms.</li>
<li><strong>Google Cloud Run and the e2-micro VM</strong> — Google&#39;s always-free tier has
held steady, though both require a card and can bill past the free line.</li>
<li><strong>Supabase, Neon, Turso</strong> — the free database tier is alive and well,
card-free, with suspend-when-idle as the trade instead of money.</li>
</ul>
<h2>The pattern</h2>
<p>Look at the two lists and the structural difference jumps out. The casualties
were all cases where <strong>your free usage cost the provider real marginal money</strong>
— compute hours, egress bandwidth, storage on someone else&#39;s cloud. Free was a
customer-acquisition expense, funded by venture capital, and it ended when the
funding climate did.</p>
<p>The survivors are cases where <strong>your free usage costs the provider almost
nothing, or you are not the customer at all</strong>. Cloudflare runs its own network;
serving your static site through capacity it already owns is nearly free, and
every free user strengthens the network effect it sells to enterprises. GitHub
Pages is a rounding error on Microsoft&#39;s developer-ecosystem spend. Google&#39;s
always-free tier is a funnel into a card-on-file billing relationship.</p>
<p>So the test for any free tier is one question: <em>why is this free?</em> If the
honest answer is &quot;to acquire me as a paying customer later, while burning
investor money on my bandwidth&quot; — build on it expecting eviction. If the answer
is &quot;my usage is nearly free to them&quot; or &quot;I am the marketing&quot; — it will probably
outlive the tutorial you learned it from.</p>
<h2>What this means in practice</h2>
<p><strong>Date every tutorial.</strong> Anything about free hosting older than a year is
unverified until you have looked at the current pricing page. This article
included.</p>
<p><strong>Keep the exit cheap.</strong> The real cost of a free tier dying is not money, it
is migration under deadline. Prefer boring, portable shapes — static files, a
SQLite or Postgres dump, a Docker image — over anything that only exists inside
one platform&#39;s proprietary config. The people burned worst by the Heroku and
PlanetScale shutdowns were the ones whose setup could not be described without
naming the vendor.</p>
<p><strong>Let the retreat push you home.</strong> A machine you own has no free tier to lose.
The <a href="https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/">NAS or mini PC that was a toy in 2021</a>
is, after four years of cuts, quietly the most stable &quot;free hosting&quot; there is — nobody can revoke it, halve it, or
get acquired out from under it. That is not nostalgia for self-hosting; it is
just where the trend line points.</p>
<p>Free hosting is not dead. But the era when you could assume a free tier was a
permanent fact of the landscape ended somewhere around 2023, and building
anything meant to last means planning for the day the email arrives.</p>
]]></content:encoded>
    </item>
    <item>
        <title>How to Avoid a Surprise Cloud Bill: The Three Kinds of &#39;Free&#39; Hosting</title>
        <link>https://lookmanocode.com/posts/hosting-that-cannot-surprise-bill-you/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/hosting-that-cannot-surprise-bill-you/</guid>
        <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
        <description>The $104,500 static site, why budget alerts do not stop anything, and how to tell in advance whether a platform&#39;s worst case is downtime or debt.</description>
        <content:encoded><![CDATA[<p>In early 2024 a developer woke up to
<a href="https://news.ycombinator.com/item?id=39520776">a $104,500 invoice from Netlify</a>. The site
in question was a static site — no backend, no database — on a free plan with
a nominal $0/month cost. Someone had pointed a flood of traffic at it, roughly
190 TB of it, and the platform had dutifully served every byte and metered it
as overage. Netlify&#39;s CEO eventually waived the bill after the story reached
the front page of Hacker News, which is not a dispute-resolution process you
should plan around.</p>
<p>The same shape of story exists for most metered platforms: the startup that
<a href="https://medium.com/milkie-way/we-burnt-72k-testing-firebase-cloud-run-and-almost-went-bankrupt-part-1-703bb3052fae">burned $72,000 on Google Cloud in a few hours</a>
through a runaway loop, the
Firebase apps rung up for thousands overnight by scripted traffic, the AWS
bills generated by strangers hammering a bucket the owner thought was idle.
Different products, one cause: <strong>the platform&#39;s worst case was money, and
there was no ceiling.</strong></p>
<h2>The three kinds of &quot;free&quot;</h2>
<p>Every hosting free tier belongs to one of three billing shapes, and the shape
matters more than the numbers on the pricing page.</p>
<p><strong>1. Free with no card and no meter.</strong> The platform does not have your payment
details, so its only possible response to excess usage is refusal: an error, a
throttle, a suspended service. Cloudflare&#39;s free plan, GitHub Pages, Supabase,
Neon, Turso, and Render&#39;s free tier all work this way. The worst case is
downtime.</p>
<p><strong>2. Free with a hard cap.</strong> There may be a card on file, but spending stops at
a limit by design. Netlify&#39;s post-2025 credit system is this — one useful thing
to come out of that invoice. The worst case is downtime at the end of the
month.</p>
<p><strong>3. A free allowance on top of a metered account.</strong> Firebase&#39;s Blaze plan,
Google Cloud, AWS. The free tier is a discount, not a boundary; past it, every
request converts to money at market rate, without limit, at machine speed. The
worst case is debt, and the size of the worst case is set by your attacker,
not by you.</p>
<p>Nothing in category three is dangerous when idle. It becomes dangerous at the
exact moment something unexpected happens — a traffic spike, a scraper, a bug
in your own retry logic — which is precisely the moment you are not watching.</p>
<h2>Why budget alerts do not save you</h2>
<p>Every metered cloud offers &quot;budget alerts&quot;, and the name does a lot of quiet
misleading. An alert is an email. It does not stop, throttle, or cap anything.
<a href="https://cloud.google.com/billing/docs/how-to/budgets">Google Cloud&#39;s own documentation</a>
is plain that a budget does not prevent spending; it notifies you about it. The $72,000 Google Cloud incident took
under two hours end to end. Alert emails were sent. They were read the next
morning.</p>
<p>Some platforms let you build a real kill switch — on Google Cloud you can wire
a budget notification to a small function that detaches the billing account,
taking your project down but ending the bleeding. That works, and if you keep
anything on a metered cloud you should install it. But notice what it is: a
do-it-yourself circuit breaker for a product that declined to include one.</p>
<h2>The decision rule</h2>
<p>Before putting anything on a platform, ask one question: <strong>what is the worst
thing that happens if a stranger sends this service a million times more
traffic than I expect?</strong></p>
<p>If the answer is &quot;it goes down&quot; — fine. Downtime on a hobby project costs
nothing. This is the correct default for anything personal: sites, dashboards,
bots, experiments. It is also, not coincidentally, what you get from
<a href="https://lookmanocode.com/posts/cloudflare-tunnel-home-server/">a machine at home behind a free tunnel</a>:
your worst case is that your own hardware is busy.</p>
<p>If the answer is &quot;I get billed&quot; — the platform needs to clear a much higher
bar, and you need three things in place from day one: a spending cap if it
exists, a real kill switch if it does not, and a genuine reason the capped
alternatives will not do. &quot;The tutorial used it&quot; is not such a reason.</p>
<h2>Where that leaves a home server</h2>
<p>A self-hosted box has plenty of real risks — power, disk failure, your own
attention span — and this site does not pretend otherwise. But it is worth
naming the risk it does not have. There is no meter. A flood of abuse against
a service in your house saturates your connection, annoys you, and ends. It
cannot compound at $0.55 per gigabyte while you sleep.</p>
<p>Pair that with a front door whose free plan also cannot bill you — a tunnel
through an unmetered edge — and the entire attack-cost equation belongs to
someone else&#39;s balance sheet. If you&#39;re weighing that trade,
<a href="https://lookmanocode.com/posts/when-free-self-hosting-stops-being-enough/">the honest version of when home hosting stops being enough</a>
is its own article. That combination, not raw performance, is the
strongest argument for the home-server-plus-free-edge setup this site keeps
coming back to: it is the only architecture where the answer to &quot;what is the
worst case?&quot; is fully known in advance.</p>
<p>Money buys availability, and sometimes availability is worth buying. But debt
should require your signature. Choose platforms where it does.</p>
]]></content:encoded>
    </item>
    <item>
        <title>Running a Long-Lived Service on a UGREEN NAS (UGOS) When Every Normal Route Is Blocked</title>
        <link>https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/</guid>
        <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
        <description>No sudo, no Docker socket, no unzip, no cron, no rsync. A working path to a service that survives reboots on UGOS, and the four walls you will hit getting there.</description>
        <content:encoded><![CDATA[<p>A UGREEN NAS running UGOS is a competent Linux box: x86_64, Docker installed,
SSH available. So the natural assumption is that hosting a small service on it
works the way it works anywhere else. Install a runtime, start a process, add a
cron entry, done.</p>
<p>It does not. UGOS reserves a lot for its own management layer, and the account
you SSH in with is not the account that owns the system. Every one of the four
standard moves fails, each in a slightly different way, and none of the error
messages tell you what to do instead.</p>
<p>Here is what actually works, and what each wall looks like when you hit it.
Almost every guide for this class of appliance is written for Synology, where the
answers are different. This one is written from UGOS.</p>
<h2>Wall 1: your SSH user cannot use Docker</h2>
<p>You will find Docker installed and immediately discover it is not yours to use:</p>
<pre><code>$ docker ps
permission denied while trying to connect to the Docker daemon socket
at unix:///var/run/docker.sock: connect: permission denied
</code></pre>
<p>The usual fix is <code>sudo usermod -aG docker $USER</code>. That fails too, because your
account has no <code>sudo</code>, and UGOS does not offer a way to grant either one. Docker
on this appliance is reachable through the desktop UI app and through control
panels like 1Panel, but not from your shell.</p>
<p><strong>What to do instead: skip Docker.</strong> This sounds like a downgrade and mostly is
not. A container buys you a restart policy, log rotation, and dependency
isolation. For a single service with no system dependencies, you can get the
first two by other means and do not need the third.</p>
<p>Everything below assumes a plain host process.</p>
<h2>Wall 2: your runtime&#39;s installer needs <code>unzip</code>, which is absent</h2>
<p>Most modern runtimes install with a one-liner that pipes a script into your
shell. On UGOS that script gets some distance and then dies, because the archive
it downloads is a zip and there is no <code>unzip</code> on the system. There is no <code>apt</code>
either — this is an appliance, not a distro.</p>
<p><strong>What to do instead: unpack it on your own machine and copy the binary over.</strong>
Most runtimes ship a single static binary inside that archive; the installer
script is a convenience, not a requirement.</p>
<pre><code class="language-bash"># on your own machine
curl -L -o runtime.zip https://example.com/runtime-linux-x64.zip
unzip runtime.zip
# stream the binary over SSH into place
cat runtime-linux-x64/bin/runtime \
  | ssh user@nas &#39;mkdir -p ~/bin &amp;&amp; cat &gt; ~/bin/runtime &amp;&amp; chmod +x ~/bin/runtime&#39;
</code></pre>
<p>Then add <code>~/bin</code> to your <code>PATH</code> in <code>~/.profile</code>. From here on the runtime behaves
completely normally — the only thing missing was the unpacking tool.</p>
<p>The same trick works for any single-binary tool you need on the box.</p>
<h2>Wall 3: SSH is not exposed, so plan how you reach the machine</h2>
<p>Port 22 is not open to the internet, and it should stay that way. When you are at
home this is a non-issue. When you are not, you need a private path in.</p>
<p>The clean answer is a mesh VPN — Tailscale or equivalent — which gives the NAS a
stable private address reachable from your laptop anywhere, with no ports opened
and no dynamic-DNS games. Install it, and <code>ssh user@100.x.y.z</code> works from a
different continent.</p>
<p>Worth knowing before you need it: the UGOS app centre has no web terminal, and
the &quot;Terminal&quot; entry in the control panel is only an on/off switch for the SSH
service, not a shell. If you lose your private path while away from home, your
remaining options are the control panel&#39;s scheduled-task feature — which can run
a script, so it doubles as a crude remote-execution channel — or waiting until
you are back on the LAN. Set the VPN up before you travel, not after.</p>
<h2>Wall 4: <code>cron</code> refuses you, and <code>nohup</code> alone is not enough</h2>
<p>Two separate problems, usually discovered together.</p>
<p>First, starting a process over SSH and disconnecting kills it unless you detach
it properly:</p>
<pre><code class="language-bash">setsid nohup ~/bin/runtime server.js &gt; ~/logs/app.log 2&gt;&amp;1 &amp;
</code></pre>
<p><code>nohup</code> alone survives the hangup signal in most cases; <code>setsid</code> also detaches
the process from the terminal&#39;s session, which is what you actually want for
something meant to outlive your shell.</p>
<p>Second, the obvious way to start it at boot is not available:</p>
<pre><code>$ crontab -e
/var/spool/cron: Permission denied
</code></pre>
<p>There is no user crontab, and no <code>systemctl --user</code> either.</p>
<p><strong>What to do instead: use the control panel&#39;s scheduled tasks.</strong> UGOS exposes a
task scheduler in its web UI with a run-at-startup trigger, and it will run a
shell script as your user. Point it at a small launcher script rather than at the
command directly, so you can change how the service starts without going back
into the UI:</p>
<pre><code class="language-bash">#!/bin/sh
# ~/apps/myapp/start.sh — kill any previous instance, then start fresh
pkill -f &#39;runtime server.js&#39;
sleep 1
cd ~/apps/myapp || exit 1
setsid nohup ~/bin/runtime server.js &gt; ~/logs/app.log 2&gt;&amp;1 &amp;
</code></pre>
<p>The same script is your deploy step and your restart step, which is one fewer
thing to remember.</p>
<h2>Deploying updates: <code>tar</code> over SSH</h2>
<p><code>rsync</code> is not present and <code>scp</code> is unreliable here. What works is streaming a
tar through the SSH connection:</p>
<pre><code class="language-bash">tar czf - --exclude=node_modules --exclude=data . \
  | ssh user@nas &#39;mkdir -p ~/apps/myapp &amp;&amp; tar xzf - -C ~/apps/myapp&#39;
ssh user@nas &#39;~/apps/myapp/start.sh&#39;
</code></pre>
<p>Exclude your data directory explicitly, every time. The one deploy where you
forget is the one that overwrites your database with an empty copy from your
laptop.</p>
<h2>Verify the part everyone skips</h2>
<p>Restarting the service proves the service works. It does not prove the thing you
actually care about, which is that the NAS comes back on its own after losing
power.</p>
<p>So test it: reboot the NAS from the control panel, wait, and check that the
service answers without you touching anything.</p>
<pre><code class="language-bash">curl -sI http://&lt;nas-address&gt;:&lt;port&gt;/ | head -1
</code></pre>
<p>&quot;It should come back&quot; and &quot;it came back&quot; are different claims. The gap between
them is usually a scheduled task that was saved but never enabled, and you would
rather find that out now than during a power cut while you are away.</p>
<h2>What this gets you</h2>
<p>A service running as your own user, started at boot by the appliance&#39;s own
scheduler, deployed with one tar command, with no <code>sudo</code>, no Docker, and nothing
installed system-wide. It is less elegant than a container and considerably less
elegant than <code>systemd</code>, but it is entirely within what UGOS will let you do, and
it stays working.</p>
<h2>When it&#39;s worth paying</h2>
<p>Nothing in this article costs money, and for running services at home the free
path genuinely goes the whole distance. The appliance is already bought, the
software is free, and the constraints are annoying rather than limiting.</p>
<p>The honest limit is not money, it is what a box in your house can promise. One
power supply, one internet connection, and no maintenance window that is not your
own evening. That is fine for a personal service and fine for a site like this
one. The moment something needs to be up while you are asleep, travelling, or
moving house, the fix is not a better startup script — it is a machine in a
building with a generator, which is where a cheap VPS starts to make sense.
I&#39;ve written about <a href="https://lookmanocode.com/posts/when-free-self-hosting-stops-being-enough/">how to tell when you&#39;ve actually reached that point</a>,
because deciding it deliberately beats discovering it during an outage.</p>
]]></content:encoded>
    </item>
    <item>
        <title>Self-Hosting at Home vs Paying for a VPS: When Free Actually Runs Out</title>
        <link>https://lookmanocode.com/posts/when-free-self-hosting-stops-being-enough/</link>
        <guid isPermaLink="true">https://lookmanocode.com/posts/when-free-self-hosting-stops-being-enough/</guid>
        <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
        <description>A decision framework for hosting at home versus paying for a server, based on what free genuinely covers, what it cannot promise, and the four signals that mean you have outgrown it.</description>
        <content:encoded><![CDATA[<p>The advice you get about self-hosting splits into two camps that are both
useless. One says pay for a VPS immediately because home hosting is unserious.
The other says never pay for anything because free tiers can do everything now.</p>
<p>Both skip the only question that matters: what specifically does free fail to
provide, and does your project need that thing?</p>
<p>Here is that question answered concretely. Nothing below is an argument for
spending money — most home setups genuinely never need to. It is an argument for
knowing in advance which line you will eventually cross, so that when you cross
it you recognise it instead of blaming your own configuration.</p>
<h2>What free actually covers</h2>
<p>More than people expect, and it is worth being precise, because vague gratitude
toward free tiers is how people end up paying for things they already had.</p>
<p><strong>Getting online at all.</strong> A tunnel service publishes a machine at home to the
public internet with
<a href="https://lookmanocode.com/posts/cloudflare-tunnel-home-server/">no public IP address, no forwarded ports, and no static address</a>.
This is fully solved and it is free. If your reason for considering a
VPS is &quot;I cannot get in from outside&quot;, you do not need a VPS.</p>
<p><strong>HTTPS.</strong> Certificates are free and automatic, both through tunnels and through
Let&#39;s Encrypt directly. This has not been a reason to pay for anything in years.</p>
<p><strong>Bandwidth, for anything text-shaped.</strong> A content site, a personal dashboard, a
git remote, an API for your own use: the traffic is negligible. Free tiers are
not going to notice you.</p>
<p><strong>Compute.</strong> A four-bay NAS or a second-hand mini PC will out-specify a $5 VPS
on every axis — more cores, far more RAM, vastly more disk. Even a
<a href="https://lookmanocode.com/posts/ugreen-nas-ugos-run-a-service/">locked-down consumer NAS can run a long-lived service</a>
once you know the walls. You are not short of
compute at home. You are short of something else.</p>
<h2>What free cannot promise</h2>
<p>Four things, and they are all the same shape: they are properties of the
<em>building</em>, not the software.</p>
<p><strong>Power.</strong> One supply, no generator, no UPS unless you bought one. A cut means
the site is down until you are physically present or the scheduled task does its
job at boot — assuming the boot itself succeeds.</p>
<p><strong>Connectivity.</strong> One residential line. Your ISP does maintenance whenever it
likes and owes you nothing. Upload is asymmetric and modest, which does not
matter for text and matters immediately for video or large downloads.</p>
<p><strong>Presence.</strong> Something that needs a hand — a stuck process, a full disk, a
failed drive — needs <em>your</em> hand, in that room. This is the constraint people
underestimate most, because it is invisible until you are away.</p>
<p><strong>A separate failure domain.</strong> Your backups, your tunnel, your monitoring and the
thing being monitored all live on one box in one room. When that room has a
problem, you lose the ability to observe the problem at the same moment you gain
the problem.</p>
<p>Notice what is not on this list: performance, reliability of the hardware,
software capability, or professionalism. Those are not what you would be buying.</p>
<h2>The four signals you have outgrown free</h2>
<p>Not thresholds you should aim for. Signals to watch for, in rough order of how
often they actually arrive.</p>
<p><strong>1. Someone other than you is depending on uptime.</strong> The moment a real user, a
client, or a paying customer is affected by an outage, &quot;I will fix it when I get
home&quot; stops being an acceptable answer. This is the signal that arrives first
and matters most, and it has nothing to do with traffic volume.</p>
<p><strong>2. You are about to be away.</strong> Travel, a move, a hospital stay. A setup that
requires your physical presence is fine right up until it does not, and this one
you can see coming.</p>
<p><strong>3. Your uploads are the bottleneck.</strong> If you are serving video, large binaries,
or an image-heavy site to an audience in another region, residential upload is
the wall — and no configuration change moves it.</p>
<p><strong>4. Your backups are not somewhere else.</strong> If the answer to &quot;what if the NAS is
stolen or the flat floods?&quot; is a shrug, the thing you need is not a VPS, it is
off-site storage. That is a cheaper purchase than a server and it is more urgent
than one. Do not conflate the two.</p>
<p>If none of those apply, you are done. Stay free. The rest of this article is not
for you yet.</p>
<h2>What to buy, in the right order</h2>
<p>Assuming a signal has actually arrived, the mistake is to buy a server first.
Spend in this order:</p>
<ol>
<li><strong>Off-site backups.</strong> Cheapest, highest value, and it addresses signal 4
completely. Object storage costs a few dollars a month for a personal-sized
dataset.</li>
<li><strong>A UPS.</strong> Addresses brief power cuts, which are most power cuts. A one-time
purchase, no subscription, and it also protects the disks you already own.</li>
<li><strong>External monitoring.</strong> A free uptime checker that lives outside your house
tells you the site is down before your readers do. It fixes the observability
half of signal 1 for nothing.</li>
<li><strong>A small VPS.</strong> Only now, and only for the specific thing that needs to be in
a different building. Frequently that is not the whole service — it can be
just the tunnel endpoint, or a mirror of the static site, while the heavy
storage stays at home.</li>
</ol>
<p>Steps 1 to 3 handle most of what people buy a VPS to solve, at a fraction of the
cost. If you skip them and buy the server, you will own a server and still have
your original problem.</p>
<h2>A note on what this site has not tested</h2>
<p>This article deliberately names no VPS provider. I run at home, and I have not
personally put this site&#39;s workload on a paid host, so any provider comparison
from me would be repackaged marketing copy rather than experience. That would be
worth less than nothing to you.</p>
<p>When that changes, the write-up will be of an actual migration with actual
numbers, and it will say what went wrong.</p>
<h2>When it&#39;s worth paying</h2>
<p>Free is not a compromise for self-hosting at home. It is the correct default, and
it covers getting online, encryption, bandwidth, and compute completely.</p>
<p>What money buys is not capability. It is <em>someone else&#39;s building</em> — their
generator, their redundant connection, their staff at 3am. That is the entire
transaction. It becomes worth it the moment your own presence stops being a
reasonable dependency, and not one day before. Until then, the cheapest and most
honest infrastructure decision available to you is the one you are already
running.</p>
]]></content:encoded>
    </item>
</channel>
</rss>
