<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>ANTYXSOFT CLOUD blog</title>
    <link>https://www.antyxsoft.io/blog</link>
    <description>Capacity, networking, migrations and the engineering behind Antyxsoft hosting.</description>
    <language>en</language>
    <pubDate>Tue, 15 Sep 2026 17:47:10 GMT</pubDate>
    <dc:date>2026-09-15T17:47:10Z</dc:date>
    <dc:language>en</dc:language>
    <item>
      <title>Writing a DR runbook you can actually execute | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/writing-a-dr-runbook-you-can-actually-execute</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/writing-a-dr-runbook-you-can-actually-execute" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/writing-a-dr-runbook-you-can-actually-execute.png" alt="Writing a DR runbook you can actually execute | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Most disaster recovery documents are inventories: a list of systems, a list of contacts, a diagram. A runbook is different. It is an ordered sequence of actions someone can follow at 04:00 while the primary site is dark, without needing to make architectural decisions on the spot.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Most disaster recovery documents are inventories: a list of systems, a list of contacts, a diagram. A runbook is different. It is an ordered sequence of actions someone can follow at 04:00 while the primary site is dark, without needing to make architectural decisions on the spot.&lt;/p&gt; 
&lt;h2&gt;Start with tiers, not systems&lt;/h2&gt; 
&lt;p&gt;Sort workloads into three or four tiers and give each tier an RPO and an RTO. The recovery point is how much data you accept losing; the recovery time is how long the service can be gone. Both are business decisions, and both cost money as they approach zero — which is exactly why the business, not the infrastructure team, should sign them off.&lt;/p&gt; 
&lt;p&gt;A workable starting shape: tier 1 gets continuous replication with seconds of RPO and tens of minutes of RTO; tier 2 gets scheduled replication with a 15-minute RPO; tier 3 restores from the offsite backup chain within a working day; tier 4 is rebuilt from configuration management and does not need a replica at all. Being explicit that some systems are tier 4 is what makes the tier 1 budget defensible.&lt;/p&gt; 
&lt;h2&gt;Get the dependency order right&lt;/h2&gt; 
&lt;p&gt;The single most common runbook failure is booting an application before the thing it authenticates against. Write the failover order down and test it: directory and DNS, then databases, then application servers, then the public entry point.&lt;/p&gt; 
&lt;p&gt;Then handle the parts that are not virtual machines. Which DNS records change, and what is their TTL? Which certificates does the replica need? Which outbound integrations are IP-allowlisted at the other end? Which scheduled jobs must stay off until failback, so invoices are not sent twice? These are the steps that turn a successful boot into a working service, and they are usually missing.&lt;/p&gt; 
&lt;h2&gt;Name the humans&lt;/h2&gt; 
&lt;p&gt;A runbook needs a declared decision-maker: who is allowed to declare a disaster and start the failover, and who deputises when that person is unreachable. Without it, the first hour of every real incident is spent seeking permission.&lt;/p&gt; 
&lt;p&gt;Add the communications plan in the same document — who tells customers, who tells staff, which channel is used when email is part of the outage — and keep an offline copy. A runbook stored only in the environment it recovers is not a runbook.&lt;/p&gt; 
&lt;h2&gt;Rehearse in a sandbox&lt;/h2&gt; 
&lt;p&gt;Test failover brings replicas up in an isolated network where they cannot reach production, so you can rehearse on a normal Tuesday. Boot the tier 1 group in dependency order, log in as a real user, run a genuine transaction, and record the wall-clock time from decision to service.&lt;/p&gt; 
&lt;p&gt;Compare that number with the RTO in the document and correct whichever is wrong. Then rehearse the part everyone skips: failback. Returning to the primary site with the changes made during the outage is the harder direction, and the first time should not be for real.&lt;/p&gt; 
&lt;h2&gt;Keep it short and current&lt;/h2&gt; 
&lt;p&gt;A runbook that has not been executed in a year is a work of fiction. Review it after every significant infrastructure change, keep it to actions rather than explanations, and attach the evidence from the last rehearsal — the date, who ran it, what broke, what was fixed. That evidence is also what an insurer or an auditor asks for.&lt;/p&gt; 
&lt;p&gt;Antyxsoft DRaaS keeps replicas of critical machines warm in EU data centres with per-workload RPO and RTO targets, sandboxed test failover and orchestrated failback — &lt;a href="https://143470013.hs-sites-eu1.com/products/veeam-backup-draas"&gt;see how Veeam backup and DRaaS works&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fwriting-a-dr-runbook-you-can-actually-execute&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Backup</category>
      <pubDate>Sun, 06 Sep 2026 11:50:18 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/writing-a-dr-runbook-you-can-actually-execute</guid>
      <dc:date>2026-09-06T11:50:18Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Adding an offsite cloud repository to Veeam | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/adding-an-offsite-cloud-repository-to-veeam</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/adding-an-offsite-cloud-repository-to-veeam" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/adding-an-offsite-cloud-repository-to-veeam.png" alt="Adding an offsite cloud repository to Veeam | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Adding a cloud repository to Veeam Backup &amp;amp; Replication is a ten-minute task. Getting the first full copy of a multi-terabyte estate through your uplink without anyone noticing takes a little planning — and that planning is the whole job.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Adding a cloud repository to Veeam Backup &amp;amp; Replication is a ten-minute task. Getting the first full copy of a multi-terabyte estate through your uplink without anyone noticing takes a little planning — and that planning is the whole job.&lt;/p&gt; 
&lt;h2&gt;Backup copy job, not a second backup&lt;/h2&gt; 
&lt;p&gt;The pattern you want is a backup copy job reading from your existing on-premises repository, not a second primary backup job pointed at the cloud. Two reasons: your production workloads are only touched once, and the copy job maintains its own retention chain offsite, which is what the third leg of 3-2-1 actually requires.&lt;/p&gt; 
&lt;p&gt;Local restores keep coming from local disk at local speed. The cloud copy is there for the day the building, the array or the domain is the problem.&lt;/p&gt; 
&lt;h2&gt;Size the first full honestly&lt;/h2&gt; 
&lt;p&gt;Work out the real number before you start: total protected data, minus what compression and deduplication will remove, over the bandwidth you are actually willing to give the job. A 3 TiB estate on a 200 Mbps window is roughly four nights of transfer — fine if you planned for it, alarming if you did not.&lt;/p&gt; 
&lt;p&gt;Two levers make that number smaller. Scope the first job to the workloads that genuinely need offsite protection rather than everything at once, and check whether seeding is available for very large first fulls. Subsequent runs move only incremental changes, which is usually a small fraction of the first.&lt;/p&gt; 
&lt;h2&gt;Throttle before the first run, not after&lt;/h2&gt; 
&lt;p&gt;Set a bandwidth rule with a schedule: full rate overnight and at weekends, a modest cap during business hours. Veeam's traffic rules apply per source-target pair, so the copy job can be limited without touching local backup performance.&lt;/p&gt; 
&lt;p&gt;Enable WAN acceleration if you have it licensed and the change rate justifies the cache. If not, the combination of compression and incremental-forever is usually enough for a nightly copy of a normal estate.&lt;/p&gt; 
&lt;h2&gt;Encryption and credentials&lt;/h2&gt; 
&lt;p&gt;Turn on job-level encryption and store the password somewhere that survives the site — a password in a vault on the server you are protecting is not a plan. Use credentials for the cloud repository that exist nowhere else in your environment, so a compromise of the production domain does not hand over the offsite copy.&lt;/p&gt; 
&lt;p&gt;The gateway connection is initiated outbound from your side, so there is no inbound rule to open and no backup infrastructure exposed to the internet.&lt;/p&gt; 
&lt;h2&gt;Retention: keep GFS deliberate&lt;/h2&gt; 
&lt;p&gt;Decide the offsite chain separately from the local one. Local retention is optimised for fast recent restores; offsite retention is optimised for surviving a long-dwell attack and for whatever the auditor asks for. A common shape is a short local chain plus weekly, monthly and yearly GFS points in the cloud, with an immutability window at least as long as the shortest GFS interval.&lt;/p&gt; 
&lt;h2&gt;Verify, then walk away&lt;/h2&gt; 
&lt;p&gt;When the first full completes, do three things. Check the chain reports as healthy and complete. Run a restore from the cloud copy — one file and one whole VM — and time both. Then enable recovery verification on a schedule so this is checked without anyone remembering to.&lt;/p&gt; 
&lt;p&gt;Only after a successful restore from the offsite copy is the third leg of 3-2-1 real. Until then it is a transfer that finished.&lt;/p&gt; 
&lt;p&gt;Antyxsoft provides the Veeam cloud repository — encrypted transport, throttling, GFS retention and per-job immutability in EU data centres — as a target your existing Veeam console can add today: &lt;a href="https://143470013.hs-sites-eu1.com/products/veeam-backup-draas"&gt;see how Veeam backup and DRaaS works&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fadding-an-offsite-cloud-repository-to-veeam&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Backup</category>
      <pubDate>Sun, 06 Sep 2026 11:49:40 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/adding-an-offsite-cloud-repository-to-veeam</guid>
      <dc:date>2026-09-06T11:49:40Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>The 3-2-1-1-0 backup rule explained | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/the-3-2-1-1-0-rule-and-where-most-estates-fail-it</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/the-3-2-1-1-0-rule-and-where-most-estates-fail-it" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/the-3-2-1-1-0-rule-and-where-most-estates-fail-it.png" alt="The 3-2-1-1-0 backup rule explained | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Most backup estates pass the first three digits of 3-2-1-1-0 and fail the last two. That is not carelessness — the last two are the ones that need a deliberate architectural decision rather than a scheduled job.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Most backup estates pass the first three digits of 3-2-1-1-0 and fail the last two. That is not carelessness — the last two are the ones that need a deliberate architectural decision rather than a scheduled job.&lt;/p&gt; 
&lt;h2&gt;The rule, digit by digit&lt;/h2&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;3 copies&lt;/strong&gt; of the data: production plus two backups. Two copies of a snapshot on the same array is one copy with extra steps.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;2 media types&lt;/strong&gt;, so a single class of failure cannot take both backups. Local disk plus cloud object storage is the common pairing today.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;1 offsite&lt;/strong&gt;, outside the building and outside the failure domain of the primary site.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;1 immutable&lt;/strong&gt; (or offline), so a copy exists that nothing can delete, encrypt or re-date for a defined period.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;0 errors&lt;/strong&gt;, verified — restores actually tested, not merely reported as successful jobs.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;h2&gt;Gap one: offsite is not the same as off-domain&lt;/h2&gt; 
&lt;p&gt;A repository in another building still fails the intent of the rule if it is joined to the same Active Directory and reachable with the same administrator credentials. Ransomware operators look for the backup server first, and a domain-joined repository is part of the environment they have already compromised.&lt;/p&gt; 
&lt;p&gt;The fix is separation, not distance: separate credentials, separate tenancy, and a channel initiated from your side rather than an open share the production network can browse. When you write down your offsite architecture, write down whose credentials can delete data in it. If the answer is "the same account that administers production", you have a copy, not a last resort.&lt;/p&gt; 
&lt;h2&gt;Gap two: nobody has restored anything&lt;/h2&gt; 
&lt;p&gt;The zero in 3-2-1-1-0 is about verification, and it is the most commonly skipped requirement in the whole rule. A job that reports success proves the backup was written. It does not prove the restore point boots, that the database inside it is consistent, or that the person on call knows the procedure.&lt;/p&gt; 
&lt;p&gt;Two things close the gap. Automated recovery verification boots restore points in an isolated sandbox and checks the guest actually came up — cheap, repeatable, and it turns "probably fine" into evidence. Then a scheduled manual restore each quarter: pick a real machine, restore it somewhere harmless, and time how long it took. That number is your true RTO, and it is usually longer than the one in the plan.&lt;/p&gt; 
&lt;h2&gt;The two digits that are not backup problems&lt;/h2&gt; 
&lt;p&gt;Immutability and verification are worth separating out because they answer different questions from the rest of the rule. The first three digits answer "does a copy exist somewhere else?". The last two answer "can it survive an attacker, and does it actually work?" — and those are the questions asked after an incident, by an insurer, or by an auditor reviewing a NIS2 or ISO 27001 control.&lt;/p&gt; 
&lt;h2&gt;A short audit you can run this week&lt;/h2&gt; 
&lt;p&gt;For each protected workload, write down: where the copies are, which media types they sit on, which copy is outside the production credential boundary, how long the immutability window is, and the date of the last verified restore. Any blank cell in that table is the finding — no tooling needed to discover it.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Veeam Backup &amp;amp; DRaaS provides the offsite and immutable legs in EU data centres, with recovery verification and scheduled DR tests so the zero is evidenced rather than assumed — &lt;a href="https://143470013.hs-sites-eu1.com/products/veeam-backup-draas"&gt;see how Veeam backup and DRaaS works&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fthe-3-2-1-1-0-rule-and-where-most-estates-fail-it&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Backup</category>
      <pubDate>Sun, 06 Sep 2026 11:49:04 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/the-3-2-1-1-0-rule-and-where-most-estates-fail-it</guid>
      <dc:date>2026-09-06T11:49:04Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Writing a health check that tells the truth | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/writing-a-health-check-that-tells-the-truth</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/writing-a-health-check-that-tells-the-truth" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/writing-a-health-check-that-tells-the-truth.png" alt="Writing a health check that tells the truth | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;A load balancer is only as good as the question it asks your servers. If that question is "is the web process accepting connections?", you will eventually watch it send traffic to a backend that returns 500 to every request with great enthusiasm and a perfectly healthy TCP port.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;A load balancer is only as good as the question it asks your servers. If that question is "is the web process accepting connections?", you will eventually watch it send traffic to a backend that returns 500 to every request with great enthusiasm and a perfectly healthy TCP port.&lt;/p&gt; 
&lt;p&gt;A useful health check answers a different question: &lt;em&gt;can this instance serve a real request right now?&lt;/em&gt;&lt;/p&gt; 
&lt;h2&gt;What /ping actually proves&lt;/h2&gt; 
&lt;p&gt;A route that returns a static 200 proves the process is running and the network path to it works. That is not nothing — it catches a crashed service, a full disk that stopped the process, a firewall change gone wrong. It is the right check for a TCP-only rule where there is nothing better available.&lt;/p&gt; 
&lt;p&gt;What it does not catch is the common failure: the process is fine and its dependencies are not. A database connection pool that is exhausted, an expired credential, a cache that has gone away, a disk that is full for writes but not reads.&lt;/p&gt; 
&lt;h2&gt;What a readiness endpoint should verify&lt;/h2&gt; 
&lt;p&gt;Check the dependencies this instance needs in order to serve its own traffic, and nothing else:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;A trivial query against the primary database — &lt;code&gt;SELECT 1&lt;/code&gt; through the normal connection pool, so pool exhaustion shows up.&lt;/li&gt; 
 &lt;li&gt;A read and write against the cache or session store, if a request cannot be served without it.&lt;/li&gt; 
 &lt;li&gt;Any local resource with a hard requirement: free disk for writes, a required mount present.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Return 200 when all of them pass, and a 503 when any of them fails. Keep the body small and machine-readable — a JSON object with one key per dependency is enough, and it turns the endpoint into a debugging tool as well as a check.&lt;/p&gt; 
&lt;h2&gt;What it must not verify&lt;/h2&gt; 
&lt;p&gt;Do not check things that are shared across the whole fleet, and do not check things you cannot fix by removing this one instance from rotation.&lt;/p&gt; 
&lt;p&gt;The classic mistake is checking a third-party API. When that provider has a bad afternoon, every backend fails its check at once, the load balancer has nowhere left to send traffic, and a degraded feature becomes a total outage. Report it in monitoring instead; the health check exists to choose between your own instances.&lt;/p&gt; 
&lt;p&gt;The same applies to any expensive check. A health check that runs a real report every ten seconds becomes its own load problem — and a slow health check causes timeouts that look exactly like a failure.&lt;/p&gt; 
&lt;h2&gt;Separate liveness from readiness&lt;/h2&gt; 
&lt;p&gt;Two endpoints, two purposes. &lt;code&gt;/livez&lt;/code&gt; answers "is this process wedged and in need of a restart?" and should touch nothing but itself. &lt;code&gt;/healthz&lt;/code&gt; or &lt;code&gt;/readyz&lt;/code&gt; answers "should this instance receive traffic right now?" and checks dependencies.&lt;/p&gt; 
&lt;p&gt;This distinction also gives you a graceful way out during deploys: make the readiness endpoint return 503 deliberately while the instance drains, without pretending the process is dead.&lt;/p&gt; 
&lt;h2&gt;Intervals, timeouts and thresholds&lt;/h2&gt; 
&lt;p&gt;Three numbers decide how the load balancer behaves, and they trade detection speed against flapping:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;&lt;strong&gt;Interval&lt;/strong&gt; — every 5 to 10 seconds suits most web applications.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Timeout&lt;/strong&gt; — shorter than the interval, and long enough that a normal check under load never trips it. Two to three seconds is typical.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Unhealthy threshold&lt;/strong&gt; — two or three consecutive failures before removal, so a single hiccup does not evict a good server.&lt;/li&gt; 
 &lt;li&gt;&lt;strong&gt;Healthy threshold&lt;/strong&gt; — two consecutive passes before it comes back, so a flapping instance does not repeatedly take a share of traffic.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;With a 10-second interval and a threshold of three, a genuinely broken backend leaves rotation in about thirty seconds and nobody is paged. That is the outcome you are buying.&lt;/p&gt; 
&lt;h2&gt;Test it by breaking it&lt;/h2&gt; 
&lt;p&gt;Stop the database on one instance in staging and watch it leave the pool, then start it again and watch it return. A health check nobody has ever seen fail is a configuration you are hoping about, not one you know.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Load Balancers support TCP and HTTP path checks with configurable intervals and failure and recovery thresholds, and return recovered backends to the pool automatically — &lt;a href="https://143470013.hs-sites-eu1.com/products/load-balancers"&gt;see how Load Balancers work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fwriting-a-health-check-that-tells-the-truth&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Networking</category>
      <pubDate>Sun, 06 Sep 2026 11:27:37 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/writing-a-health-check-that-tells-the-truth</guid>
      <dc:date>2026-09-06T11:27:37Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>From one web server to a load-balanced pair | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/from-one-web-server-to-a-load-balanced-pair</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/from-one-web-server-to-a-load-balanced-pair" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/from-one-web-server-to-a-load-balanced-pair.png" alt="From one web server to a load-balanced pair | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Adding a load balancer takes about four minutes. Adding the second web server behind it is where the work actually is — because a single-server application is allowed to assume things that stop being true the moment requests can land on either machine.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Adding a load balancer takes about four minutes. Adding the second web server behind it is where the work actually is — because a single-server application is allowed to assume things that stop being true the moment requests can land on either machine.&lt;/p&gt; 
&lt;p&gt;There are three assumptions that break, almost every time, in the same order: sessions, uploaded files, and scheduled jobs. Fix those and the pair behaves like one bigger, more boring server.&lt;/p&gt; 
&lt;h2&gt;Sessions: stop keeping them on disk&lt;/h2&gt; 
&lt;p&gt;The default session store in most frameworks is a file in a local temporary directory. With one server that works. With two, a user logs in on web-01, the next request goes to web-02, and they are logged out — intermittently, which is worse than consistently.&lt;/p&gt; 
&lt;p&gt;You have two options and only one of them is a real fix. The real one is to move sessions into somewhere both servers can see: Redis, Memcached, or the database. Sessions are small, short-lived and read on every request, so a small in-memory store on a private address inside your &lt;a href="https://143470013.hs-sites-eu1.com/products/vpc"&gt;VPC&lt;/a&gt; is usually the right shape.&lt;/p&gt; 
&lt;p&gt;The other option is sticky sessions — the load balancer keeps each client on the machine it first hit. It works, and it is the correct choice for an application you cannot change. But it makes your traffic distribution uneven, it means a host failure logs those users out anyway, and it quietly blocks the rolling deploys you added the second server to get. Treat it as a bridge, not a destination.&lt;/p&gt; 
&lt;h2&gt;Uploads: the local filesystem is now a lie&lt;/h2&gt; 
&lt;p&gt;The second thing to break is user-uploaded content. A profile photo written to &lt;code&gt;/var/www/uploads&lt;/code&gt; on web-01 does not exist on web-02, so it appears and disappears depending on which backend serves the page.&lt;/p&gt; 
&lt;p&gt;Move that content to &lt;a href="https://143470013.hs-sites-eu1.com/products/object-storage"&gt;object storage&lt;/a&gt; and serve it from there. This is a bigger change than sessions — it touches your upload path, your URLs and possibly your image processing — but it is the change that makes the machines genuinely interchangeable. Anything you can throw away and rebuild in ten minutes is a machine that no longer needs babysitting.&lt;/p&gt; 
&lt;p&gt;If you cannot move uploads yet, shared network storage is the interim answer. It is slower and it reintroduces a single point of failure, but it is honest about what it is.&lt;/p&gt; 
&lt;h2&gt;Cron: exactly once, not once per server&lt;/h2&gt; 
&lt;p&gt;Copy the crontab to the second server and every nightly job now runs twice. Sometimes that is harmless. Sometimes it sends every customer two invoices.&lt;/p&gt; 
&lt;p&gt;Three patterns work, in increasing order of effort:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Designate one instance as the scheduler and run cron only there. Simple, and fine as long as you remember it exists when that instance is rebuilt.&lt;/li&gt; 
 &lt;li&gt;Take a lock before the job body runs — a row in the database, a key in Redis with a TTL. Every server has the same crontab, only one wins.&lt;/li&gt; 
 &lt;li&gt;Move the work onto a queue with a single consumer group, so scheduling and execution are separate concerns.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Whichever you pick, write it down next to the crontab. This is the failure that reappears two years later when someone adds a third server.&lt;/p&gt; 
&lt;h2&gt;Then the load balancer part&lt;/h2&gt; 
&lt;p&gt;With those three fixed, the actual load balancing is configuration. Create the load balancer, point a forwarding rule at your backend port, target the instances by tag rather than by name so the pool follows your fleet, and give it a health check that verifies more than "the process is running".&lt;/p&gt; 
&lt;p&gt;Then move DNS to the load balancer's address and let the old server keep serving until the TTL expires. Lower the record's TTL a day before you cut over — it is the cheapest possible insurance.&lt;/p&gt; 
&lt;h2&gt;The checklist&lt;/h2&gt; 
&lt;p&gt;Sessions in a shared store. Uploads in object storage. Cron running exactly once. Health check that touches the database. Backends targeted by tag. Firewall rules so backends accept application traffic only from the load balancer. DNS TTL lowered before the switch.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Load Balancers distribute HTTP, HTTPS and TCP traffic across your instances with active health checks, SSL termination and tag-based pools, for one flat monthly price — &lt;a href="https://143470013.hs-sites-eu1.com/products/load-balancers"&gt;see how Load Balancers work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Ffrom-one-web-server-to-a-load-balanced-pair&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Networking</category>
      <pubDate>Sun, 06 Sep 2026 11:27:01 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/from-one-web-server-to-a-load-balanced-pair</guid>
      <dc:date>2026-09-06T11:27:01Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Rolling deployments behind a load balancer | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/rolling-deployments-behind-a-load-balancer</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/rolling-deployments-behind-a-load-balancer" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/rolling-deployments-behind-a-load-balancer.png" alt="Rolling deployments behind a load balancer | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Once there are two or more instances behind a load balancer, the maintenance window stops being necessary. You release to one backend at a time, and the pool serves traffic throughout. The mechanics take an afternoon to get right and then you stop deploying at midnight.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Once there are two or more instances behind a load balancer, the maintenance window stops being necessary. You release to one backend at a time, and the pool serves traffic throughout. The mechanics take an afternoon to get right and then you stop deploying at midnight.&lt;/p&gt; 
&lt;h2&gt;The shape of a rolling deploy&lt;/h2&gt; 
&lt;p&gt;For each backend, in turn: stop sending it new requests, let the requests it already has finish, deploy, wait for its health check to pass, put it back. Move to the next one only after the previous instance is healthy again.&lt;/p&gt; 
&lt;p&gt;The important property is that the pool never loses more capacity than one instance at a time — which means the remaining instances must be able to carry peak traffic without it. A load-balanced pair running at 60% each is not actually redundant; it is two servers that will both fall over politely.&lt;/p&gt; 
&lt;h2&gt;Draining is the whole trick&lt;/h2&gt; 
&lt;p&gt;Removing a backend abruptly cuts every request it was serving. Draining means the load balancer stops choosing it for new connections while existing ones complete.&lt;/p&gt; 
&lt;p&gt;The clean way to do that from inside the application is the readiness endpoint: on shutdown signal, start returning 503 from &lt;code&gt;/healthz&lt;/code&gt;, keep serving in-flight requests normally, and only then exit. The load balancer notices within an interval or two and stops routing to it. This is why the failure threshold matters in both directions — a threshold of three at a ten-second interval means up to thirty seconds of new requests still arriving after you begin the drain.&lt;/p&gt; 
&lt;p&gt;Then let the process finish what it started. Your web server's graceful shutdown period should be longer than your slowest normal request, and your deploy script should wait for the process to exit rather than killing it. Requests dropped during a deploy are almost always a shutdown that was faster than the traffic.&lt;/p&gt; 
&lt;h2&gt;Keep-alive and sticky sessions&lt;/h2&gt; 
&lt;p&gt;Two settings quietly undo good draining.&lt;/p&gt; 
&lt;p&gt;Keep-alive connections outlive individual requests, so a client can keep reusing a connection to an instance you are trying to retire. Keep the backend's keep-alive timeout modest — a few seconds — so connections recycle quickly during a rollout.&lt;/p&gt; 
&lt;p&gt;Sticky sessions pin a client to one backend, so draining that backend means those users are moved to a machine that does not have their session unless the session store is shared. If you are running rolling deploys with stickiness on, move sessions into a shared store first; otherwise every release logs a slice of your users out.&lt;/p&gt; 
&lt;h2&gt;Migrations are the hard part, not the deploy&lt;/h2&gt; 
&lt;p&gt;During a rolling deploy, two versions of the application are live at once. The database schema has to be compatible with both, which means splitting the change:&lt;/p&gt; 
&lt;ul&gt; 
 &lt;li&gt;Add the new column or table, deploy code that writes to both old and new, and backfill.&lt;/li&gt; 
 &lt;li&gt;Deploy code that reads from the new shape.&lt;/li&gt; 
 &lt;li&gt;Only then remove the old column, in a later release.&lt;/li&gt; 
&lt;/ul&gt; 
&lt;p&gt;Renames and &lt;code&gt;NOT NULL&lt;/code&gt; constraints added in one step are the two that bite. If a change genuinely cannot be made backwards-compatible, that is the case for a short blue-green cutover rather than a rolling release.&lt;/p&gt; 
&lt;h2&gt;When to go blue-green instead&lt;/h2&gt; 
&lt;p&gt;Blue-green runs two complete fleets and shifts traffic between them: the release is a single change of which pool the load balancer targets, and the rollback is the same change in reverse. It costs double capacity for the duration and it needs the same backwards-compatible data work if both fleets talk to one database, but it turns a rollback into seconds.&lt;/p&gt; 
&lt;p&gt;Rolling is the right default for routine releases. Blue-green earns its cost for risky ones — a framework upgrade, a rewritten checkout, anything where "undo" needs to be immediate.&lt;/p&gt; 
&lt;h2&gt;Prove it with a load test&lt;/h2&gt; 
&lt;p&gt;Run a modest constant load against the public address and perform a full rollout. If the error count is zero and latency stays inside its normal band, the deploy is genuinely zero-downtime. If it is not, you have learned which of draining, keep-alive or shutdown timing is wrong — before a customer does.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Load Balancers give you active health checks, tag-targeted backend pools and round robin or least connections distribution, so rolling and blue-green releases need no maintenance window — &lt;a href="https://143470013.hs-sites-eu1.com/products/load-balancers"&gt;see how Load Balancers work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Frolling-deployments-behind-a-load-balancer&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Networking</category>
      <pubDate>Sun, 06 Sep 2026 11:26:25 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/rolling-deployments-behind-a-load-balancer</guid>
      <dc:date>2026-09-06T11:26:25Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>A baseline firewall policy for a three-tier app | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/baseline-firewall-policy-three-tier-application</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/baseline-firewall-policy-three-tier-application" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/baseline-firewall-policy-three-tier-application.png" alt="A baseline firewall policy for a three-tier app | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Most environments do not have a firewall problem. They have a firewall inventory problem: forty rules accumulated over two years, three of which nobody can explain, and no single place that answers the question "what does this server accept?"&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Most environments do not have a firewall problem. They have a firewall inventory problem: forty rules accumulated over two years, three of which nobody can explain, and no single place that answers the question "what does this server accept?"&lt;/p&gt; 
&lt;p&gt;A baseline fixes that by starting from a policy shape rather than from incidents. Here is the one we hand to customers building a normal three-tier application — a load balancer, some web and application instances, a database — and the two rules that are almost always wider than the person who wrote them intended.&lt;/p&gt; 
&lt;h2&gt;Group by role before you write a single rule&lt;/h2&gt; 
&lt;p&gt;The unit of policy is the role, not the machine. Tag every instance with what it does: &lt;code&gt;web&lt;/code&gt;, &lt;code&gt;app&lt;/code&gt;, &lt;code&gt;database&lt;/code&gt;, &lt;code&gt;bastion&lt;/code&gt;. Attach one firewall per tag. This is the whole reason the baseline stays readable at fifty instances — new machines inherit policy the moment they are tagged, and retiring one leaves nothing behind in a rule list.&lt;/p&gt; 
&lt;p&gt;It also lets rules reference other tags as their source. "The database accepts connections from the application tier" becomes a single line that stays true when the application tier is rebuilt with different addresses, instead of a maintained list of IPs that drifts out of date silently.&lt;/p&gt; 
&lt;h2&gt;The baseline, tag by tag&lt;/h2&gt; 
&lt;p&gt;&lt;strong&gt;tag: web.&lt;/strong&gt; Inbound TCP 443 from 0.0.0.0/0 and ::/0. Inbound TCP 80 from the same, if you redirect to HTTPS rather than dropping plaintext outright. Inbound TCP 22 from &lt;code&gt;tag: bastion&lt;/code&gt; only. Everything else dropped. Outbound: TCP 8080 to &lt;code&gt;tag: app&lt;/code&gt;, TCP 443 to your package mirror, UDP 53 to your resolver, and nothing else.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;tag: app.&lt;/strong&gt; No inbound from the internet at all. Inbound TCP 8080 from &lt;code&gt;tag: web&lt;/code&gt;. Inbound TCP 22 from &lt;code&gt;tag: bastion&lt;/code&gt;. Outbound TCP 5432 (or 3306) to &lt;code&gt;tag: database&lt;/code&gt;, TCP 443 to the specific third-party APIs the application calls, UDP 53 to the resolver. Everything else dropped.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;tag: database.&lt;/strong&gt; Inbound the database port from &lt;code&gt;tag: app&lt;/code&gt; only. Inbound TCP 22 from &lt;code&gt;tag: bastion&lt;/code&gt;. Outbound to the replica and to your backup target, nothing more. A database has no business initiating connections to the internet.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;tag: bastion.&lt;/strong&gt; Inbound TCP 22 from named office and VPN ranges — never from 0.0.0.0/0. Outbound TCP 22 to the private tags. This is the one host whose exposure you should be able to recite from memory.&lt;/p&gt; 
&lt;h2&gt;The two rules that are always too permissive&lt;/h2&gt; 
&lt;p&gt;The first is SSH from anywhere. It appears during the first hour of a project, when there is no bastion yet and someone needs to get in, and then it stays. Keys make it survivable, not safe: an open 22 means every credential leak, every stolen laptop and every unpatched OpenSSH advisory is directly exploitable rather than one hop removed. Put the bastion in early, even if the bastion is a single small instance you stop when you are not using it.&lt;/p&gt; 
&lt;p&gt;The second is unrestricted outbound. Almost every environment allows all egress because it is what happens if you write no outbound rules at all, and because restricting it means finding out what your application actually talks to. That discovery is the point. A compromised process with unrestricted egress can reach a command-and-control host, a mining pool, or an attacker's bucket; the same process with four allowed destinations fails at the first attempt and shows up in the logs.&lt;/p&gt; 
&lt;h2&gt;What to leave out&lt;/h2&gt; 
&lt;p&gt;Resist per-instance exceptions. The moment a rule exists for one machine rather than one role, the baseline stops being reviewable — and the exception outlives the reason for it. If a machine genuinely needs different policy, it has a different role: give it a tag.&lt;/p&gt; 
&lt;p&gt;Resist port ranges too. &lt;code&gt;30000-32767&lt;/code&gt; in an inbound rule is not a policy, it is a shrug. If a service needs a range, put a load balancer in front of it and allow that instead.&lt;/p&gt; 
&lt;h2&gt;How to verify it&lt;/h2&gt; 
&lt;p&gt;Read the policy back per tag and ask, for each rule, which application behaviour breaks if you delete it. Any rule with no answer goes. Then test from the outside: from a machine with no tag, try to reach the database port, the application port and SSH on each tier. The only thing that should answer from the internet is the load balancer.&lt;/p&gt; 
&lt;p&gt;Do that once when you build the baseline, and again after any change made during an incident — the shortcut added at 03:00 to restore service is the single most common reason a correct policy stops being correct.&lt;/p&gt; 
&lt;h2&gt;The short version&lt;/h2&gt; 
&lt;p&gt;One firewall per role, tags as rule sources, deny by default in both directions. SSH only from a bastion, egress restricted to named destinations, no per-instance exceptions and no port ranges. Then delete every rule you cannot justify out loud.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Cloud Firewalls are stateful, agentless and included with every instance at no extra charge, with unlimited firewalls and rules — &lt;a href="https://143470013.hs-sites-eu1.com/products/cloud-firewalls"&gt;see how Cloud Firewalls work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fbaseline-firewall-policy-three-tier-application&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>security</category>
      <pubDate>Fri, 04 Sep 2026 15:01:08 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/baseline-firewall-policy-three-tier-application</guid>
      <dc:date>2026-09-04T15:01:08Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Locking down SSH without locking yourself out | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/locking-down-ssh-without-locking-yourself-out</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/locking-down-ssh-without-locking-yourself-out" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/locking-down-ssh-without-locking-yourself-out.png" alt="Locking down SSH without locking yourself out | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Restricting SSH is the highest-value firewall change most environments can make, and the one most likely to end with an engineer locked out of production at an inconvenient hour. Both facts have the same cause: the change removes the path you are currently using to make it.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Restricting SSH is the highest-value firewall change most environments can make, and the one most likely to end with an engineer locked out of production at an inconvenient hour. Both facts have the same cause: the change removes the path you are currently using to make it.&lt;/p&gt; 
&lt;p&gt;The technique is not complicated. The order is what matters.&lt;/p&gt; 
&lt;h2&gt;Decide what the way in is&lt;/h2&gt; 
&lt;p&gt;Before touching a rule, pick the model you are moving to. There are three that work.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;A bastion host.&lt;/strong&gt; One small instance accepts SSH from named ranges; every other machine accepts SSH from the bastion's tag only. Cheap, easy to reason about, and the audit trail is in one place. The bastion is a hop, not a workstation — no application software, no long-lived agents, and a short list of accounts.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;A VPN into the VPC.&lt;/strong&gt; Site-to-site or client VPN, with SSH allowed from the VPN range. Better when several people need private access to many services, not just SSH, and it removes the public port entirely.&lt;/p&gt; 
&lt;p&gt;&lt;strong&gt;Office ranges only.&lt;/strong&gt; Adequate when the team works from fixed addresses and there are few servers. It fails the moment someone needs to fix something from a train, so pair it with a documented break-glass path.&lt;/p&gt; 
&lt;h2&gt;The order that keeps you in&lt;/h2&gt; 
&lt;p&gt;Work from additive changes to restrictive ones, and verify the new path before you remove the old one.&lt;/p&gt; 
&lt;p&gt;First, build the new path: launch the bastion or bring up the VPN, tag it, and allow SSH to the private tags from that tag or range. At this point both the new path and the existing open port work.&lt;/p&gt; 
&lt;p&gt;Second, verify it from a session you did not open through the old path. Open a second terminal, connect through the bastion — &lt;code&gt;ssh -J bastion app-01&lt;/code&gt; — and run something. Do not skip this because the config looks right. A wrong key on the bastion, a missing agent-forwarding setting or an SSH daemon bound to the wrong interface all look identical to a correct setup until you try.&lt;/p&gt; 
&lt;p&gt;Third, and only then, narrow the old rule. Change inbound 22 on the private tags from 0.0.0.0/0 to &lt;code&gt;tag: bastion&lt;/code&gt;. Keep your verified session open while you do it — a stateful firewall does not tear down established connections when a rule changes, so you keep a live shell to undo from if something is wrong.&lt;/p&gt; 
&lt;p&gt;Fourth, confirm the negative. From a machine outside, try to reach 22 on an application instance directly. It should time out. If it refuses instead of timing out, something in front is answering and you have not restricted what you think you have.&lt;/p&gt; 
&lt;h2&gt;Break-glass, planned in advance&lt;/h2&gt; 
&lt;p&gt;Every restriction needs a documented way back. What you must not do is leave a permanently open port "just in case" — that is the rule you were trying to remove.&lt;/p&gt; 
&lt;p&gt;The workable options: console or serial access through the provider portal, which needs no network path at all and is the reason to check your instance password is in the password manager before you need it; a second bastion in another region, stopped, that you start only during an incident; or an emergency firewall rule you can apply from the portal or API in seconds, with a note that says who may apply it and when it must be removed.&lt;/p&gt; 
&lt;p&gt;Test the break-glass path once, deliberately, on a machine that does not matter. An untested emergency path is a story you tell yourself, not a plan.&lt;/p&gt; 
&lt;h2&gt;What the firewall does not solve&lt;/h2&gt; 
&lt;p&gt;Network policy limits who can reach the port. It does not fix what happens after they do. Keep the host side boring: keys only with &lt;code&gt;PasswordAuthentication no&lt;/code&gt;, no root login, one account per human, and keys with a passphrase so a stolen laptop is not a stolen server.&lt;/p&gt; 
&lt;p&gt;Fail2ban and moving SSH to a high port become largely pointless once the port is not exposed to the internet — the noise they were suppressing no longer arrives. Spend the time on key hygiene instead.&lt;/p&gt; 
&lt;h2&gt;The short version&lt;/h2&gt; 
&lt;p&gt;Choose bastion, VPN or fixed ranges. Build the new path, verify it from a fresh session, then narrow the old rule while holding a live shell. Confirm the port really is unreachable from outside, and write down a break-glass path you have actually tested.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Cloud Firewalls let you allow SSH from a bastion tag or a named range and drop everything else, applied at the platform edge with nothing to install in the guest — &lt;a href="https://143470013.hs-sites-eu1.com/products/cloud-firewalls"&gt;see how Cloud Firewalls work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Flocking-down-ssh-without-locking-yourself-out&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>security</category>
      <category>Operations</category>
      <pubDate>Fri, 04 Sep 2026 15:00:27 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/locking-down-ssh-without-locking-yourself-out</guid>
      <dc:date>2026-09-04T15:00:27Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Egress filtering: why outbound rules matter | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/egress-filtering-outbound-rules</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/egress-filtering-outbound-rules" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/egress-filtering-outbound-rules.png" alt="Egress filtering: why outbound rules matter | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Nearly every firewall policy is written as if attacks only arrive. Inbound rules are argued over line by line; outbound is left at "allow all" because that is what happens when you write nothing.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Nearly every firewall policy is written as if attacks only arrive. Inbound rules are argued over line by line; outbound is left at "allow all" because that is what happens when you write nothing.&lt;/p&gt; 
&lt;p&gt;But the inbound rules only decide whether an intrusion starts. The outbound rules decide what it can do afterwards — and afterwards is where the cost is.&lt;/p&gt; 
&lt;h2&gt;What needs to leave, and what does not&lt;/h2&gt; 
&lt;p&gt;Once a process on your server is executing code it should not be, it needs the network to be worth anything to the attacker. Stolen data has to be uploaded somewhere. A dropper has to fetch its second stage. A mining payload has to reach a pool. A foothold has to check in with a control channel and wait for instructions.&lt;/p&gt; 
&lt;p&gt;All four are outbound connections to destinations your application has no legitimate reason to contact. An egress policy that lists the destinations your application does need turns every one of them into a failed connection and a log line, on a schedule the attacker does not control.&lt;/p&gt; 
&lt;p&gt;It also catches the boring failures. A misconfigured backup job writing to the wrong bucket, a library phoning home with telemetry, a staging instance pointed at the production database: all show up as denied egress before they become an incident.&lt;/p&gt; 
&lt;h2&gt;Building the allow list without breaking production&lt;/h2&gt; 
&lt;p&gt;The reason egress stays open is that nobody knows what the application talks to. Find out empirically rather than from documentation.&lt;/p&gt; 
&lt;p&gt;Start with what you know a normal application tier needs: DNS to your resolver, TCP 443 to your package mirror and container registry, the database port to the database tag, and the specific third-party APIs the code calls — payment provider, mail relay, object storage endpoint. That list is usually four to eight destinations, and it is shorter than people expect.&lt;/p&gt; 
&lt;p&gt;Then add rules for what you find. Watch denied outbound connections in the log for a full business cycle — a week, including whatever runs at month end — before you tighten anything in production. Nightly jobs, certificate renewals and update checks only appear when they run, and a quarterly report generator that reaches an external service will not show up in a Tuesday afternoon sample.&lt;/p&gt; 
&lt;p&gt;Prefer tags and internal ranges over hostnames where you can. A rule that says "to &lt;code&gt;tag: database&lt;/code&gt; on 5432" stays correct when the database is rebuilt; an allow list of IP addresses for a SaaS API will not, because the provider changes them without telling you. For those, allow the port to a narrow set and accept that you will revisit it.&lt;/p&gt; 
&lt;h2&gt;Stateful rules mean less work than you fear&lt;/h2&gt; 
&lt;p&gt;A common objection is that outbound rules will break replies to inbound traffic. They do not. A stateful firewall tracks sessions: a request allowed inbound has its response allowed out automatically, with no counterpart rule. You are writing policy for connections your servers &lt;em&gt;initiate&lt;/em&gt;, which is a much smaller set than all traffic.&lt;/p&gt; 
&lt;p&gt;The corollary is that your outbound list is about the application's dependencies, not its users. That is the list your team should be able to write down anyway.&lt;/p&gt; 
&lt;h2&gt;Where to be strictest&lt;/h2&gt; 
&lt;p&gt;Not every tier deserves the same rigour. Rank by what an attacker would want.&lt;/p&gt; 
&lt;p&gt;The data tier should be close to silent: replication, backup target, resolver, nothing else. A database initiating an HTTPS connection to the internet is either a misconfiguration or an exfiltration in progress, and there is no third option.&lt;/p&gt; 
&lt;p&gt;The application tier is where the allow list lives, and where the work is. The web tier usually needs even less than the application tier — package mirror, resolver, and the application tag it forwards to.&lt;/p&gt; 
&lt;p&gt;Anything holding regulated data — cardholder scope, health records, personal data under a processing agreement — gets an explicit outbound policy for a second reason: it is evidence. "Outbound restricted to four approved endpoints, rule set exported monthly" is a control an auditor can test. "Allow all" is a finding.&lt;/p&gt; 
&lt;h2&gt;The short version&lt;/h2&gt; 
&lt;p&gt;Inbound rules decide whether an intrusion starts; outbound rules decide what it achieves. Build the allow list from a week of denied-connection logs rather than from documentation, use tags for internal destinations, and be strictest on the data tier. Stateful rules mean replies to allowed sessions need no rule of their own — you are only describing what your servers dial out to.&lt;/p&gt; 
&lt;p&gt;Antyxsoft Cloud Firewalls apply inbound and outbound rules together in one stateful policy, attached to a tag rather than a list of servers — &lt;a href="https://143470013.hs-sites-eu1.com/products/cloud-firewalls"&gt;see how Cloud Firewalls work&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fegress-filtering-outbound-rules&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>compliance</category>
      <category>security</category>
      <pubDate>Fri, 04 Sep 2026 14:59:38 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/egress-filtering-outbound-rules</guid>
      <dc:date>2026-09-04T14:59:38Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
    <item>
      <title>Designing a VPC: address ranges and subnets | Antyxsoft Cloud</title>
      <link>https://www.antyxsoft.io/blog/designing-a-vpc-address-ranges-and-subnets</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt; 
 &lt;a href="https://www.antyxsoft.io/blog/designing-a-vpc-address-ranges-and-subnets" title="" class="hs-featured-image-link"&gt; &lt;img src="https://www.antyxsoft.io/hubfs/blog-covers/designing-a-vpc-address-ranges-and-subnets.png" alt="Designing a VPC: address ranges and subnets | Antyxsoft Cloud" class="hs-featured-image" style="width:auto !important; max-width:50%; float:left; margin:0 15px 15px 0;"&gt; &lt;/a&gt; 
&lt;/div&gt; 
&lt;p&gt;Renumbering a production network is one of the few infrastructure jobs with no clean path. Every firewall rule, every hard-coded host, every VPN policy and half the monitoring configuration references the old addresses. It is entirely avoidable, and the decision that avoids it takes about twenty minutes at the start of a project.&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;Renumbering a production network is one of the few infrastructure jobs with no clean path. Every firewall rule, every hard-coded host, every VPN policy and half the monitoring configuration references the old addresses. It is entirely avoidable, and the decision that avoids it takes about twenty minutes at the start of a project.&lt;/p&gt; 
&lt;p&gt;Address space is the one part of a VPC that is genuinely hard to change later. Everything else — instances, subnets, rules, gateways — is cheap to rebuild.&lt;/p&gt; 
&lt;h2&gt;Pick a /16 and stop optimising&lt;/h2&gt; 
&lt;p&gt;Private address space is free. A 10.x.0.0/16 gives you 65 536 addresses and 253 usable /24 subnets, which is more than almost any single environment will need, and it costs nothing to reserve.&lt;/p&gt; 
&lt;p&gt;The mistake is being frugal. A /24 for the whole VPC looks tidy until the day a Kubernetes cluster wants a large pod range, or a second availability zone needs its own subnets, and there is nowhere to put them. Then you are renumbering.&lt;/p&gt; 
&lt;p&gt;Two things to check before you commit to a range. First, that it does not overlap anything you might ever connect to: your office LAN, a colocation rack, a partner network, or the ranges another cloud provider hands out by default. Overlapping ranges are the single most common reason a site-to-site VPN cannot be made to work — routing becomes ambiguous and no amount of tunnel configuration fixes it. Second, that you have not picked one of the ranges everyone else picks. 192.168.0.0/24 and 192.168.1.0/24 are what every consumer router uses; 10.0.0.0/24 is what half the tutorials use. Choose something less collision-prone from the middle of 10.0.0.0/8 — 10.42.0.0/16, say — and write down why.&lt;/p&gt; 
&lt;h2&gt;One /16 per environment, not per project&lt;/h2&gt; 
&lt;p&gt;Production, staging and development each want their own VPC and their own /16. That gives complete isolation by default, lets you peer selectively where it is genuinely needed, and makes the firewall rules readable: a rule that mentions 10.42.x.x is obviously production.&lt;/p&gt; 
&lt;p&gt;Resist the temptation to give every project its own VPC. Peering meshes grow quadratically, routing tables become impossible to review, and shared services end up duplicated. Environment is the right axis of separation; projects are subnets and rules inside one.&lt;/p&gt; 
&lt;h2&gt;Subnet layout: tiers, then zones&lt;/h2&gt; 
&lt;p&gt;Inside the /16, carve /24 subnets on a predictable grid so anyone reading an address knows where it sits. A layout that works for most multi-tier applications:&lt;/p&gt; 
&lt;p&gt;10.42.1.0/24 for the public tier — load balancers, a bastion, anything that needs to be reachable from the internet. 10.42.2.0/24 for the application tier, with no public addresses at all. 10.42.3.0/24 for the data tier, with no route to the internet in either direction. Then leave a deliberate gap and start the second availability zone at 10.42.11.0/24, 10.42.12.0/24, 10.42.13.0/24, so the last octet's tens digit tells you the zone and the units digit tells you the tier.&lt;/p&gt; 
&lt;p&gt;Reserve blocks for things that are not there yet. 10.42.50.0/20 for Kubernetes pod and service ranges — clusters need far more addresses than instances do, and CNI plugins want a contiguous block. 10.42.100.0/24 for VPN clients. 10.42.200.0/24 for management: monitoring collectors, backup proxies, jump hosts.&lt;/p&gt; 
&lt;p&gt;A /24 per subnet is the right default even when you expect eight machines. The addresses cost nothing, and a uniform mask makes every rule and every route easier to read than a mix of /26s and /28s sized to last year's headcount.&lt;/p&gt; 
&lt;h2&gt;What goes in the document&lt;/h2&gt; 
&lt;p&gt;Write the allocation down before you build it, in a table with four columns: CIDR, purpose, route to internet yes or no, and who can reach it. That table is the design. It is also the thing an auditor asks for, the thing a new engineer reads first, and the thing you check against reality once a quarter.&lt;/p&gt; 
&lt;p&gt;Include the ranges you have deliberately reserved but not yet used. An unlabelled gap gets filled by whoever needs an address next; a gap labelled reserved for Kubernetes survives.&lt;/p&gt; 
&lt;h2&gt;Routing and gateways, briefly&lt;/h2&gt; 
&lt;p&gt;Only the public subnet needs a route to an internet gateway. The application tier reaches out through a NAT path if it needs package updates or third-party APIs, and the data tier ideally reaches nothing at all — which is both a security posture and a useful constraint, because it forces backup and update paths to be explicit rather than accidental.&lt;/p&gt; 
&lt;p&gt;Keep route tables per tier rather than one shared table with exceptions. A tier whose route table has exactly two entries is auditable at a glance.&lt;/p&gt; 
&lt;h2&gt;The short version&lt;/h2&gt; 
&lt;p&gt;Take a /16 per environment, from a range that overlaps nothing you might connect to and that is not the default everyone else uses. Lay out /24 subnets on a grid where the address tells you the tier and the zone, reserve blocks for Kubernetes, VPN and management before you need them, and write the allocation table before you build. Twenty minutes at the start; no renumbering at the end.&lt;/p&gt; 
&lt;p&gt;Antyxsoft VPC lets you define your own address ranges, subnets and routing tables, at no additional charge per network — &lt;a href="https://143470013.hs-sites-eu1.com/products/vpc"&gt;see how VPC works&lt;/a&gt;.&lt;/p&gt;  
&lt;img src="https://track-eu1.hubspot.com/__ptq.gif?a=143470013&amp;amp;k=14&amp;amp;r=https%3A%2F%2Fwww.antyxsoft.io%2Fblog%2Fdesigning-a-vpc-address-ranges-and-subnets&amp;amp;bu=https%253A%252F%252Fwww.antyxsoft.io%252Fblog&amp;amp;bvt=rss" alt="" width="1" height="1" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important; "&gt;</content:encoded>
      <category>Networking</category>
      <pubDate>Thu, 03 Sep 2026 20:15:12 GMT</pubDate>
      <guid>https://www.antyxsoft.io/blog/designing-a-vpc-address-ranges-and-subnets</guid>
      <dc:date>2026-09-03T20:15:12Z</dc:date>
      <dc:creator>Antyxsoft Cloud</dc:creator>
    </item>
  </channel>
</rss>
