<?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: Arthur</title>
    <description>The latest articles on DEV Community by Arthur (@arthur_luca).</description>
    <link>https://dev.to/arthur_luca</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%2F4078497%2F225fdf23-256f-428a-a8c0-1b538e08c1ef.png</url>
      <title>DEV Community: Arthur</title>
      <link>https://dev.to/arthur_luca</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arthur_luca"/>
    <language>en</language>
    <item>
      <title>When Does a Website Need VPS Hosting?</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Sun, 18 Oct 2026 08:04:23 +0000</pubDate>
      <link>https://dev.to/arthur_luca/when-does-a-website-need-vps-hosting-42pl</link>
      <guid>https://dev.to/arthur_luca/when-does-a-website-need-vps-hosting-42pl</guid>
      <description>&lt;p&gt;Many websites start with basic hosting, and that is completely fine. If you are running a small blog or a simple website, you may not need advanced server resources at the beginning.&lt;/p&gt;

&lt;p&gt;But as your website grows, you might start noticing slow loading times, limited resources, or less control over your hosting environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. When Basic Hosting Is No Longer Enough
&lt;/h2&gt;

&lt;p&gt;Shared hosting is a good starting point for beginners. However, multiple websites share the same server resources, which can sometimes affect performance.&lt;/p&gt;

&lt;p&gt;If your website receives more visitors or runs resource-heavy applications, you may need a more flexible hosting solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What Makes VPS Hosting Different?
&lt;/h2&gt;

&lt;p&gt;A Virtual Private Server (VPS) provides dedicated resources within a virtualized server environment. It usually gives you more control over server settings, software installation, and resource management.&lt;/p&gt;

&lt;p&gt;VPS hosting can be useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Growing business websites&lt;/li&gt;
&lt;li&gt;Web applications and APIs&lt;/li&gt;
&lt;li&gt;Development and testing environments&lt;/li&gt;
&lt;li&gt;Websites that need more control over server configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Check Your Requirements Before Choosing
&lt;/h2&gt;

&lt;p&gt;Before switching to VPS hosting, consider your expected traffic, RAM requirements, storage, bandwidth, and technical experience.&lt;/p&gt;

&lt;p&gt;For example, a small website may work well with a basic VPS, while a larger application might require additional CPU cores and memory.&lt;/p&gt;

&lt;p&gt;You can explore &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; to learn more about available hosting options and compare them with your project's requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Is VPS Hosting Right for Everyone?
&lt;/h2&gt;

&lt;p&gt;Not necessarily. If your website is small and your current hosting performs well, there may be no reason to upgrade immediately.&lt;/p&gt;

&lt;p&gt;However, if you need more control, predictable resources, or room to grow, VPS hosting is worth considering.&lt;/p&gt;

&lt;p&gt;The best approach is to identify your current limitations first and choose a hosting plan that matches your actual needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Choosing hosting is not just about getting more resources. It is about finding the right balance between performance, control, reliability, and cost. Start with your website's current needs and upgrade when there is a clear reason to do so.&lt;/p&gt;

</description>
      <category>vps</category>
      <category>programming</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>What Happens When a Web Server Runs Out of Memory?</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:08:46 +0000</pubDate>
      <link>https://dev.to/arthur_luca/what-happens-when-a-web-server-runs-out-of-memory-1neb</link>
      <guid>https://dev.to/arthur_luca/what-happens-when-a-web-server-runs-out-of-memory-1neb</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. When working with websites and applications, we usually focus on features, design, and performance. But there is one problem that can affect everything: a server running out of memory.&lt;/p&gt;

&lt;p&gt;I wanted to understand why applications sometimes become slow or stop responding, even when the server seems to be working normally. Memory usage is one of the things worth checking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does a Server Need RAM?
&lt;/h2&gt;

&lt;p&gt;RAM stores the data and instructions that running applications need to access quickly. A web server uses memory for processes, active connections, application code, caching, and other tasks.&lt;/p&gt;

&lt;p&gt;When several applications run at the same time, memory consumption can increase. A busy database, a memory leak, or too many application workers can put additional pressure on the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens When RAM Is Almost Full?
&lt;/h2&gt;

&lt;p&gt;When a Linux server runs low on available memory, several things can happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applications may respond more slowly.&lt;/li&gt;
&lt;li&gt;The operating system may reclaim cached memory.&lt;/li&gt;
&lt;li&gt;Swap space may be used, which is generally slower than RAM.&lt;/li&gt;
&lt;li&gt;Under severe memory pressure, the Linux Out-Of-Memory (OOM) killer may terminate processes to protect the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why high memory usage deserves attention, especially on production servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check Memory Usage in Linux
&lt;/h2&gt;

&lt;p&gt;You don't always need advanced monitoring software to start investigating a memory problem.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;free -h&lt;/code&gt; command displays memory usage in a readable format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;free &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To inspect running processes and their resource consumption, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;top
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also review system logs for memory-related events. On systems using systemd, this command may help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;-k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on your permissions and system configuration, you may need elevated privileges to access some kernel logs.&lt;/p&gt;

&lt;p&gt;Remember that Linux uses available memory for caching, so high memory usage alone does not necessarily mean something is wrong. Pay attention to available memory, swap activity, application behavior, and system logs together.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Can You Prevent Memory Problems?
&lt;/h2&gt;

&lt;p&gt;A few practical habits can make server management easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor resource usage:&lt;/strong&gt; Track memory consumption and set alerts for sustained pressure rather than reacting to a single reading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Investigate application behavior:&lt;/strong&gt; Look for memory leaks, unnecessary processes, and workloads that consume more RAM than expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimize configuration:&lt;/strong&gt; Review application worker counts, database settings, and caching strategies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose suitable resources:&lt;/strong&gt; Make sure your server has enough memory for its expected workload, including periods of higher traffic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test before making changes:&lt;/strong&gt; Avoid restarting services or changing production settings without understanding the cause of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does VPS Hosting Make a Difference?
&lt;/h2&gt;

&lt;p&gt;A Virtual Private Server provides allocated virtual resources, including RAM, according to the selected plan. This can give developers more control over their environment and application configuration.&lt;/p&gt;

&lt;p&gt;However, a VPS cannot automatically prevent memory problems. The required resources depend on the software, traffic, database workload, and background processes running on the server.&lt;/p&gt;

&lt;p&gt;If you're exploring hosting options for development or production projects, you can learn more about &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer&lt;/a&gt; and its hosting services.&lt;/p&gt;

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

&lt;p&gt;Memory problems are easier to handle when you understand what the operating system is doing. Checking memory usage, investigating processes, and reviewing logs can help you identify the real cause instead of making random configuration changes.&lt;/p&gt;

&lt;p&gt;You don't need to be an experienced system administrator to start learning these skills. A few basic Linux commands and a habit of monitoring your server can take you a long way.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to Back Up Postgres on a VPS (and Prove the Restore Works)</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Wed, 14 Oct 2026 16:27:52 +0000</pubDate>
      <link>https://dev.to/arthur_luca/how-to-back-up-postgres-on-a-vps-and-prove-the-restore-works-464h</link>
      <guid>https://dev.to/arthur_luca/how-to-back-up-postgres-on-a-vps-and-prove-the-restore-works-464h</guid>
      <description>&lt;p&gt;Hi, I'm Arthur. Picture this: a migration meant for staging runs against production, and a table is gone. You open your backup folder and find a file from three weeks ago, or nothing at all because the cron job has been failing quietly since a disk filled up.&lt;/p&gt;

&lt;p&gt;Most "back up Postgres" guides stop at one &lt;code&gt;pg_dump&lt;/code&gt; command. That's the easy part. What saves you is knowing the job ran, having a copy that isn't on the same disk, and having restored it at least once. This guide builds all three on a single Ubuntu VPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A VPS running Ubuntu with Postgres installed and root access. &lt;a href="https://helloserver.tech" rel="noopener noreferrer"&gt;HelloServer&lt;/a&gt; offers VPS plans with full root access, and any similar provider works the same way.&lt;/li&gt;
&lt;li&gt;Somewhere off the server to store copies: any S3-compatible bucket, Backblaze B2, or similar.&lt;/li&gt;
&lt;li&gt;About 30 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;pg_dump&lt;/code&gt; and not a file copy
&lt;/h2&gt;

&lt;p&gt;Copying Postgres's data directory while it's running can give you files that don't match each other. &lt;code&gt;pg_dump&lt;/code&gt; takes a consistent snapshot of the database without blocking writers. The &lt;code&gt;-Fc&lt;/code&gt; (custom) format also compresses the dump and lets you restore single tables with &lt;code&gt;pg_restore&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: A place for backups
&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 mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/backups/postgres
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;postgres:postgres /var/backups/postgres
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;700 /var/backups/postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the &lt;code&gt;postgres&lt;/code&gt; user can read it. A dump contains all your data, so treat the folder like the database itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Set up offsite storage
&lt;/h2&gt;

&lt;p&gt;Install rclone and configure a remote as the &lt;code&gt;postgres&lt;/code&gt; user, so the cron job can find the config later:&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; rclone
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres rclone config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts to add your storage provider and name the remote &lt;code&gt;remote&lt;/code&gt;. Then check 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;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres rclone lsd remote:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dumps leave your server here, so encrypt them. rclone has a &lt;code&gt;crypt&lt;/code&gt; remote type that wraps another remote: create one pointing at &lt;code&gt;remote:my-backups&lt;/code&gt; and use it in the script below instead of the plain one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The script
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;/usr/local/bin/pg-backup.sh&lt;/code&gt;:&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"myapp"&lt;/span&gt;
&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/backups/postgres"&lt;/span&gt;
&lt;span class="nv"&gt;STAMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%F_%H%M&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.dump"&lt;/span&gt;

&lt;span class="c"&gt;# 1. Dump to a temp file first, so a half-written file never looks valid&lt;/span&gt;
pg_dump &lt;span class="nt"&gt;-Fc&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;.tmp"&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;.tmp"&lt;/span&gt;
&lt;span class="nb"&gt;mv&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;.tmp"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# 2. Roles and passwords live outside any single database&lt;/span&gt;
pg_dumpall &lt;span class="nt"&gt;--globals-only&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/globals_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql"&lt;/span&gt;

&lt;span class="c"&gt;# 3. Copy offsite&lt;/span&gt;
rclone copy &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; remote:my-backups/postgres/
rclone copy &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;/globals_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAMP&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql"&lt;/span&gt; remote:my-backups/postgres/

&lt;span class="c"&gt;# 4. Prune: 7 days locally, 30 days offsite&lt;/span&gt;
find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="se"&gt;\(&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.dump'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'globals_*.sql'&lt;/span&gt; &lt;span class="se"&gt;\)&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +7 &lt;span class="nt"&gt;-delete&lt;/span&gt;
rclone delete remote:my-backups/postgres/ &lt;span class="nt"&gt;--min-age&lt;/span&gt; 30d

&lt;span class="c"&gt;# 5. Tell the monitor we finished&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsS&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 10 &lt;span class="nt"&gt;--retry&lt;/span&gt; 3 https://hc-ping.com/YOUR-UUID-HERE &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few details are worth understanding before you copy it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;set -euo pipefail&lt;/code&gt;&lt;/strong&gt; stops the script at the first failure. That matters because step 5 only runs if everything before it worked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pg_dumpall --globals-only&lt;/code&gt;&lt;/strong&gt; saves roles and their passwords. Without it, a restore onto a fresh server fails because the app's database user doesn't exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The pruning lines&lt;/strong&gt; keep the folder and bucket from growing forever. Disks that fill up are one of the most common reasons backup jobs stop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make it executable and run it once by hand:&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 chmod&lt;/span&gt; +x /usr/local/bin/pg-backup.sh
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres /usr/local/bin/pg-backup.sh
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; /var/backups/postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that the file has a real size and that it also appears in your bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Schedule it and get alerted when it fails
&lt;/h2&gt;

&lt;p&gt;Add a cron job for the &lt;code&gt;postgres&lt;/code&gt; user:&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;crontab &lt;span class="nt"&gt;-u&lt;/span&gt; postgres &lt;span class="nt"&gt;-e&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;15 3 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/local/bin/pg-backup.sh &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /var/backups/postgres/backup.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That runs at 03:15 every night. Now the monitoring: a service like Healthchecks.io gives you a unique ping URL and emails you if no ping arrives on schedule. Paste that URL into step 5 of the script. This catches the failure cron never reports: the job that silently stopped running. Set the expected period to one day, with a grace period of an hour or two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The restore drill
&lt;/h2&gt;

&lt;p&gt;This is the step that turns a file into a backup. Restore into a scratch database, not your live one:&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; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres createdb myapp_restore_test
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres pg_restore &lt;span class="nt"&gt;-d&lt;/span&gt; myapp_restore_test &lt;span class="nt"&gt;--no-owner&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  /var/backups/postgres/myapp_2026-10-14_0315.dump
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql myapp_restore_test &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT count(*) FROM users;"&lt;/span&gt;
&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres dropdb myapp_restore_test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the row count with production. Note how long the restore took, since that's your real downtime in an emergency.&lt;/p&gt;

&lt;p&gt;A full rebuild on a brand-new server goes in this order: install Postgres (same major version or newer), restore the globals with &lt;code&gt;sudo -u postgres psql -f globals_....sql&lt;/code&gt;, then &lt;code&gt;createdb&lt;/code&gt; and &lt;code&gt;pg_restore&lt;/code&gt; the dump. Do this drill once now, not for the first time during an outage.&lt;/p&gt;

&lt;h2&gt;
  
  
  If Postgres runs in Docker
&lt;/h2&gt;

&lt;p&gt;Run the dump through &lt;code&gt;docker exec&lt;/code&gt;, but &lt;strong&gt;don't add &lt;code&gt;-t&lt;/code&gt;&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;docker &lt;span class="nb"&gt;exec &lt;/span&gt;db pg_dump &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-Fc&lt;/span&gt; myapp &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; myapp.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-t&lt;/code&gt; flag allocates a terminal, which can corrupt binary output, and you won't notice until you try to restore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this setup falls short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You can lose up to a day of data.&lt;/strong&gt; A nightly dump only captures that moment. If that's too much, look at continuous archiving with a tool like pgBackRest or WAL-G for point-in-time recovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big databases slow down while dumping.&lt;/strong&gt; It doesn't block writes, but it uses CPU and disk. Schedule it for your quietest hour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same provider is still a single risk.&lt;/strong&gt; For a second layer, a small separate VPS can act as a backup target over SSH with &lt;code&gt;rsync&lt;/code&gt;. A second small plan from &lt;a href="https://helloserver.tech" rel="noopener noreferrer"&gt;HelloServer&lt;/a&gt; would work for that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Your checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run the script once by hand and check the file size.&lt;/li&gt;
&lt;li&gt;Confirm the copy landed in your bucket.&lt;/li&gt;
&lt;li&gt;Set up the monitor and let it alert you once, on purpose, by skipping a run.&lt;/li&gt;
&lt;li&gt;Do the restore drill and write down how long it took.&lt;/li&gt;
&lt;li&gt;Put a reminder on your calendar to repeat step 4 every few months.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want a safe place to try this end to end, a small VPS from &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer&lt;/a&gt; is enough, because you can break things and rebuild without touching a real project. How often do you actually test your restores? I'd like to know whether anyone does it on a schedule.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>devops</category>
      <category>linux</category>
      <category>backup</category>
    </item>
    <item>
      <title>Why Developers Need Reliable VPS Hosting for Modern Applications</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Mon, 12 Oct 2026 15:44:41 +0000</pubDate>
      <link>https://dev.to/arthur_luca/why-developers-need-reliable-vps-hosting-for-modern-applications-33mf</link>
      <guid>https://dev.to/arthur_luca/why-developers-need-reliable-vps-hosting-for-modern-applications-33mf</guid>
      <description>&lt;p&gt;Modern applications need more than good code. They also need reliable infrastructure, stable performance, and enough resources to handle real-world workloads.&lt;/p&gt;

&lt;p&gt;Whether you're deploying APIs, running Docker containers, hosting websites, or managing databases, choosing the right server can make a big difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Infrastructure Matters
&lt;/h2&gt;

&lt;p&gt;An application may work perfectly in a local development environment but behave differently in production. Limited RAM, CPU bottlenecks, slow storage, and network issues can all affect performance.&lt;/p&gt;

&lt;p&gt;Before deploying an application, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CPU:&lt;/strong&gt; Choose enough cores for your application's workload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAM:&lt;/strong&gt; Leave sufficient memory for your application, database, and background processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; NVMe SSDs can improve disk-intensive workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network:&lt;/strong&gt; Reliable bandwidth matters for APIs, downloads, and distributed services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Make sure you can upgrade resources as traffic grows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. VPS vs. Shared Hosting
&lt;/h2&gt;

&lt;p&gt;Shared hosting can work well for small websites, but developers often need more control over their environments.&lt;/p&gt;

&lt;p&gt;A Virtual Private Server (VPS) provides dedicated virtualized resources and greater control over software, services, and configurations. It can be useful for staging environments, web applications, APIs, and development projects.&lt;/p&gt;

&lt;p&gt;However, the right choice depends on your workload, budget, and management requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What to Check Before Renting a VPS
&lt;/h2&gt;

&lt;p&gt;Don't choose a server based on CPU cores alone. Review the full configuration and ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much RAM and storage are included?&lt;/li&gt;
&lt;li&gt;Is the storage NVMe or SATA SSD?&lt;/li&gt;
&lt;li&gt;What network speed and traffic limits apply?&lt;/li&gt;
&lt;li&gt;Which operating systems are supported?&lt;/li&gt;
&lt;li&gt;Is technical support available?&lt;/li&gt;
&lt;li&gt;Can resources be upgraded later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers comparing server options, &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; is one option to explore alongside other providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Monitor Your Application After Deployment
&lt;/h2&gt;

&lt;p&gt;Server selection is only the first step. Monitor CPU utilization, memory usage, disk I/O, response times, and error logs after deployment.&lt;/p&gt;

&lt;p&gt;Tools such as Prometheus, Grafana, and Linux system utilities can help identify bottlenecks before they become serious problems.&lt;/p&gt;

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

&lt;p&gt;Reliable infrastructure makes application deployment easier, but the best server is the one that matches your actual workload. Evaluate resources, network limits, support, and scalability before making a decision.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>devops</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Your Background Jobs Are Slowing Down Your API — Here’s How to Fix It</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Sun, 11 Oct 2026 05:37:59 +0000</pubDate>
      <link>https://dev.to/arthur_luca/your-background-jobs-are-slowing-down-your-api-heres-how-to-fix-it-40do</link>
      <guid>https://dev.to/arthur_luca/your-background-jobs-are-slowing-down-your-api-heres-how-to-fix-it-40do</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. I want to talk about a problem that often appears when an application starts growing.&lt;/p&gt;

&lt;p&gt;At first, everything works well. Users submit forms, upload files, receive reports, and get quick responses. But as the application becomes busier, some requests start taking several seconds to finish.&lt;/p&gt;

&lt;p&gt;The first reaction is often to upgrade the server or optimize the database. Sometimes that helps, but the real problem may be that the application is doing too much work before responding to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Understand What Is Blocking the Response
&lt;/h2&gt;

&lt;p&gt;Imagine a user requests a report. Your API receives the request and then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetches information from the database.&lt;/li&gt;
&lt;li&gt;Generates a large CSV file.&lt;/li&gt;
&lt;li&gt;Sends an email.&lt;/li&gt;
&lt;li&gt;Saves an activity log.&lt;/li&gt;
&lt;li&gt;Returns the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user must wait for all these operations to finish, even though the email and some other tasks do not need to happen before the response.&lt;/p&gt;

&lt;p&gt;This increases response time and can tie up application workers unnecessarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Move Slow Tasks to a Background Queue
&lt;/h2&gt;

&lt;p&gt;A better approach is to let the API handle the essential work, enqueue the remaining tasks, and return a response without waiting for every task to finish.&lt;/p&gt;

&lt;p&gt;A typical architecture looks like this:&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
flowchart TD&lt;br&gt;
    A[User Request] --&amp;gt; B[API Server]&lt;br&gt;
    B --&amp;gt; C[Validate and Save Data]&lt;br&gt;
    C --&amp;gt; D[Add Job to Queue]&lt;br&gt;
    D --&amp;gt; E[Return Response]&lt;br&gt;
    D --&amp;gt; F[Background Worker]&lt;br&gt;
    F --&amp;gt; G[Generate Report]&lt;br&gt;
    F --&amp;gt; H[Send Email]&lt;br&gt;
    F --&amp;gt; I[Record Job Status]&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Tools such as Celery with Redis or RabbitMQ, and BullMQ for Node.js, can help implement background processing.&lt;/p&gt;

&lt;p&gt;The right choice depends on your programming language, workload, and reliability requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A Simple Python Example
&lt;/h2&gt;

&lt;p&gt;Python applications can use a queue to separate job submission from job execution.&lt;/p&gt;

&lt;p&gt;Here is a simplified example using Python's built-in &lt;code&gt;queue&lt;/code&gt; module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Thread&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_job&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Simulate slow work
&lt;/span&gt;            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Finished: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;process_job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generate-monthly-report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;send-notification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jobs submitted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates the basic idea, but it is not a production-ready distributed queue. The queue exists only in memory, so jobs can be lost if the process stops. For production systems, consider a durable broker, retries, monitoring, and safe shutdown behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Design Jobs to Handle Retries Safely
&lt;/h2&gt;

&lt;p&gt;Background jobs can fail because an external API is unavailable, a network connection drops, or a database temporarily rejects a request.&lt;/p&gt;

&lt;p&gt;A reliable worker should have a retry policy with a reasonable delay. However, retrying can accidentally perform the same operation twice.&lt;/p&gt;

&lt;p&gt;For example, a payment notification might be sent twice if the worker completes the operation but crashes before recording success.&lt;/p&gt;

&lt;p&gt;Use idempotency where possible: processing the same job more than once should not create duplicate side effects.&lt;/p&gt;

&lt;p&gt;Also consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting a maximum retry count.&lt;/li&gt;
&lt;li&gt;Moving repeatedly failing jobs to a dead-letter queue.&lt;/li&gt;
&lt;li&gt;Recording failure reasons.&lt;/li&gt;
&lt;li&gt;Alerting when the queue backlog grows unexpectedly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Monitor the Queue, Not Just the API
&lt;/h2&gt;

&lt;p&gt;Your API may respond quickly while background jobs fall further behind.&lt;/p&gt;

&lt;p&gt;Track metrics such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Queue depth: how many jobs are waiting?&lt;/li&gt;
&lt;li&gt;Job age: how long has the oldest job been waiting?&lt;/li&gt;
&lt;li&gt;Processing time: how long does each job take?&lt;/li&gt;
&lt;li&gt;Failure rate: how many jobs fail or need retries?&lt;/li&gt;
&lt;li&gt;Worker utilization: are workers busy, idle, or overloaded?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These measurements help you determine whether you need more workers, faster job processing, or a better queue design.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Give Background Workers Enough Resources
&lt;/h2&gt;

&lt;p&gt;Background jobs still consume CPU, memory, disk, and network bandwidth. Moving work out of the API does not make that workload disappear.&lt;/p&gt;

&lt;p&gt;For example, generating thousands of reports can consume significant memory. Running too many workers simultaneously may slow down the database or affect the API.&lt;/p&gt;

&lt;p&gt;If you deploy your application on a VPS, review the available CPU, RAM, storage, and network capacity before deciding how many workers to run. You can compare options such as &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; against your application's actual workload and resource requirements.&lt;/p&gt;

&lt;p&gt;Start with a manageable number of workers, measure performance, and increase concurrency gradually.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Know When Background Processing Is Worth It
&lt;/h2&gt;

&lt;p&gt;Not every operation needs a queue. A small, fast database query usually belongs in the normal request flow.&lt;/p&gt;

&lt;p&gt;Background processing is particularly useful for tasks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending emails and notifications.&lt;/li&gt;
&lt;li&gt;Generating large reports.&lt;/li&gt;
&lt;li&gt;Processing uploaded media.&lt;/li&gt;
&lt;li&gt;Synchronizing data with external services.&lt;/li&gt;
&lt;li&gt;Running scheduled cleanup tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep essential validation and operations that must succeed before confirming a transaction in the main request flow. The goal is not to move everything into a queue; it is to move work that can safely happen later.&lt;/p&gt;

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

&lt;p&gt;Slow APIs are not always caused by weak hardware or inefficient queries. Sometimes the application is simply waiting for work that does not need to happen immediately.&lt;/p&gt;

&lt;p&gt;Separate slow tasks from user-facing requests, make jobs safe to retry, and monitor queue performance. These changes can improve responsiveness without requiring a complete rewrite.&lt;/p&gt;

&lt;p&gt;The best optimization is often not doing the same work faster, but organizing the work so users do not have to wait for it.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>performance</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why Your Database Gets Slower as Your App Grows</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Sat, 10 Oct 2026 04:24:22 +0000</pubDate>
      <link>https://dev.to/arthur_luca/why-your-database-gets-slower-as-your-app-grows-2nmp</link>
      <guid>https://dev.to/arthur_luca/why-your-database-gets-slower-as-your-app-grows-2nmp</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. One problem developers often face is that an application works perfectly when it has a few hundred records, but starts slowing down when the database grows.&lt;/p&gt;

&lt;p&gt;At first, everything seems fine. Pages load quickly, API responses are fast, and database queries finish almost instantly.&lt;/p&gt;

&lt;p&gt;Then the application grows. More users join, more records are stored, and suddenly a query that used to take milliseconds takes several seconds.&lt;/p&gt;

&lt;p&gt;The first reaction is often to upgrade the server. But sometimes, the real problem is the way the database is being queried.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Stop Fetching Every Record
&lt;/h2&gt;

&lt;p&gt;Consider this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns every column and every row in the &lt;code&gt;orders&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;That might be fine for a small test database, but it can become expensive when the table contains millions of records.&lt;/p&gt;

&lt;p&gt;If your application only needs an order ID, status, and creation date, request those fields instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You reduce the amount of data the database needs to return and the application needs to process.&lt;/p&gt;

&lt;p&gt;For large tables, you should also limit the number of rows returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Add Indexes Where They Actually Help
&lt;/h2&gt;

&lt;p&gt;Imagine your application frequently searches for orders belonging to a particular customer.&lt;/p&gt;

&lt;p&gt;Without a suitable index, the database may need to examine many rows to find matching records.&lt;/p&gt;

&lt;p&gt;You could create an index like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_orders_customer_id&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the database has an additional structure it can use to locate matching rows efficiently.&lt;/p&gt;

&lt;p&gt;However, indexes aren't free. They consume storage and can make inserts, updates, and deletes more expensive.&lt;/p&gt;

&lt;p&gt;Before adding an index, inspect the query plan using &lt;code&gt;EXPLAIN&lt;/code&gt; in your database system. Test the change against realistic data.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Avoid the N+1 Query Problem
&lt;/h2&gt;

&lt;p&gt;Suppose an application fetches 100 blog posts and then runs another query to retrieve each author's name.&lt;/p&gt;

&lt;p&gt;That can result in 101 database queries instead of one or a few efficient queries.&lt;/p&gt;

&lt;p&gt;A join can often help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The best approach depends on your schema and application, but the key idea is to avoid repeatedly querying the database for related information when it can be fetched more efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use Pagination for Large Results
&lt;/h2&gt;

&lt;p&gt;Returning thousands of records in one request can increase database work, memory usage, and response time.&lt;/p&gt;

&lt;p&gt;A simple SQL example is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a small dataset, &lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt; may be enough. For very large datasets, cursor-based pagination can perform better because large offsets may still require the database to scan and discard many rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Measure Before Changing the Server
&lt;/h2&gt;

&lt;p&gt;When a database becomes slow, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which queries take the longest?&lt;/li&gt;
&lt;li&gt;Are indexes being used?&lt;/li&gt;
&lt;li&gt;Are too many queries running per request?&lt;/li&gt;
&lt;li&gt;Is the connection pool exhausted?&lt;/li&gt;
&lt;li&gt;Is the database waiting on disk operations?&lt;/li&gt;
&lt;li&gt;Are multiple transactions blocking one another?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These checks help distinguish a query problem from a resource problem.&lt;/p&gt;

&lt;p&gt;If you've optimized your queries and confirmed that the database needs more resources, then reviewing CPU, RAM, storage performance, and network latency makes sense.&lt;/p&gt;

&lt;p&gt;For applications that need more control over their hosting environment, you can compare &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; with other providers and evaluate the resources against your database workload.&lt;/p&gt;

&lt;p&gt;Keep in mind that hosting specifications alone don't guarantee database performance. Configuration, workload, and storage behavior matter too.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A Simple Optimization Workflow
&lt;/h2&gt;

&lt;p&gt;When a query becomes slow, follow this process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure its execution time.&lt;/li&gt;
&lt;li&gt;Inspect the query plan.&lt;/li&gt;
&lt;li&gt;Check the columns used in filters and joins.&lt;/li&gt;
&lt;li&gt;Review indexes and unnecessary data retrieval.&lt;/li&gt;
&lt;li&gt;Test the optimized query with realistic data.&lt;/li&gt;
&lt;li&gt;Measure again and compare the results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Change one thing at a time so you can understand what actually improved performance.&lt;/p&gt;

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

&lt;p&gt;A growing database doesn't automatically require a bigger server.&lt;/p&gt;

&lt;p&gt;Sometimes, selecting fewer columns, adding a carefully chosen index, fixing repeated queries, or introducing better pagination can make a noticeable difference.&lt;/p&gt;

&lt;p&gt;The goal isn't to optimize every query blindly. It's to find the queries that matter, measure their behavior, and improve them based on evidence.&lt;/p&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Find and Fix Memory Leaks in Python</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Fri, 09 Oct 2026 17:06:52 +0000</pubDate>
      <link>https://dev.to/arthur_luca/how-to-find-and-fix-memory-leaks-in-python-16p0</link>
      <guid>https://dev.to/arthur_luca/how-to-find-and-fix-memory-leaks-in-python-16p0</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. Have you ever noticed a Python application using more and more RAM even though you're not doing anything unusual?&lt;/p&gt;

&lt;p&gt;At first, everything works fine. After a few hours, the application becomes slower. Eventually, it may crash with an out-of-memory error.&lt;/p&gt;

&lt;p&gt;Restarting the application might temporarily fix the problem, but it doesn't solve the underlying issue.&lt;/p&gt;

&lt;p&gt;One possible cause is a memory leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Causes Memory Leaks in Python?
&lt;/h2&gt;

&lt;p&gt;Python automatically manages memory, so you don't normally need to free objects manually.&lt;/p&gt;

&lt;p&gt;However, objects can remain in memory when your application still holds references to them.&lt;/p&gt;

&lt;p&gt;Common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storing every request in a list.&lt;/li&gt;
&lt;li&gt;Keeping old results in an unlimited cache.&lt;/li&gt;
&lt;li&gt;Accidentally retaining large objects.&lt;/li&gt;
&lt;li&gt;Running background tasks that accumulate data.&lt;/li&gt;
&lt;li&gt;Holding references to objects that are no longer needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at a simple example.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Understand the Problem
&lt;/h2&gt;

&lt;p&gt;Imagine an application that saves every incoming request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;requests_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;requests_log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the application receives thousands of requests, this list continues growing.&lt;/p&gt;

&lt;p&gt;If each item contains a large amount of data, memory consumption can increase significantly.&lt;/p&gt;

&lt;p&gt;A better approach might be to keep only the most recent entries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;

&lt;span class="n"&gt;requests_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxlen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;requests_log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the collection retains at most 1,000 entries. Choose an appropriate limit for your application, and avoid storing sensitive request data unnecessarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Track Memory With &lt;code&gt;tracemalloc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Python includes a built-in module called &lt;code&gt;tracemalloc&lt;/code&gt; that helps identify where Python allocations are happening.&lt;/p&gt;

&lt;p&gt;You don't need to install another package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tracemalloc&lt;/span&gt;

&lt;span class="n"&gt;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Run the code you want to investigate here.
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="n"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take_snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lineno&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows the source locations responsible for the largest tracked memory allocations.&lt;/p&gt;

&lt;p&gt;For a real application, take snapshots at different times and compare them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take_snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Run the workload you want to investigate.
&lt;/span&gt;
&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take_snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lineno&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the same part of your application keeps accumulating allocations, investigate that code first.&lt;/p&gt;

&lt;p&gt;Remember that &lt;code&gt;tracemalloc&lt;/code&gt; tracks Python memory allocations, not every possible source of process memory usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Check the Application's RAM Usage
&lt;/h2&gt;

&lt;p&gt;You can also monitor the Python process with &lt;code&gt;psutil&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;psutil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;

&lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;memory_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RSS memory: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rss&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; MB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RSS represents the physical memory currently resident for that process.&lt;/p&gt;

&lt;p&gt;Run this measurement at regular intervals while testing your application. If memory usage continually rises under the same workload, investigate further before assuming that you have found a leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Be Careful With Caches
&lt;/h2&gt;

&lt;p&gt;Caching can improve performance, but an unlimited cache can create a memory problem.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If every request creates a new key, the dictionary may grow indefinitely.&lt;/p&gt;

&lt;p&gt;One solution is to use a cache with a maximum size. For example, Python's &lt;code&gt;functools.lru_cache&lt;/code&gt; supports a size limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;

&lt;span class="nd"&gt;@lru_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well for suitable repeatable calculations. For applications where cached data changes frequently, consider expiration rules or an appropriate external cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Why This Matters on a VPS
&lt;/h2&gt;

&lt;p&gt;Memory leaks are especially important in long-running services, APIs, bots, workers, and background jobs.&lt;/p&gt;

&lt;p&gt;A process that gradually consumes more RAM can affect other applications running on the same server.&lt;/p&gt;

&lt;p&gt;When choosing infrastructure for a Python application, consider memory requirements, CPU allocation, storage, and expected traffic. If you're comparing hosting options, &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; is one place to review alongside other providers.&lt;/p&gt;

&lt;p&gt;But adding more RAM should not replace investigating a memory problem. More resources may delay the symptoms without fixing the cause.&lt;/p&gt;

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

&lt;p&gt;When a Python application becomes slower over time, don't immediately assume the server is too small.&lt;/p&gt;

&lt;p&gt;Measure memory usage, compare allocation snapshots, inspect growing collections, and test the application under a repeatable workload.&lt;/p&gt;

&lt;p&gt;The most useful debugging process is the one that helps you find the cause rather than repeatedly restarting the application.&lt;/p&gt;

</description>
      <category>python</category>
      <category>debugging</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>What Actually Happens When You Type a URL in Your Browser?</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Thu, 08 Oct 2026 17:10:28 +0000</pubDate>
      <link>https://dev.to/arthur_luca/what-actually-happens-when-you-type-a-url-in-your-browser-8g7</link>
      <guid>https://dev.to/arthur_luca/what-actually-happens-when-you-type-a-url-in-your-browser-8g7</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. I used to think opening a website was simple: type the URL, press Enter, and the page appears.&lt;/p&gt;

&lt;p&gt;But quite a lot happens between those two moments.&lt;/p&gt;

&lt;p&gt;Your browser has to find the server, establish a connection, send a request, receive the response, and then build the page you see.&lt;/p&gt;

&lt;p&gt;Let’s break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Browser Reads the URL
&lt;/h2&gt;

&lt;p&gt;Suppose you enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/products
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser separates this into different parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://     → Protocol
example.com  → Domain
/products    → Path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser now knows that it needs to communicate with the website using HTTPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. DNS Finds the Server
&lt;/h2&gt;

&lt;p&gt;Computers communicate using IP addresses, not domain names.&lt;/p&gt;

&lt;p&gt;So the browser needs to find the IP address behind:&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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where DNS comes in.&lt;/p&gt;

&lt;p&gt;You can think of DNS as the internet's phone book.&lt;/p&gt;

&lt;p&gt;For example:&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
      ↓
DNS lookup
      ↓
93.184.xxx.xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser can now contact the correct server.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Connection Is Established
&lt;/h2&gt;

&lt;p&gt;With HTTPS, the browser needs to establish a secure connection with the server.&lt;/p&gt;

&lt;p&gt;This involves TLS, which encrypts the communication between your browser and the website.&lt;/p&gt;

&lt;p&gt;This is why you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for most modern websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. The Browser Sends an HTTP Request
&lt;/h2&gt;

&lt;p&gt;The browser then sends a request to the server.&lt;/p&gt;

&lt;p&gt;A simplified request might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/products&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server receives the request and decides what response to return.&lt;/p&gt;

&lt;p&gt;It might return an HTML page, an image, JSON data, or something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The Server Does Its Work
&lt;/h2&gt;

&lt;p&gt;This is where the hosting environment becomes important.&lt;/p&gt;

&lt;p&gt;A simple static website may only need to return an HTML file.&lt;/p&gt;

&lt;p&gt;A dynamic application might need to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   ↓
Web server
   ↓
Application
   ↓
Database
   ↓
Application
   ↓
Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, an online store may need to query a database before showing the products.&lt;/p&gt;

&lt;p&gt;If the server is overloaded or the database is slow, the browser has to wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Browser Receives the Response
&lt;/h2&gt;

&lt;p&gt;The server might respond with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;followed by the actual HTML.&lt;/p&gt;

&lt;p&gt;The browser starts reading that HTML and discovers other files it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTML
 ├── CSS
 ├── JavaScript
 ├── Images
 └── Fonts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then requests those resources as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The Browser Builds the Page
&lt;/h2&gt;

&lt;p&gt;Finally, the browser processes the HTML, CSS, and JavaScript and turns them into the page you see.&lt;/p&gt;

&lt;p&gt;That's why a page can sometimes load the text first and images a moment later.&lt;/p&gt;

&lt;p&gt;There are multiple things happening behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Developers
&lt;/h2&gt;

&lt;p&gt;Understanding this process makes website performance easier to understand.&lt;/p&gt;

&lt;p&gt;For example, if DNS is slow, the first connection can be delayed.&lt;/p&gt;

&lt;p&gt;If the server takes too long to respond, the browser waits.&lt;/p&gt;

&lt;p&gt;If the HTML loads quickly but there are hundreds of large images and JavaScript files, the page can still feel slow.&lt;/p&gt;

&lt;p&gt;That's why improving website speed isn't always about buying a faster server.&lt;/p&gt;

&lt;p&gt;It can involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;Server response time&lt;/li&gt;
&lt;li&gt;Database queries&lt;/li&gt;
&lt;li&gt;Image sizes&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;CDN configuration&lt;/li&gt;
&lt;li&gt;Network latency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where Does a VPS Fit In?
&lt;/h2&gt;

&lt;p&gt;A VPS gives developers more control over the server environment.&lt;/p&gt;

&lt;p&gt;You can configure the web server, install specific software, manage applications, and choose resources according to the workload.&lt;/p&gt;

&lt;p&gt;If you're comparing VPS options, &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; is one option to look at alongside other providers. The important thing is to compare the actual resources, storage, network, location, and management options rather than choosing only by price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The next time you type a URL and a website appears almost instantly, remember that your browser didn't simply "open a page."&lt;/p&gt;

&lt;p&gt;It found a server, established a connection, sent a request, received data, downloaded additional resources, and rendered everything on your screen.&lt;/p&gt;

&lt;p&gt;All of that can happen in just a few seconds.&lt;/p&gt;

&lt;p&gt;That's one of the things I find interesting about web development: something that looks simple to a user can involve a surprising number of steps underneath.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>devops</category>
      <category>learning</category>
    </item>
    <item>
      <title>I Built a Simple File Backup System With Python for My VPS</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:40:59 +0000</pubDate>
      <link>https://dev.to/arthur_luca/i-built-a-simple-file-backup-system-with-python-for-my-vps-ldi</link>
      <guid>https://dev.to/arthur_luca/i-built-a-simple-file-backup-system-with-python-for-my-vps-ldi</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. One thing I learned after working with servers is that having a backup is not enough.&lt;/p&gt;

&lt;p&gt;You also need to know &lt;strong&gt;where the backup is, when it was created, and whether you can actually restore it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For a small VPS project, I wanted something simpler than a full backup platform, so I built a small Python script that creates compressed backups automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Script Does
&lt;/h2&gt;

&lt;p&gt;The script will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select a folder to back up&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.tar.gz&lt;/code&gt; archive&lt;/li&gt;
&lt;li&gt;Add the current date and time to the filename&lt;/li&gt;
&lt;li&gt;Store the backup in another directory&lt;/li&gt;
&lt;li&gt;Remove old backups after a certain number of days&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the basic version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="n"&gt;SOURCE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/www/mywebsite&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;BACKUP_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/home/backups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;KEEP_DAYS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;

&lt;span class="n"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d_%H-%M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;backup_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BACKUP_DIR&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;website_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.tar.gz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;tarfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backup_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w:gz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;archive&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOURCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arcname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SOURCE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Backup created: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;backup_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every backup gets a unique name, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;website_2026-10-07_19-30.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That makes it much easier to identify when a backup was created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatically Remove Old Backups
&lt;/h2&gt;

&lt;p&gt;Keeping every backup forever can eventually fill your disk.&lt;/p&gt;

&lt;p&gt;We can remove files older than seven days:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.tar.gz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromtimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;st_mtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;KEEP_DAYS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deleted old backup: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the backup directory won't continue growing forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Keep the Only Backup on the Same VPS
&lt;/h2&gt;

&lt;p&gt;This is probably the most important part.&lt;/p&gt;

&lt;p&gt;If your VPS has a disk failure and your backup is stored on that same disk, you may lose both.&lt;/p&gt;

&lt;p&gt;For anything important, I would keep another copy somewhere else, such as object storage or another server.&lt;/p&gt;

&lt;p&gt;A VPS is useful because you get control over the environment, but that also means you need to think about your own backup strategy.&lt;/p&gt;

&lt;p&gt;When comparing VPS providers, I would look at storage, backup options, disk type, network, and server location rather than focusing only on CPU and RAM. For example, you can compare these factors with &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS hosting&lt;/a&gt; and other providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating the Backup
&lt;/h2&gt;

&lt;p&gt;Linux has a simple tool called &lt;code&gt;cron&lt;/code&gt; that can run the script automatically.&lt;/p&gt;

&lt;p&gt;Open the cron configuration:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 3 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/bin/python3 /home/scripts/backup.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the backup every day at 3:00 AM.&lt;/p&gt;

&lt;p&gt;You can change the time depending on when your server has the least activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always Test Your Backups
&lt;/h2&gt;

&lt;p&gt;A backup that has never been restored is only a theory.&lt;/p&gt;

&lt;p&gt;Every once in a while, I would create a test directory and extract one of the backup files:&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;mkdir &lt;/span&gt;backup-test
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; website_2026-10-07_19-30.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; backup-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check whether the important files are actually there.&lt;/p&gt;

&lt;p&gt;This simple step can save a lot of trouble later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;You don't always need a complicated backup system for a small project.&lt;/p&gt;

&lt;p&gt;A simple automated script can already give you a good starting point.&lt;/p&gt;

&lt;p&gt;But the important rule is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backup → Store another copy → Test the restore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is much safer than simply assuming your backup will work when you need it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to Move a Node API From a Free Host to a VPS (Step by Step)</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Mon, 05 Oct 2026 14:58:09 +0000</pubDate>
      <link>https://dev.to/arthur_luca/how-to-move-a-node-api-from-a-free-host-to-a-vps-step-by-step-3koh</link>
      <guid>https://dev.to/arthur_luca/how-to-move-a-node-api-from-a-free-host-to-a-vps-step-by-step-3koh</guid>
      <description>&lt;p&gt;Hi, I'm Arthur.&lt;/p&gt;

&lt;p&gt;Free hosting is a great way to get your first backend online.&lt;/p&gt;

&lt;p&gt;You can build an API, connect a frontend, test your idea, and start getting users without worrying about server costs.&lt;/p&gt;

&lt;p&gt;But eventually, you may notice things like cold starts, memory limits, sleeping applications, restricted background processes, or simply no SSH access when something goes wrong.&lt;/p&gt;

&lt;p&gt;That's usually when a VPS starts making sense.&lt;/p&gt;

&lt;p&gt;Instead of the hosting platform deciding how your application runs, you get your own Linux environment and control over the software, processes, logs, and configuration.&lt;/p&gt;

&lt;p&gt;In this guide, I'll move a small Node.js/Express API from a free hosting environment to an Ubuntu VPS.&lt;/p&gt;

&lt;p&gt;I'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a non-root user&lt;/li&gt;
&lt;li&gt;Installing Node.js and Nginx&lt;/li&gt;
&lt;li&gt;Deploying the application&lt;/li&gt;
&lt;li&gt;Running Node with systemd&lt;/li&gt;
&lt;li&gt;Configuring Nginx&lt;/li&gt;
&lt;li&gt;Adding HTTPS&lt;/li&gt;
&lt;li&gt;Creating a simple deployment script&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before You Start
&lt;/h2&gt;

&lt;p&gt;You'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Ubuntu 22.04 or 24.04 VPS&lt;/li&gt;
&lt;li&gt;Root or sudo access&lt;/li&gt;
&lt;li&gt;A domain or subdomain&lt;/li&gt;
&lt;li&gt;Your Node.js application in a Git repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll use this example domain throughout the guide:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Before continuing, create an &lt;strong&gt;A record&lt;/strong&gt; pointing your domain to the VPS IP address.&lt;/p&gt;

&lt;p&gt;DNS changes can take some time, and you'll need the domain working before configuring HTTPS.&lt;/p&gt;

&lt;p&gt;If you're looking for a small VPS for testing, &lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer&lt;/a&gt; is one option you can compare. The important thing is that your VPS gives you the root or sudo access needed for the setup below.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Create a Non-Root User
&lt;/h2&gt;

&lt;p&gt;You don't want to run your application as root.&lt;/p&gt;

&lt;p&gt;Connect to your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new user:&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;p&gt;Copy your SSH configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;--archive&lt;/span&gt; &lt;span class="nt"&gt;--chown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;deploy:deploy ~/.ssh /home/deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open a second terminal and test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh deploy@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure this works before changing your SSH configuration.&lt;/p&gt;

&lt;p&gt;Once you've confirmed the new account works, edit:&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;nano /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PermitRootLogin no
PasswordAuthentication no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart SSH:&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 restart ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep your existing SSH session open while testing the new login.&lt;/p&gt;

&lt;p&gt;That way, if you make a configuration mistake, you still have a working session.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Install Node.js and Nginx
&lt;/h2&gt;

&lt;p&gt;Update the 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;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Node.js LTS repository:&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://deb.nodesource.com/setup_lts.x | &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; bash -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install Node.js, Nginx, and Git:&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; nodejs nginx git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
npm &lt;span class="nt"&gt;--version&lt;/span&gt;
nginx &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure the Firewall
&lt;/h3&gt;

&lt;p&gt;If UFW isn't already configured:&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 OpenSSH
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow &lt;span class="s1"&gt;'Nginx Full'&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order matters.&lt;/p&gt;

&lt;p&gt;Always allow SSH &lt;strong&gt;before&lt;/strong&gt; enabling the firewall, otherwise you can accidentally lock yourself out of the server.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Put Your Application on the Server
&lt;/h2&gt;

&lt;p&gt;Move into the deploy user's home directory:&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;cd&lt;/span&gt; /home/deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_USER/YOUR_REPO.git api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the project:&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;cd &lt;/span&gt;api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install production dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For testing, your Express application might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/health&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that I'm binding the application to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's intentional.&lt;/p&gt;

&lt;p&gt;Nginx will communicate with Node locally, while the public internet only reaches Nginx.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Keep Node Running With systemd
&lt;/h2&gt;

&lt;p&gt;On many free hosting platforms, the provider automatically starts your application again if it crashes.&lt;/p&gt;

&lt;p&gt;On your own VPS, you need to configure that yourself.&lt;/p&gt;

&lt;p&gt;That's where &lt;code&gt;systemd&lt;/code&gt; comes in.&lt;/p&gt;

&lt;p&gt;First, create a file for environment variables:&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;nano /etc/api.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL=postgres://...
JWT_SECRET=change-this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Protect the file:&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 chmod &lt;/span&gt;600 /etc/api.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create the systemd service:&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;nano /etc/systemd/system/api.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;My Node API&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/deploy/api&lt;/span&gt;
&lt;span class="py"&gt;EnvironmentFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/etc/api.env&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;PORT=3000&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/node server.js&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;RestartSec&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload systemd:&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 daemon-reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the API:&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 &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; api &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also test the API locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:3000/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;enable&lt;/code&gt; command is important because it makes the service start automatically after a server reboot.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Put Nginx in Front of Node
&lt;/h2&gt;

&lt;p&gt;Node is running on port &lt;code&gt;3000&lt;/code&gt;, but we don't want users accessing that port directly.&lt;/p&gt;

&lt;p&gt;Nginx will act as the reverse proxy.&lt;/p&gt;

&lt;p&gt;Create a new Nginx configuration:&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;nano /etc/nginx/sites-available/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Enable the configuration:&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 ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/api /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test 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;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the configuration is valid:&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 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now visit:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Your request should reach Nginx first, which then forwards it to Node.&lt;/p&gt;

&lt;p&gt;If your Express application uses secure cookies, rate limiting, or other features that depend on the original request information, you may also need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trust proxy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Add HTTPS
&lt;/h2&gt;

&lt;p&gt;At this point, the API works over HTTP.&lt;/p&gt;

&lt;p&gt;The next step is HTTPS.&lt;/p&gt;

&lt;p&gt;Install Certbot:&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; certbot python3-certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then request a certificate:&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;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; api.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Certbot can update the Nginx configuration automatically.&lt;/p&gt;

&lt;p&gt;Afterward, test renewal:&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;certbot renew &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is configured correctly, your API should now be available over HTTPS.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Create a Simple Deploy Script
&lt;/h2&gt;

&lt;p&gt;Manually pulling the repository and restarting the application every time gets old quickly.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /home/deploy/deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&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="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; /home/deploy/api

git pull origin main
npm ci &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart api

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Deployed."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it executable:&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;chmod&lt;/span&gt; +x /home/deploy/deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can deploy with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to run it remotely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh deploy@YOUR_SERVER_IP ./deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, you can connect this script to GitHub Actions and turn the process into a basic CI/CD workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Now Have
&lt;/h2&gt;

&lt;p&gt;At this point, the setup looks roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   |
   v
Nginx :443
   |
   v
Node.js :3000
   |
   v
Your API
   |
   v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nginx handles the public traffic and HTTPS.&lt;/p&gt;

&lt;p&gt;Node handles the application.&lt;/p&gt;

&lt;p&gt;systemd makes sure the application stays running.&lt;/p&gt;

&lt;p&gt;And your deploy script handles basic updates.&lt;/p&gt;

&lt;p&gt;It's a simple setup, but it's enough for many small APIs and personal projects.&lt;/p&gt;




&lt;h1&gt;
  
  
  What You Take Responsibility For With a VPS
&lt;/h1&gt;

&lt;p&gt;Moving from free hosting to a VPS gives you more control, but that also means more responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updates
&lt;/h3&gt;

&lt;p&gt;Keep the operating system and installed packages updated.&lt;/p&gt;

&lt;p&gt;You can install automatic security updates with:&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;unattended-upgrades
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Backups
&lt;/h3&gt;

&lt;p&gt;If your database is running on the same server, don't assume the VPS itself is a backup.&lt;/p&gt;

&lt;p&gt;For example, PostgreSQL backups can be created with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_dump DATABASE_NAME &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But don't keep your only backup on the same server.&lt;/p&gt;

&lt;p&gt;If the server disappears, the backup disappears with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;You don't need an expensive monitoring system for a small project.&lt;/p&gt;

&lt;p&gt;A simple uptime monitor checking:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;is a good starting point.&lt;/p&gt;




&lt;h1&gt;
  
  
  When Should You Actually Move to a VPS?
&lt;/h1&gt;

&lt;p&gt;I wouldn't automatically recommend a VPS for every project.&lt;/p&gt;

&lt;p&gt;If you're building a prototype and the free tier works, stay there.&lt;/p&gt;

&lt;p&gt;Free hosting can be perfectly fine for learning and testing.&lt;/p&gt;

&lt;p&gt;I'd consider moving when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your API keeps going to sleep&lt;/li&gt;
&lt;li&gt;Cold starts are affecting users&lt;/li&gt;
&lt;li&gt;You need background workers&lt;/li&gt;
&lt;li&gt;You need a database alongside the API&lt;/li&gt;
&lt;li&gt;You need SSH access&lt;/li&gt;
&lt;li&gt;You need more control over the server&lt;/li&gt;
&lt;li&gt;Your application is consistently hitting CPU or memory limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest advantage isn't simply getting more resources.&lt;/p&gt;

&lt;p&gt;It's getting control.&lt;/p&gt;

&lt;p&gt;You decide what runs.&lt;/p&gt;

&lt;p&gt;You decide how it is configured.&lt;/p&gt;

&lt;p&gt;And when something breaks, you can actually log into the machine and investigate it.&lt;/p&gt;

&lt;p&gt;That's the part I appreciate most about having a VPS.&lt;/p&gt;

&lt;p&gt;If you're practicing this setup yourself, a small VPS from HelloServer or another provider can be enough to go through the entire process without needing a large production server.&lt;/p&gt;

&lt;p&gt;Start small, break things, rebuild the server, and learn what each component actually does.&lt;/p&gt;

&lt;p&gt;That's usually more valuable than simply following a deployment tutorial once.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>8 VPS Performance Details Developers Should Actually Know</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Sun, 04 Oct 2026 05:22:02 +0000</pubDate>
      <link>https://dev.to/arthur_luca/8-vps-performance-details-developers-should-actually-know-15bj</link>
      <guid>https://dev.to/arthur_luca/8-vps-performance-details-developers-should-actually-know-15bj</guid>
      <description>&lt;p&gt;Hello, I’m Arthur.&lt;/p&gt;

&lt;p&gt;If you work with VPS servers, you probably already know the usual specs: vCPU, RAM, storage, and bandwidth.&lt;/p&gt;

&lt;p&gt;But those numbers don't always explain why one server feels faster than another.&lt;/p&gt;

&lt;p&gt;Once you start running databases, APIs, containers, background workers, or other demanding workloads, a few less obvious things start to matter.&lt;/p&gt;

&lt;p&gt;Here are 8 VPS performance details I think developers should know.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Check CPU Steal Time
&lt;/h2&gt;

&lt;p&gt;Your VPS may show low CPU usage and still feel slow.&lt;/p&gt;

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

&lt;p&gt;In a virtualized environment, your virtual CPU shares physical CPU resources with other workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU steal time&lt;/strong&gt; shows how much time your VM wanted CPU but had to wait for it.&lt;/p&gt;

&lt;p&gt;If steal time becomes consistently high, the problem may not be your code.&lt;/p&gt;

&lt;p&gt;The underlying host could be heavily loaded.&lt;/p&gt;

&lt;p&gt;That's something worth checking before spending time optimizing an application that isn't actually the main problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. vCPU Count Doesn't Tell the Whole Story
&lt;/h2&gt;

&lt;p&gt;“8 vCPU” sounds straightforward.&lt;/p&gt;

&lt;p&gt;But 8 vCPUs on one physical CPU platform aren't necessarily equal to 8 vCPUs on another.&lt;/p&gt;

&lt;p&gt;CPU generation, architecture, clock behavior, virtualization, and resource allocation can all affect real performance.&lt;/p&gt;

&lt;p&gt;For CPU-heavy workloads, benchmarking the actual server is much more useful than comparing the vCPU number alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. NVMe Doesn't Guarantee the Same I/O Performance
&lt;/h2&gt;

&lt;p&gt;Developers often see NVMe and assume the storage problem is solved.&lt;/p&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Two VPS providers can both offer NVMe while delivering very different I/O performance.&lt;/p&gt;

&lt;p&gt;Your workload may depend on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random reads&lt;/li&gt;
&lt;li&gt;Random writes&lt;/li&gt;
&lt;li&gt;Sequential I/O&lt;/li&gt;
&lt;li&gt;IOPS&lt;/li&gt;
&lt;li&gt;Storage latency&lt;/li&gt;
&lt;li&gt;Queue depth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A database can be especially sensitive to random I/O and latency.&lt;/p&gt;

&lt;p&gt;So if an application is slow while CPU usage looks normal, check disk latency and I/O wait before assuming you need more CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Network Speed and Latency Are Different
&lt;/h2&gt;

&lt;p&gt;A server with a 1 Gbps connection isn't automatically going to give you low-latency connections.&lt;/p&gt;

&lt;p&gt;For distributed applications, APIs, databases, and microservices, latency can matter more than maximum bandwidth.&lt;/p&gt;

&lt;p&gt;A server might have plenty of bandwidth but a poor network route to another service.&lt;/p&gt;

&lt;p&gt;That's why server location can be an actual performance decision, not just a geographical preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Load Average Isn't Just CPU Usage
&lt;/h2&gt;

&lt;p&gt;Linux load average is another metric that's easy to misunderstand.&lt;/p&gt;

&lt;p&gt;A high load doesn't always mean your CPU is running at 100%.&lt;/p&gt;

&lt;p&gt;Processes waiting for certain resources, including I/O, can contribute to system load.&lt;/p&gt;

&lt;p&gt;For example, you could have a server with moderate CPU usage but a high load because processes are waiting on storage.&lt;/p&gt;

&lt;p&gt;Looking at load average together with CPU usage, I/O wait, and disk latency gives you a much clearer picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Swap Usage Doesn't Automatically Mean You Need More RAM
&lt;/h2&gt;

&lt;p&gt;Seeing swap usage can be alarming.&lt;/p&gt;

&lt;p&gt;But a small amount of swap activity doesn't automatically mean the VPS needs more RAM.&lt;/p&gt;

&lt;p&gt;Linux can move less frequently used memory pages to swap while keeping RAM available for filesystem caching.&lt;/p&gt;

&lt;p&gt;The more important question is whether the system is under &lt;strong&gt;memory pressure&lt;/strong&gt; and actively swapping because it doesn't have enough memory.&lt;/p&gt;

&lt;p&gt;Heavy swapping is a different situation.&lt;/p&gt;

&lt;p&gt;If the system constantly moves data between RAM and swap, application performance can suffer badly.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Containers Still Depend on the Host
&lt;/h2&gt;

&lt;p&gt;Docker makes it easy to run multiple services on a VPS.&lt;/p&gt;

&lt;p&gt;But containers don't magically create extra CPU, RAM, or disk performance.&lt;/p&gt;

&lt;p&gt;If five containers are competing for the same resources, they can still affect each other.&lt;/p&gt;

&lt;p&gt;This is why resource limits and monitoring matter.&lt;/p&gt;

&lt;p&gt;For example, a background worker consuming all available CPU can make an API container appear slow even though the API itself hasn't changed.&lt;/p&gt;

&lt;p&gt;Container-level monitoring can help identify which service is actually responsible.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Bigger VPS Isn't Always the Right Fix
&lt;/h2&gt;

&lt;p&gt;This is probably the most useful lesson.&lt;/p&gt;

&lt;p&gt;When an application becomes slow, upgrading from 4 vCPU to 8 vCPU feels like the obvious solution.&lt;/p&gt;

&lt;p&gt;Sometimes it works.&lt;/p&gt;

&lt;p&gt;Sometimes it doesn't.&lt;/p&gt;

&lt;p&gt;If the actual bottleneck is database queries, storage latency, network latency, memory pressure, or an inefficient background process, doubling the CPU won't solve the real problem.&lt;/p&gt;

&lt;p&gt;Before upgrading, find the bottleneck.&lt;/p&gt;

&lt;p&gt;Check the application.&lt;/p&gt;

&lt;p&gt;Check the database.&lt;/p&gt;

&lt;p&gt;Check the disk.&lt;/p&gt;

&lt;p&gt;Check memory pressure.&lt;/p&gt;

&lt;p&gt;Check network behavior.&lt;/p&gt;

&lt;p&gt;Then decide what needs to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Check Before Choosing a VPS
&lt;/h2&gt;

&lt;p&gt;I don't look at the specification table alone anymore.&lt;/p&gt;

&lt;p&gt;I try to match the server to the workload.&lt;/p&gt;

&lt;p&gt;A PostgreSQL-heavy application has different requirements from a static website.&lt;/p&gt;

&lt;p&gt;A Kubernetes cluster has different requirements from a small API.&lt;/p&gt;

&lt;p&gt;A data-processing workload may care much more about CPU performance and storage I/O.&lt;/p&gt;

&lt;p&gt;If you're comparing VPS providers, &lt;strong&gt;&lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS&lt;/a&gt;&lt;/strong&gt; is one option worth checking alongside other providers, but the important part is matching the resources to what your application actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;VPS performance isn't just about how many cores or how much RAM you buy.&lt;/p&gt;

&lt;p&gt;The interesting part is what happens when your workload actually starts using those resources.&lt;/p&gt;

&lt;p&gt;CPU steal time, I/O wait, storage latency, network routing, memory pressure, and container resource limits can all become bottlenecks.&lt;/p&gt;

&lt;p&gt;So the next time a VPS feels slow, don't immediately upgrade it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure first. Find the bottleneck. Then change the resource that is actually limiting you.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Small Server Mistakes That Can Cause Big Problems</title>
      <dc:creator>Arthur</dc:creator>
      <pubDate>Sat, 03 Oct 2026 07:50:52 +0000</pubDate>
      <link>https://dev.to/arthur_luca/the-small-server-mistakes-that-can-cause-big-problems-3aem</link>
      <guid>https://dev.to/arthur_luca/the-small-server-mistakes-that-can-cause-big-problems-3aem</guid>
      <description>&lt;p&gt;Hello, I’m Arthur. I want to share something I learned while working with websites and applications.&lt;/p&gt;

&lt;p&gt;When something breaks on a server, we usually look for a big reason.&lt;/p&gt;

&lt;p&gt;A server crashed.&lt;/p&gt;

&lt;p&gt;The application has too much traffic.&lt;/p&gt;

&lt;p&gt;The database is overloaded.&lt;/p&gt;

&lt;p&gt;But sometimes the problem starts with something very small.&lt;/p&gt;

&lt;p&gt;A forgotten process.&lt;/p&gt;

&lt;p&gt;A full disk.&lt;/p&gt;

&lt;p&gt;An old log file.&lt;/p&gt;

&lt;p&gt;A wrong cron job.&lt;/p&gt;

&lt;p&gt;These little things can slowly turn into bigger problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Full Disk Can Break More Than You Expect
&lt;/h2&gt;

&lt;p&gt;This is one of those problems that is easy to miss.&lt;/p&gt;

&lt;p&gt;You check CPU usage.&lt;/p&gt;

&lt;p&gt;You check RAM.&lt;/p&gt;

&lt;p&gt;Everything looks normal.&lt;/p&gt;

&lt;p&gt;But your disk is almost full.&lt;/p&gt;

&lt;p&gt;Once storage gets close to its limit, applications can start behaving strangely. Logs may fail to write, databases may have trouble, and applications that need temporary files can run into errors.&lt;/p&gt;

&lt;p&gt;That's why disk space should be part of regular server monitoring.&lt;/p&gt;

&lt;p&gt;Don't wait until the server tells you there is no space left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Old Logs Can Take More Space Than You Think
&lt;/h2&gt;

&lt;p&gt;Logs are useful.&lt;/p&gt;

&lt;p&gt;They help you understand what happened when something goes wrong.&lt;/p&gt;

&lt;p&gt;But logs can also grow quietly for weeks or months.&lt;/p&gt;

&lt;p&gt;A server running several applications can generate a surprising amount of log data.&lt;/p&gt;

&lt;p&gt;If nobody checks them, they can slowly consume storage.&lt;/p&gt;

&lt;p&gt;Log rotation and cleanup are simple things, but they can prevent unnecessary problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cron Jobs Can Become a Hidden Problem
&lt;/h2&gt;

&lt;p&gt;Cron jobs are great for automation.&lt;/p&gt;

&lt;p&gt;You can use them for backups, reports, cleanup tasks, scripts, and many other jobs.&lt;/p&gt;

&lt;p&gt;But here's the problem.&lt;/p&gt;

&lt;p&gt;A cron job that takes 10 seconds today might take much longer when your database or number of files grows.&lt;/p&gt;

&lt;p&gt;And if the same job starts again before the previous one finishes, you can end up with multiple copies running at the same time.&lt;/p&gt;

&lt;p&gt;That can put unnecessary pressure on the server.&lt;/p&gt;

&lt;p&gt;So don't just create a cron job and forget about it.&lt;/p&gt;

&lt;p&gt;Check what it does and how long it takes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Too Many Services
&lt;/h2&gt;

&lt;p&gt;When setting up a server, it's tempting to install everything you might need.&lt;/p&gt;

&lt;p&gt;A web server.&lt;/p&gt;

&lt;p&gt;A database.&lt;/p&gt;

&lt;p&gt;Docker.&lt;/p&gt;

&lt;p&gt;Monitoring.&lt;/p&gt;

&lt;p&gt;Control panels.&lt;/p&gt;

&lt;p&gt;Extra tools.&lt;/p&gt;

&lt;p&gt;Testing software.&lt;/p&gt;

&lt;p&gt;But every service adds another process to manage and another thing that may consume resources.&lt;/p&gt;

&lt;p&gt;A cleaner server is usually easier to understand.&lt;/p&gt;

&lt;p&gt;If you don't need a service, there is little reason to keep it running.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Server Resources Don't Fix Bad Configuration
&lt;/h2&gt;

&lt;p&gt;Let's say your application is slow.&lt;/p&gt;

&lt;p&gt;You move it to a VPS with more CPU and RAM.&lt;/p&gt;

&lt;p&gt;The problem is still there.&lt;/p&gt;

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

&lt;p&gt;Because the problem may not have been the amount of resources.&lt;/p&gt;

&lt;p&gt;It could be a slow database query.&lt;/p&gt;

&lt;p&gt;A badly configured web server.&lt;/p&gt;

&lt;p&gt;A process using too many connections.&lt;/p&gt;

&lt;p&gt;A memory leak.&lt;/p&gt;

&lt;p&gt;Or an application making unnecessary requests.&lt;/p&gt;

&lt;p&gt;This is why I prefer checking the actual bottleneck before upgrading a server.&lt;/p&gt;

&lt;p&gt;If you are choosing a VPS for a project, compare the resources with your actual workload. For example, &lt;strong&gt;&lt;a href="https://helloserver.tech/vps-hosting/" rel="noopener noreferrer"&gt;HelloServer VPS&lt;/a&gt;&lt;/strong&gt; offers VPS hosting that can be considered when planning a server setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backups Need to Be Tested
&lt;/h2&gt;

&lt;p&gt;This one sounds obvious, but it's easy to forget.&lt;/p&gt;

&lt;p&gt;You create a backup.&lt;/p&gt;

&lt;p&gt;The backup finishes successfully.&lt;/p&gt;

&lt;p&gt;You assume everything is fine.&lt;/p&gt;

&lt;p&gt;But have you ever tried restoring it?&lt;/p&gt;

&lt;p&gt;A backup that cannot be restored when you need it isn't very useful.&lt;/p&gt;

&lt;p&gt;Even an occasional test restore can give you much more confidence in your backup system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Updates Are Easy to Delay
&lt;/h2&gt;

&lt;p&gt;Developers are busy.&lt;/p&gt;

&lt;p&gt;You finish a project and think:&lt;/p&gt;

&lt;p&gt;“I'll update the server later.”&lt;/p&gt;

&lt;p&gt;Then later becomes next week.&lt;/p&gt;

&lt;p&gt;Then next month.&lt;/p&gt;

&lt;p&gt;The problem is that servers aren't something you should configure once and forget forever.&lt;/p&gt;

&lt;p&gt;Operating systems, packages, frameworks, libraries, and applications can all need updates.&lt;/p&gt;

&lt;p&gt;Keeping a simple maintenance routine is much easier than trying to fix everything after a problem appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Ignore Small Warning Signs
&lt;/h2&gt;

&lt;p&gt;One of the most useful habits I've developed is paying attention to small changes.&lt;/p&gt;

&lt;p&gt;A command that suddenly takes longer.&lt;/p&gt;

&lt;p&gt;Disk usage increasing every day.&lt;/p&gt;

&lt;p&gt;RAM usage slowly going up.&lt;/p&gt;

&lt;p&gt;A backup taking twice as long.&lt;/p&gt;

&lt;p&gt;More database connections than usual.&lt;/p&gt;

&lt;p&gt;None of these automatically means something is broken.&lt;/p&gt;

&lt;p&gt;But they are useful signals.&lt;/p&gt;

&lt;p&gt;Small changes can help you find a problem before it becomes a major one.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Simple Server Checklist
&lt;/h2&gt;

&lt;p&gt;When I manage or troubleshoot a server, I like to keep the basics simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check CPU usage&lt;/li&gt;
&lt;li&gt;Check available RAM&lt;/li&gt;
&lt;li&gt;Check disk space&lt;/li&gt;
&lt;li&gt;Check disk activity&lt;/li&gt;
&lt;li&gt;Review important logs&lt;/li&gt;
&lt;li&gt;Check running processes&lt;/li&gt;
&lt;li&gt;Review cron jobs&lt;/li&gt;
&lt;li&gt;Test backups&lt;/li&gt;
&lt;li&gt;Keep packages updated&lt;/li&gt;
&lt;li&gt;Remove services that aren't needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need to become a server expert overnight.&lt;/p&gt;

&lt;p&gt;Start with these basics and learn what each one tells you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Main Lesson
&lt;/h2&gt;

&lt;p&gt;Server management isn't always about fixing huge problems.&lt;/p&gt;

&lt;p&gt;A lot of it is noticing small things before they become huge problems.&lt;/p&gt;

&lt;p&gt;A little monitoring today can save hours of troubleshooting later.&lt;/p&gt;

&lt;p&gt;And when something does go wrong, don't immediately assume that you need a bigger server.&lt;/p&gt;

&lt;p&gt;First ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is actually causing the problem?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question will usually take you further than simply adding more CPU or RAM.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
