<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: overnight.host</title>
    <description>The latest articles on DEV Community by overnight.host (@overnighthost).</description>
    <link>https://dev.to/overnighthost</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3976394%2F8db407ee-a48d-41ca-a769-7d4279957f6d.png</url>
      <title>DEV Community: overnight.host</title>
      <link>https://dev.to/overnighthost</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/overnighthost"/>
    <language>en</language>
    <item>
      <title>Scheduling jobs on a VPS with cron — a practical guide</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Wed, 24 Jun 2026 07:16:17 +0000</pubDate>
      <link>https://dev.to/overnighthost/scheduling-jobs-on-a-vps-with-cron-a-practical-guide-5322</link>
      <guid>https://dev.to/overnighthost/scheduling-jobs-on-a-vps-with-cron-a-practical-guide-5322</guid>
      <description>&lt;p&gt;One of the first things you want from your own server is for it to &lt;em&gt;do things while you sleep&lt;/em&gt;: run a backup at 3 a.m., restart a flaky service nightly, pull fresh data every fifteen minutes. On Linux, the oldest and most reliable tool for that is &lt;code&gt;cron&lt;/code&gt;. It is on practically every VPS already, it needs no daemon you have to install, and once you understand the five-field syntax it stops being intimidating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five fields
&lt;/h2&gt;

&lt;p&gt;A cron schedule is five space-separated fields, followed by the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;┌─ &lt;span class="n"&gt;minute&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;59&lt;/span&gt;)
│ ┌─ &lt;span class="n"&gt;hour&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;23&lt;/span&gt;)
│ │ ┌─ &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;-&lt;span class="m"&gt;31&lt;/span&gt;)
│ │ │ ┌─ &lt;span class="n"&gt;month&lt;/span&gt; (&lt;span class="m"&gt;1&lt;/span&gt;-&lt;span class="m"&gt;12&lt;/span&gt;)
│ │ │ │ ┌─ &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;week&lt;/span&gt; (&lt;span class="m"&gt;0&lt;/span&gt;-&lt;span class="m"&gt;7&lt;/span&gt;, &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;both&lt;/span&gt; &lt;span class="n"&gt;Sunday&lt;/span&gt;)
│ │ │ │ │
* * * * *  &lt;span class="n"&gt;command&lt;/span&gt;-&lt;span class="n"&gt;to&lt;/span&gt;-&lt;span class="n"&gt;run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;*&lt;/code&gt; means "every value." So &lt;code&gt;*/15 * * * *&lt;/code&gt; is "every 15 minutes," &lt;code&gt;0 3 * * *&lt;/code&gt; is "03:00 every day," and &lt;code&gt;0 9 * * 1&lt;/code&gt; is "09:00 every Monday." That is 90% of what you will ever write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editing your crontab
&lt;/h2&gt;

&lt;p&gt;Each user has their own crontab. Edit yours with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;      &lt;span class="c"&gt;# opens your personal crontab in $EDITOR&lt;/span&gt;
crontab &lt;span class="nt"&gt;-l&lt;/span&gt;      &lt;span class="c"&gt;# list current jobs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a line and save. For example, a quarter-hourly sync and a nightly backup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*/15 * * * * /usr/bin/curl -fsS https://api.example.com/sync &amp;gt;&amp;gt; /var/log/sync.log 2&amp;gt;&amp;amp;1
0 3 * * *    /home/deploy/backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run something as root (system maintenance, service restarts), use &lt;code&gt;sudo crontab -e&lt;/code&gt;, or drop a file into &lt;code&gt;/etc/cron.d/&lt;/code&gt; with an extra username field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things that trip everyone up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Cron has almost no &lt;code&gt;PATH&lt;/code&gt;.&lt;/strong&gt; Inside cron, &lt;code&gt;$PATH&lt;/code&gt; is minimal, so a bare &lt;code&gt;python&lt;/code&gt; or &lt;code&gt;node&lt;/code&gt; often "works on the command line but not in cron." Always use absolute paths (&lt;code&gt;/usr/bin/python3&lt;/code&gt;), or set &lt;code&gt;PATH=&lt;/code&gt; at the top of the crontab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Output goes to mail, or nowhere.&lt;/strong&gt; If a job prints anything and you do not redirect it, cron tries to email it locally and you never see it. Redirect both streams to a log so failures are visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 3 * * * /home/deploy/backup.sh &amp;gt;&amp;gt; /var/log/backup.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; is the important half — it captures errors, not just normal output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Timezone.&lt;/strong&gt; Cron uses the server's system clock. On a multi-region setup your VPS might be on UTC, not your local time. Check with &lt;code&gt;timedatectl&lt;/code&gt;, and either do the mental math or set &lt;code&gt;CRON_TZ=Europe/Berlin&lt;/code&gt; (or your zone) at the top of the crontab so &lt;code&gt;0 3 * * *&lt;/code&gt; means what you think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't let jobs pile up
&lt;/h2&gt;

&lt;p&gt;If a job can run longer than its interval (a backup that occasionally takes 20 minutes on a 15-minute schedule), guard it with &lt;code&gt;flock&lt;/code&gt; so a slow run never overlaps the next one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*/15 * * * * /usr/bin/flock -n /tmp/sync.lock /home/deploy/sync.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-n&lt;/code&gt; means "if the lock is held, skip this run rather than queue." Overlapping cron jobs are a classic cause of a server quietly grinding itself to a halt.&lt;/p&gt;

&lt;h2&gt;
  
  
  When cron is the wrong tool
&lt;/h2&gt;

&lt;p&gt;For sub-minute scheduling, jobs with dependencies, or anything that needs retries and a dashboard, reach for &lt;code&gt;systemd&lt;/code&gt; timers or a proper job runner instead. Cron is perfect for simple, independent, time-based tasks — and most of what a small server needs is exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick way to get the syntax right
&lt;/h2&gt;

&lt;p&gt;If you would rather not count asterisks in your head, we keep a free &lt;a href="https://overnight.host/tools/cron-expression-generator/" rel="noopener noreferrer"&gt;cron expression generator&lt;/a&gt; that turns plain-English schedules into the exact five-field line (and explains an existing one back to you). It is one of a handful of small, free tools we host on overnight.host — no signup, just useful. Whether your box lives in an EU or US region, the cron syntax is identical, so the schedule you build there drops straight into &lt;code&gt;crontab -e&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>sysadmin</category>
    </item>
    <item>
      <title>A practical UFW firewall for your VPS — open only what you need</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Wed, 24 Jun 2026 07:15:41 +0000</pubDate>
      <link>https://dev.to/overnighthost/a-practical-ufw-firewall-for-your-vps-open-only-what-you-need-3lln</link>
      <guid>https://dev.to/overnighthost/a-practical-ufw-firewall-for-your-vps-open-only-what-you-need-3lln</guid>
      <description>&lt;p&gt;A fresh VPS arrives with every port reachable from the entire internet. Most of them have nothing listening, but the moment you start a database, a cache, or a dev server bound to &lt;code&gt;0.0.0.0&lt;/code&gt;, it is exposed — and bots scan for exactly that within minutes. A firewall flips the default from "open unless I close it" to "closed unless I open it." On Ubuntu and Debian, &lt;code&gt;ufw&lt;/code&gt; (Uncomplicated Firewall) makes that a five-minute job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The golden rule: allow SSH before you enable
&lt;/h2&gt;

&lt;p&gt;The single most common way people lock themselves out of a VPS is enabling a default-deny firewall without first allowing their own SSH port. Do it in this order, every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ufw          &lt;span class="c"&gt;# usually already present&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw default deny incoming
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw default allow outgoing
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH        &lt;span class="c"&gt;# or: sudo ufw allow 22/tcp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;default deny incoming&lt;/code&gt; blocks everything arriving from outside. &lt;code&gt;default allow outgoing&lt;/code&gt; lets your server reach the internet (package updates, API calls) normally. The SSH rule is what keeps your session alive after you turn the firewall on.&lt;/p&gt;

&lt;p&gt;Only now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable
sudo &lt;/span&gt;ufw status verbose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you moved SSH to a custom port, allow that port instead of &lt;code&gt;OpenSSH&lt;/code&gt;, and confirm it works in a second terminal before closing the one you are in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open the services you actually run
&lt;/h2&gt;

&lt;p&gt;Add a rule per public service. A web server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 80/tcp
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/tcp
&lt;span class="c"&gt;# or the named profile if installed:&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow &lt;span class="s1"&gt;'Nginx Full'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A game server usually needs a specific UDP and/or TCP port — for example a Minecraft Java server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 25565/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The principle is to map each rule to a service you are deliberately exposing. If you cannot name the service behind a port, you probably should not open it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep databases private
&lt;/h2&gt;

&lt;p&gt;The biggest win is &lt;em&gt;not&lt;/em&gt; opening your datastore. Postgres (5432), MySQL (3306), Redis (6379) and friends should listen on &lt;code&gt;127.0.0.1&lt;/code&gt; or a private network interface, never the public one. If your app runs on the same box as its database, the database needs no firewall rule at all — local traffic never traverses the public interface.&lt;/p&gt;

&lt;p&gt;If you must reach a database from another server, scope the rule to that source address rather than the whole world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow from 203.0.113.10 to any port 5432 proto tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one line is the difference between "my teammate's server can connect" and "the entire internet can try."&lt;/p&gt;

&lt;h2&gt;
  
  
  Rate-limit SSH against brute force
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ufw&lt;/code&gt; has a built-in throttle that temporarily blocks an address making too many connections in a short window — handy for the constant SSH login attempts every public box receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw limit OpenSSH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is not a replacement for key-based auth and tools like fail2ban, but it is a free first layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect, edit, and undo
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw status numbered     &lt;span class="c"&gt;# list rules with index numbers&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw delete 3            &lt;span class="c"&gt;# remove rule #3&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw reload              &lt;span class="c"&gt;# reapply after edits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because rules are numbered, you can remove a mistake without flushing everything. Keep the list short — a firewall you understand at a glance is one you will actually maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sensible default set
&lt;/h2&gt;

&lt;p&gt;For a typical web VPS, the whole policy is four ideas: deny incoming by default, allow and rate-limit SSH, allow 80/443, and keep every datastore bound to localhost. That is enough to take a box from "exposed by default" to "exposes only what you chose," which is the entire point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing note
&lt;/h2&gt;

&lt;p&gt;A firewall is layer one, not the whole story — combine it with SSH keys, prompt updates, and least-privilege services. If you would rather start from a platform that already takes isolation seriously, &lt;a href="https://overnight.host/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; runs full-root KVM VPS in multiple regions (EU and US), where each tenant is genuinely isolated and the specs are honest — you still own your firewall, we just give you a clean, well-fenced box to run it on.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Choosing a VPS region: latency, data residency, and where your users actually are</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:18:49 +0000</pubDate>
      <link>https://dev.to/overnighthost/choosing-a-vps-region-latency-data-residency-and-where-your-users-actually-are-27cn</link>
      <guid>https://dev.to/overnighthost/choosing-a-vps-region-latency-data-residency-and-where-your-users-actually-are-27cn</guid>
      <description>&lt;p&gt;Picking a data-centre region feels like a minor checkbox at checkout, but it quietly shapes how fast your service feels and which rules apply to your data. Here is how to choose it deliberately instead of accepting whatever the default happens to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Put the server near your users, not near you
&lt;/h2&gt;

&lt;p&gt;Network latency is dominated by physical distance. Light in fibre is fast but not instant, and every router adds a little more. As a rough mental model, a round trip across an ocean is ~80-150 ms, within a continent ~10-40 ms, and within a metro ~1-5 ms. If your developer machine is in Berlin but your players are in Texas, hosting in Germany "because that is where you are" can add 100+ ms to every interaction for them.&lt;/p&gt;

&lt;p&gt;Test it before you commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# round-trip time to a host in a candidate region&lt;/span&gt;
ping &lt;span class="nt"&gt;-c&lt;/span&gt; 5 some-host-in-that-region.example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Match the latency budget to the use case
&lt;/h2&gt;

&lt;p&gt;Not everything needs to be twitch-fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Competitive game servers, voice, real-time apps:&lt;/strong&gt; latency is everything. Pick the region closest to the bulk of your players, even if it splits your audience across two servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web apps and dashboards:&lt;/strong&gt; users tolerate more, and a CDN in front hides a lot. Origin region still matters for dynamic, database-backed requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch jobs, scrapers, build runners, bots:&lt;/strong&gt; region barely matters for throughput — put them wherever is cheapest or most convenient, with one exception below.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Data residency and compliance
&lt;/h2&gt;

&lt;p&gt;Where your data physically sits can carry legal weight. If you handle personal data of EU residents, keeping that data in an EU region is the simplest way to stay on the right side of GDPR expectations and to answer the "where is our data?" question honestly. US and other jurisdictions have their own rules. The point is to choose region as a deliberate compliance decision, not an afterthought — and to be honest with your own users about where their data lives rather than overclaiming.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A CDN changes the math for static content
&lt;/h2&gt;

&lt;p&gt;If most of what you serve is cacheable — images, CSS, JS, static pages — a CDN like Cloudflare serves it from an edge near each visitor regardless of where your origin lives. In that case the origin region mostly affects cache misses and dynamic requests. If your traffic is heavily dynamic or database-driven, the origin region matters a lot more, because every request goes the full distance.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. When to go multi-region
&lt;/h2&gt;

&lt;p&gt;Reach for multiple regions when you genuinely have two centres of gravity (say, a European and a North American audience) and latency to one of them is hurting. Multi-region adds real operational complexity — data sync, failover, more moving parts — so do it because the numbers demand it, not because it sounds impressive. Many projects are better served by one well-chosen region plus a CDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Ping a few candidates, put the origin near the users who feel latency most, keep regulated data in an appropriate jurisdiction, and let a CDN cover the static stuff. "Closest to me" is rarely the right default.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;overnight.host runs VPS and game servers in multiple regions — EU and US today, with more coming — so you can pick the one nearest your users rather than nearest us. Honest specs, full root, &lt;a href="https://overnight.host/vps/" rel="noopener noreferrer"&gt;cancel-anytime billing&lt;/a&gt;, in your region.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vps</category>
      <category>devops</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How much RAM does your game server actually need? A practical sizing guide</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:17:43 +0000</pubDate>
      <link>https://dev.to/overnighthost/how-much-ram-does-your-game-server-actually-need-a-practical-sizing-guide-3b97</link>
      <guid>https://dev.to/overnighthost/how-much-ram-does-your-game-server-actually-need-a-practical-sizing-guide-3b97</guid>
      <description>&lt;p&gt;"How much RAM do I need?" is the first question for anyone spinning up a game server — and most answers online are either marketing ("buy more!") or pure guesswork. Here is a practical, honest way to size it, based on what actually consumes memory rather than what a sales page wants you to buy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually uses memory
&lt;/h2&gt;

&lt;p&gt;Four things, roughly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The base server process.&lt;/strong&gt; Every game server has a fixed footprint just to boot and idle with nobody connected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The world or map.&lt;/strong&gt; Larger, older, more-explored worlds hold more in memory. A Minecraft world that has been mined across thousands of chunks costs far more than a fresh one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Players and entities.&lt;/strong&gt; Each connected player loads the area around them; mobs, items, vehicles and physics objects all add up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mods and plugins.&lt;/strong&gt; This is the big multiplier. A vanilla server and a heavily-modded one of the same game can differ by an order of magnitude.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Rule-of-thumb baselines
&lt;/h2&gt;

&lt;p&gt;These are sane starting points for a small-to-medium community, not hard limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minecraft (Vanilla / Paper):&lt;/strong&gt; 2-4 GB for up to ~10-20 players. Paper is more memory-efficient than vanilla at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minecraft (modded — Forge / Fabric, big modpacks):&lt;/strong&gt; 6-10 GB is common; some kitchen-sink packs want more. The modpack, not the player count, drives this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust:&lt;/strong&gt; 8 GB minimum for a real map, often more on larger worlds — Rust is genuinely memory-hungry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Counter-Strike 2 / Source-engine games:&lt;/strong&gt; 1-2 GB is usually plenty; these are CPU- and tick-rate-bound more than RAM-bound.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ARK:&lt;/strong&gt; 8-16 GB depending on map and mods; another hungry one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why "just buy 16 GB" is usually the wrong instinct
&lt;/h2&gt;

&lt;p&gt;Two reasons. First, Java games like Minecraft do not get faster with a huge heap — an oversized &lt;code&gt;-Xmx&lt;/code&gt; can make garbage-collection pauses &lt;em&gt;worse&lt;/em&gt;, not better. Sizing the heap correctly (and using sane GC flags) beats brute force. Second, you pay for memory you never touch. It is cheaper and just as reliable to start at a sensible tier and move up if real usage demands it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure instead of guess
&lt;/h2&gt;

&lt;p&gt;Once your server is running under a realistic load, look at actual usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# live view of memory per process&lt;/span&gt;
htop

&lt;span class="c"&gt;# quick total snapshot&lt;/span&gt;
free &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch it with the player count you actually expect on a busy evening, not an empty server at 3am. If you sit comfortably under your allocation with headroom to spare, you are sized right. If you are pinned near the ceiling and seeing lag spikes, step up one tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  One honest caveat about "cheap" RAM
&lt;/h2&gt;

&lt;p&gt;A very cheap "game server" or "VPS" is sometimes an oversold shared container where the advertised RAM is burstable, not guaranteed — your process can be starved when a neighbour spikes. On real KVM virtualisation you get your own kernel and dedicated (not burstable) RAM, which is what a game server actually needs to stay stable under load. If a host will not say whether RAM is dedicated, ask before you buy.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to skip the mental math? We built a free &lt;a href="https://overnight.host/game-server-ram-calculator/" rel="noopener noreferrer"&gt;game server RAM calculator&lt;/a&gt; that sizes Minecraft, Rust, ARK and more from player count and mods — no signup. If you would rather have it managed, overnight.host runs game servers on dedicated bare metal with full file access and daily backups, in your region.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>minecraft</category>
      <category>selfhosting</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to monitor your VPS on a budget — uptime, resources and alerts</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Mon, 22 Jun 2026 02:40:56 +0000</pubDate>
      <link>https://dev.to/overnighthost/how-to-monitor-your-vps-on-a-budget-uptime-resources-and-alerts-19m9</link>
      <guid>https://dev.to/overnighthost/how-to-monitor-your-vps-on-a-budget-uptime-resources-and-alerts-19m9</guid>
      <description>&lt;p&gt;The cheapest way to find out your server is down is for a user to tell you. Don't be that operator. Monitoring a VPS well costs nothing but an afternoon, and it turns "why didn't anyone notice for six hours" into a push notification before most people refresh the page. Here's a practical, free stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things worth watching
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is it up?&lt;/strong&gt; Reachability from outside your own network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it healthy?&lt;/strong&gt; CPU, RAM, disk — the slow leaks that take a box down at 4 a.m.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Did something break?&lt;/strong&gt; Failed services, full disks, errors in logs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can cover all three without paying for an enterprise APM.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. External uptime checks
&lt;/h2&gt;

&lt;p&gt;The single most important monitor lives &lt;em&gt;off&lt;/em&gt; your server, because a check running on a dead box can't alert you. Free options like Uptime Kuma (self-hosted on a second machine) or a hosted free tier ping your URL every minute and notify you on failure.&lt;/p&gt;

&lt;p&gt;If you self-host Uptime Kuma, run it somewhere other than the server it watches — a second cheap VPS in a different region, or a Raspberry Pi at home. Point it at your real user-facing URL, not just the IP, so you catch TLS and DNS failures too.&lt;/p&gt;

&lt;p&gt;A nice habit: publish your uptime on a public status page. It keeps you honest and answers the "is it just me?" question without a support ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Resource monitoring
&lt;/h2&gt;

&lt;p&gt;For a single box, &lt;code&gt;htop&lt;/code&gt; and &lt;code&gt;df -h&lt;/code&gt; over SSH go a long way, but you want history, not just a snapshot. A lightweight, genuinely free option is &lt;strong&gt;netdata&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://my-netdata.io/kickstart.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It gives you per-second CPU, memory, disk I/O, and network graphs in a local web UI with essentially no configuration. Bind it to localhost and reach it through an SSH tunnel rather than exposing the dashboard to the internet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 19999:localhost:19999 root@your-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;code&gt;http://localhost:19999&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Service and disk alerts
&lt;/h2&gt;

&lt;p&gt;The two failures that bite small servers most often are a service that died silently and a disk that filled up. Catch both with a tiny cron script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# /usr/local/bin/healthcheck.sh&lt;/span&gt;
&lt;span class="nv"&gt;DISK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;df&lt;/span&gt; / | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'END{print +$5}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DISK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 85 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Disk at &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DISK&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;% on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"DISK WARNING"&lt;/span&gt; you@example.com
&lt;span class="k"&gt;fi
&lt;/span&gt;systemctl is-active &lt;span class="nt"&gt;--quiet&lt;/span&gt; nginx &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"nginx down on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | mail &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"SERVICE DOWN"&lt;/span&gt; you@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /usr/local/bin/healthcheck.sh
&lt;span class="c"&gt;# run every 5 minutes&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"*/5 * * * * root /usr/local/bin/healthcheck.sh"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/cron.d/healthcheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No mail server set up? Pipe the alert to a push service like ntfy instead — a one-line &lt;code&gt;curl&lt;/code&gt; to a private topic lands on your phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't over-alert
&lt;/h2&gt;

&lt;p&gt;The fastest way to start ignoring alerts is to get fifty a day. Alert on things that need a human: down, nearly-full, service crashed. Let graphs handle the rest — you look at those when you're investigating, not when you're asleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing note
&lt;/h2&gt;

&lt;p&gt;Good monitoring is mostly about putting the check in the right place (outside the box) and not crying wolf. If you'd rather not babysit it, every plan at &lt;a href="https://overnight.host/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; backs a 99.9% uptime SLA with live, public numbers you can check yourself — same philosophy, just one less thing for you to run, in whichever region you choose.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>selfhosting</category>
    </item>
    <item>
      <title>Reverse proxy on a VPS with Caddy — automatic HTTPS in minutes</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Mon, 22 Jun 2026 02:40:25 +0000</pubDate>
      <link>https://dev.to/overnighthost/reverse-proxy-on-a-vps-with-caddy-automatic-https-in-minutes-4b9b</link>
      <guid>https://dev.to/overnighthost/reverse-proxy-on-a-vps-with-caddy-automatic-https-in-minutes-4b9b</guid>
      <description>&lt;p&gt;If you run more than one web app on a single VPS — a site on port 3000, an API on 8080, a dashboard on 9000 — you don't want visitors typing port numbers. You want &lt;code&gt;app.example.com&lt;/code&gt; and &lt;code&gt;api.example.com&lt;/code&gt; to just work, over HTTPS, without you hand-rolling TLS certificates. That's what a reverse proxy does, and Caddy makes it about as painless as it gets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Caddy
&lt;/h2&gt;

&lt;p&gt;Nginx and Traefik are both excellent. Caddy earns its place because of one feature: it provisions and renews TLS certificates from Let's Encrypt automatically, with zero config beyond naming your domain. No certbot cron job, no renewal surprises at 2 a.m. For a small operator that one thing removes a whole category of outages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A VPS with root (any KVM box with full root will do — distro doesn't much matter).&lt;/li&gt;
&lt;li&gt;A domain with DNS pointing at your server's public IP. If your VPS uses NAT IPv4, make sure the HTTP/HTTPS ports you need are actually forwarded to it — check with your host before you debug for an hour.&lt;/li&gt;
&lt;li&gt;Ports 80 and 443 open in your firewall.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;On Debian or Ubuntu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; debian-keyring debian-archive-keyring apt-transport-https curl
curl &lt;span class="nt"&gt;-1sLf&lt;/span&gt; &lt;span class="s1"&gt;'https://dl.cloudsmith.io/public/caddy/stable/gpg.key'&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl &lt;span class="nt"&gt;-1sLf&lt;/span&gt; &lt;span class="s1"&gt;'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/caddy-stable.list
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;caddy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caddy installs as a systemd service and starts immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Caddyfile
&lt;/h2&gt;

&lt;p&gt;The entire config for proxying two apps lives in &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com {
    reverse_proxy localhost:3000
}

api.example.com {
    reverse_proxy localhost:8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload caddy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole thing. The first time a request hits &lt;code&gt;app.example.com&lt;/code&gt;, Caddy fetches a certificate, serves it over HTTPS, and redirects plain HTTP to HTTPS for you. No certbot, no renewal timer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful extras
&lt;/h2&gt;

&lt;p&gt;Gzip/zstd compression and a security header, added inline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.example.com {
    encode zstd gzip
    header Strict-Transport-Security "max-age=31536000;"
    reverse_proxy localhost:3000
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serve static files and proxy an API under one host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example.com {
    root * /var/www/site
    file_server
    handle /api/* {
        reverse_proxy localhost:8080
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A couple of gotchas
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DNS first.&lt;/strong&gt; Caddy can't get a certificate for a name that doesn't resolve to your box yet. Let DNS propagate before you reload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limits.&lt;/strong&gt; Let's Encrypt limits how many certs you can request per week. While testing, point Caddy at the staging CA so you don't burn your quota.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs.&lt;/strong&gt; &lt;code&gt;journalctl -u caddy -f&lt;/code&gt; shows you exactly what it's doing during the certificate dance — read it the first time, it's reassuring.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing note
&lt;/h2&gt;

&lt;p&gt;Caddy turns "I have three things running on one box" into three clean HTTPS hostnames in about ten minutes. Any full-root KVM VPS handles it comfortably — we run a small one for exactly this at &lt;a href="https://overnight.host/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt;, in whichever region you pick, with NAT-IPv4 port forwarding disclosed up front so the DNS step doesn't surprise you.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>devops</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Docker on a VPS - a beginner's guide to your first container</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sun, 21 Jun 2026 07:08:14 +0000</pubDate>
      <link>https://dev.to/overnighthost/docker-on-a-vps-a-beginners-guide-to-your-first-container-fji</link>
      <guid>https://dev.to/overnighthost/docker-on-a-vps-a-beginners-guide-to-your-first-container-fji</guid>
      <description>&lt;p&gt;Docker has a reputation for being either magic or a headache, and the truth is it's mostly neither once you've run a couple of containers yourself. If you have a KVM VPS with full root, you can go from a blank box to a running, restart-on-reboot app in about ten minutes. Here's the honest, no-magic path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Docker on a VPS
&lt;/h2&gt;

&lt;p&gt;A container bundles your app and everything it needs into one image, so "works on my machine" becomes "works on the server too." You also get clean isolation (one app's mess doesn't touch another's), easy upgrades (pull a new image, recreate the container), and trivial teardown. The one real requirement: a &lt;strong&gt;KVM&lt;/strong&gt; VPS, not an oversold container-on-a-container. You need your own kernel to run Docker properly — if a host doesn't say KVM anywhere, ask before you buy.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Install Docker
&lt;/h2&gt;

&lt;p&gt;The official convenience script works across Debian, Ubuntu, and the RHEL family:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com | &lt;span class="nb"&gt;sudo &lt;/span&gt;sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; docker
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your user to the &lt;code&gt;docker&lt;/code&gt; group so you don't have to &lt;code&gt;sudo&lt;/code&gt; every command (log out and back in afterward):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Run your first container
&lt;/h2&gt;

&lt;p&gt;Prove it works with something disposable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run something real — a web server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; web &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a live nginx on port 80. The flags matter: &lt;code&gt;-d&lt;/code&gt; runs it in the background, &lt;code&gt;--restart unless-stopped&lt;/code&gt; brings it back after a reboot, and &lt;code&gt;-p 80:80&lt;/code&gt; maps the host port to the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Use Compose for anything with more than one piece
&lt;/h2&gt;

&lt;p&gt;Most real apps are an app plus a database. &lt;code&gt;docker compose&lt;/code&gt; (built into modern Docker) describes the whole stack in one file. Create &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost:5&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:2368"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;database__client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql&lt;/span&gt;
      &lt;span class="na"&gt;database__connection__host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;database__connection__user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
      &lt;span class="na"&gt;database__connection__password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changeme&lt;/span&gt;
      &lt;span class="na"&gt;database__connection__database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changeme&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghost&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changeme&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dbdata:/var/lib/mysql&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dbdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two containers, networked together, data persisted in a named volume that survives a &lt;code&gt;compose down&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The habits that keep it healthy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persist data in volumes&lt;/strong&gt;, never inside the container — containers are disposable, volumes are not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't publish database ports&lt;/strong&gt; (&lt;code&gt;3306&lt;/code&gt;, &lt;code&gt;5432&lt;/code&gt;) to the public internet; let containers reach each other over the internal Docker network instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pin image versions&lt;/strong&gt; (&lt;code&gt;mysql:8&lt;/code&gt;, not &lt;code&gt;mysql:latest&lt;/code&gt;) so an upgrade is a decision, not a surprise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put a reverse proxy in front&lt;/strong&gt; (Caddy or nginx) for TLS, instead of exposing app ports directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Updating and cleaning up
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose pull &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;   &lt;span class="c"&gt;# upgrade in place&lt;/span&gt;
docker system prune &lt;span class="nt"&gt;-f&lt;/span&gt;                         &lt;span class="c"&gt;# reclaim space from old images&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where to run it
&lt;/h2&gt;

&lt;p&gt;Docker doesn't care which region your server is in — the same image runs identically in the EU or the US. If you need a box to try this on, &lt;a href="https://overnight.host/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; offers KVM VPS with full root access and honest specs (real KVM, SSD, NAT IPv4 disclosed before checkout), hosted in your region. Spin one up, run the hello-world above, and you'll have demystified Docker by lunch.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>vps</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to set up automated, off-site backups for your VPS with restic</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sun, 21 Jun 2026 07:08:12 +0000</pubDate>
      <link>https://dev.to/overnighthost/how-to-set-up-automated-off-site-backups-for-your-vps-with-restic-506l</link>
      <guid>https://dev.to/overnighthost/how-to-set-up-automated-off-site-backups-for-your-vps-with-restic-506l</guid>
      <description>&lt;p&gt;A backup that lives on the same machine as your data isn't a backup — it's a copy waiting to disappear with the disk. If you run anything on a VPS that you'd be unhappy to lose (a database, a game world, a self-hosted app), you want backups that run on a schedule, leave the server, and can actually be restored. Here's a clean, honest setup using &lt;a href="https://restic.net/" rel="noopener noreferrer"&gt;restic&lt;/a&gt;, which is free, open-source, encrypted by default, and deduplicates so repeated backups stay small.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Install restic
&lt;/h2&gt;

&lt;p&gt;On Debian/Ubuntu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; restic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On AlmaLinux/Rocky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; epel-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; restic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Pick an off-site destination
&lt;/h2&gt;

&lt;p&gt;The whole point is "not on this server." Good options: an S3-compatible object store, a second VPS in another region, or an SFTP target. restic encrypts everything client-side before it leaves the box, so the destination never sees your plaintext.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_REPOSITORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sftp:backup@backup-host:/srv/restic/myvps"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"a-long-random-passphrase-you-store-safely"&lt;/span&gt;
restic init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep that passphrase somewhere safe and separate. Without it, the repository is unrecoverable — which is exactly what protects you if the backup host is ever compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Back up the things that matter
&lt;/h2&gt;

&lt;p&gt;Don't back up the whole root filesystem — you'll just restore the OS. Back up your data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;restic backup /var/lib/mysql /var/www /etc /home &lt;span class="nt"&gt;--exclude-caches&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For databases, dump first so you get a consistent snapshot rather than copying live files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysqldump &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--all-databases&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /root/db-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%F&lt;span class="si"&gt;)&lt;/span&gt;.sql
restic backup /root/db-&lt;span class="k"&gt;*&lt;/span&gt;.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Automate it with a timer
&lt;/h2&gt;

&lt;p&gt;Drop this into &lt;code&gt;/usr/local/sbin/backup.sh&lt;/code&gt;, make it executable, and let cron run it nightly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_REPOSITORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sftp:backup@backup-host:/srv/restic/myvps"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RESTIC_PASSWORD_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.restic-pass"&lt;/span&gt;
mysqldump &lt;span class="nt"&gt;--single-transaction&lt;/span&gt; &lt;span class="nt"&gt;--all-databases&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /root/db.sql
restic backup /var/www /etc /root/db.sql &lt;span class="nt"&gt;--exclude-caches&lt;/span&gt;
restic forget &lt;span class="nt"&gt;--keep-daily&lt;/span&gt; 7 &lt;span class="nt"&gt;--keep-weekly&lt;/span&gt; 4 &lt;span class="nt"&gt;--keep-monthly&lt;/span&gt; 6 &lt;span class="nt"&gt;--prune&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;700 /usr/local/sbin/backup.sh
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"15 3 * * * root /usr/local/sbin/backup.sh &amp;gt;&amp;gt; /var/log/backup.log 2&amp;gt;&amp;amp;1"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/cron.d/restic-backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;forget --prune&lt;/code&gt; line is the part people skip — it keeps a sensible retention window so the repository doesn't grow forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Test the restore (this is the real step)
&lt;/h2&gt;

&lt;p&gt;An untested backup is a hope, not a plan. Once a month, prove it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;restic snapshots
restic restore latest &lt;span class="nt"&gt;--target&lt;/span&gt; /tmp/restore-test &lt;span class="nt"&gt;--include&lt;/span&gt; /etc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the files come back, you have a backup. If they don't, you found out on a Tuesday instead of during a disaster.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on where this runs
&lt;/h2&gt;

&lt;p&gt;restic is region-agnostic — it works the same whether your VPS is in the EU or the US, and the encrypted-before-it-leaves design means you stay in control of your data wherever the backup target lives. If you're spinning up a box for this, &lt;a href="https://overnight.host/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; runs KVM VPS with full root and honest specs (SSD, NAT IPv4 disclosed up front), hosted in your region — so you can point your off-site backups at a second region without overthinking it.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>linux</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Migrating a website to a new host with near-zero downtime</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:03:11 +0000</pubDate>
      <link>https://dev.to/overnighthost/migrating-a-website-to-a-new-host-with-near-zero-downtime-3mh5</link>
      <guid>https://dev.to/overnighthost/migrating-a-website-to-a-new-host-with-near-zero-downtime-3mh5</guid>
      <description>&lt;p&gt;The scary part of moving hosts is the gap where the site is half here and half there. Sequence it right and visitors never notice.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Build the new home first, behind the scenes
&lt;/h2&gt;

&lt;p&gt;Set everything up on the new server while the old one keeps serving. Copy the files and the database, get the app running, and test it by hitting the new IP directly (a hosts-file entry on your laptop pointing the domain at the new IP lets you browse the real site there before anyone else does).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Lower your DNS TTL ahead of time
&lt;/h2&gt;

&lt;p&gt;A day before the move, drop the TTL on the relevant records to 300 seconds. Now when you flip, caches expire in minutes instead of a day or two. Do this early, because the old long TTL has to expire first.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Freeze, sync the delta, flip
&lt;/h2&gt;

&lt;p&gt;Pick a quiet window. Put the old site in read-only or maintenance mode briefly, sync the last database changes and any new uploads to the new box, then change the DNS A record to the new IP. Because the TTL is low, resolvers pick it up fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Both servers serve during the overlap
&lt;/h2&gt;

&lt;p&gt;For a short while, some visitors still hit the old IP and some hit the new one. This is why you went read-only for the cutover: so no writes land on the old box that the new one misses. Once traffic has clearly moved (check your new server's access logs), you can lift maintenance mode on the new host.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Re-issue TLS and confirm
&lt;/h2&gt;

&lt;p&gt;Make sure the certificate on the new host covers the domain, then walk the site: forms, logins, checkout, the lot. Leave the old server up for a few days as a fallback before you tear it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one that bites people
&lt;/h2&gt;

&lt;p&gt;Email and DNS often live with the old host. Before you cancel anything, move your MX records and any other records, not just the A record, or you will silently lose mail.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://overnight.host/migrate/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; does free migrations as part of onboarding for exactly this reason: the sequencing is routine for us and nerve-wracking to do alone for the first time.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>hosting</category>
      <category>dns</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self-hosting n8n or Activepieces vs letting someone manage it</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:02:25 +0000</pubDate>
      <link>https://dev.to/overnighthost/self-hosting-n8n-or-activepieces-vs-letting-someone-manage-it-2go1</link>
      <guid>https://dev.to/overnighthost/self-hosting-n8n-or-activepieces-vs-letting-someone-manage-it-2go1</guid>
      <description>&lt;p&gt;Open-source workflow automation (n8n, Activepieces) is the privacy-friendly answer to Zapier and Make. The engine is free. The question is who runs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What self-hosting actually involves
&lt;/h2&gt;

&lt;p&gt;Spinning up the container is the easy part. Keeping it healthy is the job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A database (Postgres) and Redis, backed up, with backups you have actually restored once.&lt;/li&gt;
&lt;li&gt;TLS, a reverse proxy, and a domain.&lt;/li&gt;
&lt;li&gt;Updates, which sometimes include breaking schema migrations you have to read the notes for.&lt;/li&gt;
&lt;li&gt;Monitoring so you find out a flow stopped firing before your customer does.&lt;/li&gt;
&lt;li&gt;Secrets and connection tokens stored encrypted, not in plaintext env files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you enjoy that and have the time, self-hosting is great and you keep total control.&lt;/p&gt;

&lt;h2&gt;
  
  
  When managed makes sense
&lt;/h2&gt;

&lt;p&gt;If the automations are running your business rather than your hobby, the math changes. Managed means someone else owns the database backups, the updates, the TLS renewals and the monitoring, and you get an isolated instance you just build on. You still own the workflows, because the engine is open source (MIT) and your flows export cleanly. No lock-in, less plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest middle
&lt;/h2&gt;

&lt;p&gt;A good test: if your automations going dark for a day would cost you real money, pay someone to run them. If it would just be annoying, self-host and learn a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Region matters for compliance
&lt;/h2&gt;

&lt;p&gt;Where the instance and its backups physically live is a real decision if you handle personal data. Pick a host that lets you choose the region at checkout and will sign a data processing agreement for the EU, rather than one that is vague about where the box is.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://overnight.host/automation/" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; runs managed open-source automation on isolated per-customer instances, in the region you pick (EU or US), with a live demo panel you can poke at before you commit. The engine stays open source, so your workflows are always yours.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>selfhosted</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to point a domain at your VPS — DNS, A records and TLS</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:02:24 +0000</pubDate>
      <link>https://dev.to/overnighthost/how-to-point-a-domain-at-your-vps-dns-a-records-and-tls-26hl</link>
      <guid>https://dev.to/overnighthost/how-to-point-a-domain-at-your-vps-dns-a-records-and-tls-26hl</guid>
      <description>&lt;p&gt;You have a VPS with a public IP and a domain sitting at a registrar. Connecting the two trips up more people than it should. Here is the whole path.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The A record is the core of it
&lt;/h2&gt;

&lt;p&gt;An &lt;code&gt;A&lt;/code&gt; record maps a name to an IPv4 address. At your DNS provider, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type  Name   Value
A     @      203.0.113.10
A     www    203.0.113.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@&lt;/code&gt; is the bare domain (example.com), &lt;code&gt;www&lt;/code&gt; is the subdomain. If you have IPv6, add &lt;code&gt;AAAA&lt;/code&gt; records with the same names pointing at your v6 address.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Understand TTL and propagation
&lt;/h2&gt;

&lt;p&gt;TTL is how long resolvers cache the record. Set it low (300 seconds) before a planned change so the switch is fast, then raise it again afterwards. "Propagation" is just caches expiring around the world; there is nothing to speed up except waiting out the TTL.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Check it from the outside, not your browser
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short example.com
dig +short www.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your browser caches and your OS caches, so trust &lt;code&gt;dig&lt;/code&gt; against a public resolver over a page reload.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add TLS once DNS resolves
&lt;/h2&gt;

&lt;p&gt;Certbot with the HTTP challenge needs the domain to already point at the box and port 80 reachable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx
certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; example.com &lt;span class="nt"&gt;-d&lt;/span&gt; www.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are behind a CDN or want wildcards, use the DNS-01 challenge instead, which proves control through a TXT record rather than a live web server.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. A note on NAT-IPv4 hosts
&lt;/h2&gt;

&lt;p&gt;On budget hosts your VPS may share an IPv4 and get specific forwarded ports rather than the whole IP. That is fine for most workloads, but it changes how you point a domain: you map the name to the shared IP and reach your service on its forwarded port, or you put a reverse proxy in front. Always check whether your plan gives you a dedicated IP or a NAT one before you design around it.&lt;/p&gt;




&lt;p&gt;At &lt;a href="https://overnight.host" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; we are upfront about which plans are NAT-IPv4 and which give a dedicated IP, because finding out after you have wired DNS is nobody's idea of fun.&lt;/p&gt;

</description>
      <category>dns</category>
      <category>vps</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Securing a fresh VPS — the 15-minute checklist</title>
      <dc:creator>overnight.host</dc:creator>
      <pubDate>Sat, 20 Jun 2026 18:00:21 +0000</pubDate>
      <link>https://dev.to/overnighthost/securing-a-fresh-vps-the-15-minute-checklist-mpe</link>
      <guid>https://dev.to/overnighthost/securing-a-fresh-vps-the-15-minute-checklist-mpe</guid>
      <description>&lt;p&gt;You just spun up a VPS. Before you put anything real on it, spend fifteen minutes locking it down. Here is the order that catches the most risk for the least effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create a non-root user
&lt;/h2&gt;

&lt;p&gt;Working as root all day means one fat-fingered command can wipe the box. Make a user and give it sudo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adduser deploy
usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Switch to SSH keys, then turn off password login
&lt;/h2&gt;

&lt;p&gt;Passwords get brute-forced around the clock. Copy your key up, confirm you can log in with it, then in &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; set &lt;code&gt;PasswordAuthentication no&lt;/code&gt; and &lt;code&gt;PermitRootLogin prohibit-password&lt;/code&gt;, and reload sshd. Keep a second terminal open until you have confirmed the new login works, so you never lock yourself out.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Turn on a firewall with a default-deny stance
&lt;/h2&gt;

&lt;p&gt;Only open what you actually serve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;ufw allow 80,443/tcp&lt;/code&gt; when you put a web server on it. The principle is the same one we run at the host level: deny by default, allow on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add fail2ban
&lt;/h2&gt;

&lt;p&gt;It watches your auth log and bans IPs that hammer SSH. &lt;code&gt;apt install fail2ban&lt;/code&gt; and the default jail is already sensible.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Patch, then enable unattended security updates
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
apt &lt;span class="nb"&gt;install &lt;/span&gt;unattended-upgrades
dpkg-reconfigure &lt;span class="nt"&gt;-plow&lt;/span&gt; unattended-upgrades
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Know where your backups are
&lt;/h2&gt;

&lt;p&gt;A server you cannot restore is a server you do not really have. Snapshot before big changes, and keep at least one copy off the box.&lt;/p&gt;

&lt;p&gt;That is the 15-minute baseline. None of it is exotic, and skipping it is how most small servers get owned.&lt;/p&gt;




&lt;p&gt;We run &lt;a href="https://overnight.host" rel="noopener noreferrer"&gt;overnight.host&lt;/a&gt; on rented bare metal across EU and US regions, with a default-deny firewall and key-based access as the standard, not an upsell. If you want a VPS that ships locked down, that is the idea.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>security</category>
      <category>linux</category>
      <category>sysadmin</category>
    </item>
  </channel>
</rss>
