<?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: Oscar Ricardo Sánche Gutierréz</title>
    <description>The latest articles on DEV Community by Oscar Ricardo Sánche Gutierréz (@oscar_ricardosncheguti).</description>
    <link>https://dev.to/oscar_ricardosncheguti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3804416%2F2f910017-a0c5-45f4-99ba-cef5a096c7de.jpg</url>
      <title>DEV Community: Oscar Ricardo Sánche Gutierréz</title>
      <link>https://dev.to/oscar_ricardosncheguti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oscar_ricardosncheguti"/>
    <language>en</language>
    <item>
      <title>RustDesk: How to Create a Secure Private Remote Access Network</title>
      <dc:creator>Oscar Ricardo Sánche Gutierréz</dc:creator>
      <pubDate>Tue, 31 Mar 2026 00:47:18 +0000</pubDate>
      <link>https://dev.to/oscar_ricardosncheguti/rustdesk-how-to-create-a-secure-private-remote-access-network-1dj4</link>
      <guid>https://dev.to/oscar_ricardosncheguti/rustdesk-how-to-create-a-secure-private-remote-access-network-1dj4</guid>
      <description>&lt;p&gt;RustDesk is the perfect solution for secure remote access, open-source and under your complete control. In this article I'll show you how to deploy your own server, configure it as a closed network, and secure it for corporate use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgctjvatzp24vwqaqafx3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgctjvatzp24vwqaqafx3.gif" alt="Architecture" width="700" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagram created with &lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;https://savnet.co&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RustDesk is an open-source alternative to tools like TeamViewer or AnyDesk, but with a key advantage: &lt;strong&gt;you can self-host it&lt;/strong&gt;. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complete control&lt;/strong&gt; over your data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No connection limits&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero licensing costs&lt;/strong&gt; (only server costs)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Prepare the Server
&lt;/h2&gt;

&lt;p&gt;You'll need a Linux server with Ubuntu 22.04 or 24.04 LTS with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 vCPU, 2 GB RAM&lt;/strong&gt; (enough for dozens of connections)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu 22.04 LTS&lt;/strong&gt; or higher&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fixed public IP&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1nozchz2tacuisj03xp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1nozchz2tacuisj03xp.png" alt="New DigitalOcean server" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Initial Server Configuration
&lt;/h2&gt;

&lt;p&gt;Connect via SSH and update the system:&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
apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
timedatectl set-timezone America/New_York  &lt;span class="c"&gt;# Adjust to your timezone&lt;/span&gt;
reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Install Docker and Docker Compose
&lt;/h2&gt;

&lt;p&gt;Follow the official Docker installation:&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;# Install dependencies&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg

&lt;span class="c"&gt;# Add official Docker repository&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.asc
&lt;span class="nb"&gt;chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.asc

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.asc] &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="se"&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;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

&lt;span class="c"&gt;# Install Docker&lt;/span&gt;
apt update
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
docker compose version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1avbg4jwfgvd0dd1vz3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1avbg4jwfgvd0dd1vz3.png" alt="Docker versions" width="377" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Prepare RustDesk Structure
&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/rustdesk-server/data
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/rustdesk-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Create the docker-compose.yml File
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;nano /opt/rustdesk-server/compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hbbr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rustdesk/rustdesk-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/root&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host"&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;hbbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbs&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rustdesk/rustdesk-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbs&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/root&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: We use &lt;code&gt;network_mode: "host"&lt;/code&gt; because RustDesk needs to see the real host IP to function correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Start the Services
&lt;/h2&gt;



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

&lt;span class="c"&gt;# Verify they're running&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# View logs&lt;/span&gt;
docker compose logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmx4j1ehfg2x9p1rti10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmx4j1ehfg2x9p1rti10.png" alt="Docker services" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Get the Server Public Key
&lt;/h2&gt;

&lt;p&gt;This key is crucial for clients to trust 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;&lt;span class="nb"&gt;cat&lt;/span&gt; /opt/rustdesk-server/data/id_ed25519.pub &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the result. It will look something like:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 8: Configure the Firewall
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ports needed for RustDesk OSS:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21115&lt;/strong&gt; - Main service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21116&lt;/strong&gt; - ID service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UDP 21116&lt;/strong&gt; - For better performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21117&lt;/strong&gt; - Relay service&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configure UFW on the server:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install firewall ufw&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ufw

&lt;span class="c"&gt;# Allow SSH from YOUR public IP&lt;/span&gt;
ufw allow from your_admin_ip to any port 22
&lt;span class="c"&gt;# IF YOU DON'T HAVE a public IP, allow any origin with&lt;/span&gt;
ufw allow 22

&lt;span class="c"&gt;# Allow RustDesk ports&lt;/span&gt;
ufw allow 21115/tcp
ufw allow 21116/tcp
ufw allow 21116/udp
ufw allow 21117/tcp

&lt;span class="c"&gt;# Enable firewall&lt;/span&gt;
ufw &lt;span class="nb"&gt;enable
&lt;/span&gt;ufw status verbose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8bedz4fx07i1dyb5wjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8bedz4fx07i1dyb5wjj.png" alt="Ufw firewall" width="658" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure cloud provider firewall:
&lt;/h3&gt;

&lt;p&gt;In your cloud provider panel, create &lt;strong&gt;Inbound&lt;/strong&gt; rules that allow only from your corporate IPs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7rgd6qo12hrkpq6pwo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7rgd6qo12hrkpq6pwo1.png" alt="DigitalOcean firewall" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Configure Computer/Client
&lt;/h2&gt;

&lt;p&gt;On each computer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open RustDesk&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings → Network&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Unlock Network Settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Server ID/Relay&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ID Server&lt;/strong&gt;: &lt;code&gt;YourRustServerIP&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relay Server&lt;/strong&gt;: &lt;code&gt;YourRustServerIP&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key&lt;/strong&gt;: Paste the public key obtained in step 7&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Server&lt;/strong&gt;: Leave empty (only for RustDesk Pro)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecxhizufe5wnpnjo2pvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecxhizufe5wnpnjo2pvj.png" alt="RustDesk client setup" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to quickly use your configuration, click the copy icon in the top right corner, and the paste icon to import:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xo5iywnx2lzegfixfta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xo5iywnx2lzegfixfta.png" alt="RustDesk client export/import" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;







&lt;h2&gt;
  
  
  Ways to Improve Your RustDesk Client Security
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke9a0hzzqwqxt4xe0118.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fke9a0hzzqwqxt4xe0118.png" alt="Security RustDesk client" width="760" height="992"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RustDesk offers multiple authentication methods to securely control remote access. Here I explain each option:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;One-time password&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automatically generated for each session and the user must provide it to the remote technician to connect&lt;/li&gt;
&lt;li&gt;Length options: 6, 8, or 10 digits&lt;/li&gt;
&lt;li&gt;The key changes with each session&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal use&lt;/strong&gt;: Temporary technical support or occasional access&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Permanent password&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Key you specify manually that doesn't change between sessions&lt;/li&gt;
&lt;li&gt;Allows continuous access without needing to share new keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal use&lt;/strong&gt;: Frequent remote access to your own computer&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Both passwords&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flexibility to use temporary OR permanent password&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal use&lt;/strong&gt;: Mixed scenarios (personal use + occasional support)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Two-Factor Authentication (2FA)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Additional security layer&lt;/li&gt;
&lt;li&gt;Options: codes from authenticator app or Telegram bot integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal use&lt;/strong&gt;: Computers accessible from public internet&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Trusted devices&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Only applies when using 2FA&lt;/li&gt;
&lt;li&gt;Mark specific devices as trusted&lt;/li&gt;
&lt;li&gt;Avoids requesting 2FA on each connection from those devices&lt;/li&gt;
&lt;li&gt;Improves convenience while maintaining security&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Additional Security Settings&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Password length&lt;/strong&gt;: Configurable based on security needs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration time&lt;/strong&gt;: For temporary passwords&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit logging&lt;/strong&gt;: Access monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Recommendations:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;For frequent personal use&lt;/strong&gt;: Permanent password + optional 2FA&lt;br&gt;&lt;br&gt;
&lt;strong&gt;For technical support&lt;/strong&gt;: One-time password&lt;br&gt;&lt;br&gt;
&lt;strong&gt;For corporate environments&lt;/strong&gt;: Mandatory 2FA + trusted devices&lt;br&gt;&lt;br&gt;
&lt;strong&gt;For maximum security&lt;/strong&gt;: Combination of methods + audit logging  &lt;/p&gt;

&lt;p&gt;These methods allow you to balance security and convenience according to your specific needs.&lt;/p&gt;







&lt;h2&gt;
  
  
  How to Make This a Truly Closed Network
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Block Access from Public Internet on the RustDesk Server
&lt;/h3&gt;

&lt;p&gt;Don't allow access from any IP in the firewall ufw rules or cloud provider rules. Only allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your office IPs&lt;/li&gt;
&lt;li&gt;Your corporate VPN IP&lt;/li&gt;
&lt;li&gt;Specific authorized ranges&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Implement VPN for Remote Access
&lt;/h3&gt;

&lt;p&gt;The most secure way: remote users first connect to the corporate VPN, then access RustDesk.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Create Administrative User Without Root:
&lt;/h3&gt;



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

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/adminops/.ssh
&lt;span class="nb"&gt;cp&lt;/span&gt; /root/.ssh/authorized_keys /home/adminops/.ssh/authorized_keys
&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; adminops:adminops /home/adminops/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 /home/adminops/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 /home/adminops/.ssh/authorized_keys

&lt;span class="c"&gt;# Disable root SSH&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'^PermitRootLogin'&lt;/span&gt; /etc/ssh/sshd_config&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/^PermitRootLogin.*/PermitRootLogin no/'&lt;/span&gt; /etc/ssh/sshd_config
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'PermitRootLogin no'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/ssh/sshd_config
&lt;span class="k"&gt;fi

&lt;/span&gt;sshd &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  RustDesk Pro: For Advanced Enterprise Needs
&lt;/h2&gt;

&lt;p&gt;The RustDesk version we've configured is excellent for basic remote access, but if you need advanced enterprise features, RustDesk offers a Pro version with additional capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized user and group management&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Granular access control&lt;/strong&gt; (role-based permissions)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LDAP/Active Directory authentication&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Detailed auditing and logs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Priority technical support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mass management functions&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these organizations, you can check the Pro plans at &lt;a href="https://rustdesk.com/pricing/" rel="noopener noreferrer"&gt;https://rustdesk.com/pricing/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need a cloud server?&lt;/strong&gt; You can get an Ubuntu Droplet on DigitalOcean using our &lt;a href="https://m.do.co/c/2c579acd7121" rel="noopener noreferrer"&gt;referral link&lt;/a&gt; and receive initial credits to try this tutorial.&lt;/p&gt;




&lt;p&gt;Have you implemented RustDesk in your organization? Share your experience in the comments!&lt;/p&gt;

</description>
      <category>rustdesk</category>
      <category>remotedesktop</category>
      <category>selfhosted</category>
      <category>opensource</category>
    </item>
    <item>
      <title>RustDesk: Cómo crear una red de acceso remoto segura y privada</title>
      <dc:creator>Oscar Ricardo Sánche Gutierréz</dc:creator>
      <pubDate>Tue, 31 Mar 2026 00:35:54 +0000</pubDate>
      <link>https://dev.to/oscar_ricardosncheguti/rustdesk-como-crear-una-red-de-acceso-remoto-segura-y-privada-50df</link>
      <guid>https://dev.to/oscar_ricardosncheguti/rustdesk-como-crear-una-red-de-acceso-remoto-segura-y-privada-50df</guid>
      <description>&lt;p&gt;RustDesk es la solución perfecta para acceso remoto seguro, de código abierto y bajo tu control completo. En este artículo te mostraré cómo desplegar tu propio servidor, configurarlo como una red cerrada y asegurarlo para uso corporativo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi38r6i6fxppelpaqzhpa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi38r6i6fxppelpaqzhpa.gif" alt="Architecture" width="700" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagrama realizado con &lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;https://savnet.co&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RustDesk es una alternativa de código abierto a herramientas como TeamViewer o AnyDesk, pero con una ventaja clave: &lt;strong&gt;puedes autoalojarlo&lt;/strong&gt;. Esto significa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control total&lt;/strong&gt; sobre tus datos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sin límites&lt;/strong&gt; de conexión&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costo cero&lt;/strong&gt; en licencias (solo el servidor)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 1: Preparar el servidor
&lt;/h2&gt;

&lt;p&gt;Necesitarás un servidor Linux con Ubuntu 22.04 o 24.04 LTS con:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 vCPU, 2 GB RAM&lt;/strong&gt; (suficiente para decenas de conexiones)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ubuntu 22.04 LTS&lt;/strong&gt; o superior&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP pública fija&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0nrxitd5jg1qxzapucor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0nrxitd5jg1qxzapucor.png" alt="New DigitalOcean Server" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 2: Configuración inicial del servidor
&lt;/h2&gt;

&lt;p&gt;Conéctate por SSH y actualiza el sistema:&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@tu_ip_servidor
apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
timedatectl set-timezone America/Bogota  &lt;span class="c"&gt;# Ajusta a tu zona horaria&lt;/span&gt;
reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Instalar Docker y Docker Compose
&lt;/h2&gt;

&lt;p&gt;Sigue la instalación oficial de Docker:&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;# Instalar dependencias&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ca-certificates curl gnupg

&lt;span class="c"&gt;# Agregar repositorio oficial de Docker&lt;/span&gt;
&lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.asc
&lt;span class="nb"&gt;chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.asc

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.asc] &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="se"&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;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

&lt;span class="c"&gt;# Instalar Docker&lt;/span&gt;
apt update
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class="c"&gt;# Verificar instalación&lt;/span&gt;
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
docker compose version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6pn1ggqqirum8e9u2r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6pn1ggqqirum8e9u2r4.png" alt="Versiones docker" width="377" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 4: Preparar la estructura de RustDesk
&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /opt/rustdesk-server/data
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/rustdesk-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 5: Crear el archivo docker-compose.yml
&lt;/h2&gt;

&lt;p&gt;Crea  &lt;code&gt;nano /opt/rustdesk-server/compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hbbr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rustdesk/rustdesk-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/root&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host"&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;hbbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbs&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rustdesk/rustdesk-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hbbs&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/root&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;hbbr&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: Usamos &lt;code&gt;network_mode: "host"&lt;/code&gt; porque RustDesk necesita ver la IP real del host para funcionar correctamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 6: Levantar los servicios
&lt;/h2&gt;



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

&lt;span class="c"&gt;# Verificar que estén corriendo&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Ver logs&lt;/span&gt;
docker compose logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F939r0p4g61pmlkc6c1ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F939r0p4g61pmlkc6c1ss.png" alt="Servicios docker" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 7: Obtener la clave pública del servidor
&lt;/h2&gt;

&lt;p&gt;Esta clave es crucial para que los clientes confíen en tu servidor:&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;cat&lt;/span&gt; /opt/rustdesk-server/data/id_ed25519.pub &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guarda el resultado. Se verá algo como:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 8: Configurar el firewall
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Puertos necesarios para RustDesk OSS:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21115&lt;/strong&gt; - Servicio principal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21116&lt;/strong&gt; - Servicio de ID&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UDP 21116&lt;/strong&gt; - Para mejor rendimiento&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP 21117&lt;/strong&gt; - Servicio de relay&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configurar UFW en el servidor:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Instalar firewall ufw&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ufw

&lt;span class="c"&gt;# Permitir SSH desde TU IP pública&lt;/span&gt;
ufw allow from tu_ip_admin to any port 22
&lt;span class="c"&gt;# SI NO TIENES IP pública, permite cualquier origen con&lt;/span&gt;
ufw allow 22

&lt;span class="c"&gt;# Permitir puertos de RustDesk&lt;/span&gt;
ufw allow 21115/tcp
ufw allow 21116/tcp
ufw allow 21116/udp
ufw allow 21117/tcp

&lt;span class="c"&gt;# Activar firewall&lt;/span&gt;
ufw &lt;span class="nb"&gt;enable
&lt;/span&gt;ufw status verbose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2t0jrrgs9ozzj3tss1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2t0jrrgs9ozzj3tss1z.png" alt="Firewall ufw" width="658" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configurar firewall del proveedor cloud:
&lt;/h3&gt;

&lt;p&gt;En el panel de tu proveedor cloud, crea reglas &lt;strong&gt;Inbound&lt;/strong&gt; que permitan solo desde tus IPs corporativas:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9dt0ytzh0h2d3g8lu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frv9dt0ytzh0h2d3g8lu7.png" alt="Firewall DigitalOcean" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 9: Configurar computador/cliente
&lt;/h2&gt;

&lt;p&gt;En cada equipo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abre RustDesk&lt;/li&gt;
&lt;li&gt;Ve a &lt;strong&gt;Settings → Network&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Haz click en &lt;strong&gt;Unlock Network Settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Ve a &lt;strong&gt;Servidor ID/Relay&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configura:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ID Server&lt;/strong&gt;: &lt;code&gt;IpServidorRust&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relay Server&lt;/strong&gt;: &lt;code&gt;IpServidorRust&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key&lt;/strong&gt;: Pega la clave pública obtenida en el paso 7&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Server&lt;/strong&gt;: Déjalo vacío (solo para RustDesk Pro)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5yb7rwtyhmmggqph587.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5yb7rwtyhmmggqph587.png" alt="Configuración cliente Rust" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si quieres usar rápidamente tu configuración da click en el icono de copiar en la parte superior derecha, y el icono de pegar para importar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgjimz6pmo0cffgaeuqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgjimz6pmo0cffgaeuqv.png" alt="Export/Import cliente RustDesk" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;







&lt;h2&gt;
  
  
  Formas de mejorar la seguridad de tu computador/cliente RustDesk
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fson7mgpdnrdwh7kvii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fson7mgpdnrdwh7kvii.png" alt="Configuración seguridad cliente RustDesk" width="760" height="992"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RustDesk ofrece múltiples métodos de autenticación para controlar el acceso remoto de forma segura. Aquí te explico cada opción:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Contraseña de un solo uso (One-time password)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Se genera automáticamente en cada sesión y el usuario debe suministrarla al técnico remoto para que pueda conectarse.&lt;/li&gt;
&lt;li&gt;Opciones de longitud: 6, 8 o 10 dígitos&lt;/li&gt;
&lt;li&gt;La clave cambia en cada sesión.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso ideal&lt;/strong&gt;: Soporte técnico puntual o accesos temporales&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Contraseña permanente (Permanent password)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clave que especificas manualmente y no cambia entre sesiones&lt;/li&gt;
&lt;li&gt;Permite acceso continuo sin necesidad de compartir nuevas claves&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso ideal&lt;/strong&gt;: Acceso remoto frecuente a tu propio equipo&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Combinación de ambos métodos (Both passwords)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flexibilidad para usar contraseña temporal O permanente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso ideal&lt;/strong&gt;: Escenarios mixtos (uso personal + soporte ocasional)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Autenticación en dos factores (2FA)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Capa adicional de seguridad&lt;/li&gt;
&lt;li&gt;Opciones: códigos desde app autenticadora o integración con bot de Telegram&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uso ideal&lt;/strong&gt;: Equipos accesibles desde internet público&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Dispositivos de confianza (Trusted devices)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Solo aplica cuando usas 2FA&lt;/li&gt;
&lt;li&gt;Marcar dispositivos específicos como confiables&lt;/li&gt;
&lt;li&gt;Evita solicitar 2FA en cada conexión desde esos dispositivos&lt;/li&gt;
&lt;li&gt;Mejora la comodidad manteniendo seguridad&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Configuraciones de seguridad adicionales&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Longitud de contraseña&lt;/strong&gt;: Configurable según necesidades de seguridad&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiempo de expiración&lt;/strong&gt;: Para contraseñas temporales&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registro de auditoría&lt;/strong&gt;: Monitoreo de accesos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recomendaciones prácticas:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Para uso personal frecuente&lt;/strong&gt;: Contraseña permanente + 2FA opcional&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Para soporte técnico&lt;/strong&gt;: Contraseña de un solo uso&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Para entornos corporativos&lt;/strong&gt;: 2FA obligatorio + dispositivos de confianza&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Para máxima seguridad&lt;/strong&gt;: Combinación de métodos + registro de auditoría  &lt;/p&gt;

&lt;p&gt;Estos métodos te permiten balancear seguridad y conveniencia según tus necesidades específicas.&lt;/p&gt;







&lt;h2&gt;
  
  
  Cómo convertir esto en una red realmente cerrada
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Bloquear acceso desde Internet público del servidor RustDesk
&lt;/h3&gt;

&lt;p&gt;No permitas acceso a cualquier ip en las reglas del firewall ufw o del operador cloud. Solo permite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IPs de tus oficinas&lt;/li&gt;
&lt;li&gt;IP de tu VPN corporativa&lt;/li&gt;
&lt;li&gt;Rangos específicos autorizados&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Implementar VPN para acceso remoto
&lt;/h3&gt;

&lt;p&gt;La forma más segura: usuarios remotos primero se conectan a la VPN corporativa, luego acceden a RustDesk.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Crear usuario administrativo sin root:
&lt;/h3&gt;



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

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/adminops/.ssh
&lt;span class="nb"&gt;cp&lt;/span&gt; /root/.ssh/authorized_keys /home/adminops/.ssh/authorized_keys
&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; adminops:adminops /home/adminops/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 /home/adminops/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 /home/adminops/.ssh/authorized_keys

&lt;span class="c"&gt;# Deshabilitar root por SSH&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'^PermitRootLogin'&lt;/span&gt; /etc/ssh/sshd_config&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/^PermitRootLogin.*/PermitRootLogin no/'&lt;/span&gt; /etc/ssh/sshd_config
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'PermitRootLogin no'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/ssh/sshd_config
&lt;span class="k"&gt;fi

&lt;/span&gt;sshd &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  RustDesk Pro: Para necesidades empresariales avanzadas
&lt;/h2&gt;

&lt;p&gt;La versión RustDesk que hemos configurado es excelente para acceso remoto básico, pero si necesitas funcionalidades empresariales avanzadas, RustDesk ofrece una versión Pro con características adicionales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gestión centralizada de usuarios y grupos&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control de acceso granular&lt;/strong&gt; (permisos por rol)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autenticación LDAP/Active Directory&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auditoría y logs detallados&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Soporte técnico prioritario&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Funciones de administración masiva&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para estas organizaciones puedes consultar los planes Pro en &lt;a href="https://rustdesk.com/pricing/" rel="noopener noreferrer"&gt;https://rustdesk.com/pricing/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Necesitas un servidor en la nube?&lt;/strong&gt; Puedes obtener un Droplet Ubuntu en DigitalOcean usando nuestro &lt;a href="https://m.do.co/c/2c579acd7121" rel="noopener noreferrer"&gt;enlace de referido&lt;/a&gt; y recibir créditos iniciales para probar este tutorial.&lt;/p&gt;




&lt;p&gt;¿Has implementado RustDesk en tu organización? ¡Comparte tu experiencia en los comentarios!&lt;/p&gt;

</description>
      <category>rustdesk</category>
      <category>remotedesktop</category>
      <category>selfhosted</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to Deploy Dokploy on an Ubuntu Server and Create Your First "Hello World" in Node.js</title>
      <dc:creator>Oscar Ricardo Sánche Gutierréz</dc:creator>
      <pubDate>Fri, 27 Mar 2026 22:41:28 +0000</pubDate>
      <link>https://dev.to/oscar_ricardosncheguti/how-to-deploy-dokploy-on-an-ubuntu-server-and-create-your-first-hello-world-in-nodejs-lg2</link>
      <guid>https://dev.to/oscar_ricardosncheguti/how-to-deploy-dokploy-on-an-ubuntu-server-and-create-your-first-hello-world-in-nodejs-lg2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Dokploy is a self-hosted deployment platform that simplifies containerized application management using Docker Swarm. In this comprehensive tutorial, I'll show you how to install Dokploy on an &lt;strong&gt;Ubuntu server&lt;/strong&gt;, configure security with firewalls, deploy your first Node.js application, and follow production best practices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jvvlixnrkljsaanq0x3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jvvlixnrkljsaanq0x3.gif" alt="Architecture" width="700" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagram created with &lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;https://savnet.co&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What You'll Need
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;Ubuntu 24.04 LTS server&lt;/strong&gt; (minimum 2 GB RAM for testing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH access&lt;/strong&gt; with configured keys&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;domain or subdomain&lt;/strong&gt; (optional but recommended for HTTPS)&lt;/li&gt;
&lt;li&gt;Basic terminal and Docker knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Prepare Your Ubuntu Server
&lt;/h2&gt;

&lt;p&gt;If you already have an Ubuntu 24.04 LTS server with SSH access, you can skip this step. If you need to create one, follow these recommendations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose a cloud or VPS provider&lt;/strong&gt; that offers Ubuntu 24.04 LTS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select a plan&lt;/strong&gt; with at least 2 GB of RAM for testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure SSH key access&lt;/strong&gt; instead of password (more secure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider enabling backups and monitoring&lt;/strong&gt; for production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Note the public IP&lt;/strong&gt; of your server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your provider has an integrated firewall (like DigitalOcean Cloud Firewall, AWS Security Groups, etc.), configure the necessary rules from the control panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o655rkgi11xk9gqelp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o655rkgi11xk9gqelp2.png" alt="New Server DigitalOcean" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Initial Server Configuration
&lt;/h2&gt;

&lt;p&gt;Connect to the server via SSH:&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_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update system and install utilities
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl wget git ufw ca-certificates gnupg lsb-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create administrator user (recommended)
&lt;/h3&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
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 you can connect with the 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;ssh deploy@YOUR_PUBLIC_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Configure Firewall with UFW
&lt;/h2&gt;

&lt;p&gt;Dokploy needs specific ports open. Configure UFW properly:&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;# Allow SSH first to avoid locking ourselves out&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH

&lt;span class="c"&gt;# Open ports needed for Dokploy and applications&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 80/tcp     &lt;span class="c"&gt;# HTTP for Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/tcp    &lt;span class="c"&gt;# HTTPS for Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/udp    &lt;span class="c"&gt;# HTTPS UDP for Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 3000/tcp   &lt;span class="c"&gt;# Dokploy panel (temporary only)&lt;/span&gt;

&lt;span class="c"&gt;# Enable firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable
sudo &lt;/span&gt;ufw status numbered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Docker can bypass UFW rules because it manipulates &lt;code&gt;iptables&lt;/code&gt; directly. If your cloud provider offers an integrated firewall (like DigitalOcean Cloud Firewall, AWS Security Groups, etc.), we recommend configuring it as an additional security layer.&lt;/p&gt;

&lt;p&gt;Configure the same firewall rules in your provider's panel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;22/TCP&lt;/strong&gt; from your IP or trusted range (SSH)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;80/TCP&lt;/strong&gt; from Anywhere (HTTP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;443/TCP&lt;/strong&gt; from Anywhere (HTTPS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;443/UDP&lt;/strong&gt; from Anywhere (HTTPS UDP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3000/TCP&lt;/strong&gt; temporarily from your IP only (for initial setup)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;assets/dropplet-firewall.png&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 4: Install Dokploy
&lt;/h2&gt;

&lt;p&gt;The official Dokploy installation is straightforward with their script:&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;-sSL&lt;/span&gt; https://dokploy.com/install.sh | &lt;span class="nb"&gt;sudo &lt;/span&gt;sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installs Docker if not present&lt;/li&gt;
&lt;li&gt;Initializes Docker Swarm&lt;/li&gt;
&lt;li&gt;Creates the overlay network &lt;code&gt;dokploy-network&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deploys Postgres, Redis, and Dokploy services&lt;/li&gt;
&lt;li&gt;Launches Traefik as reverse proxy&lt;/li&gt;
&lt;li&gt;Publishes the panel on port 3000&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Verify the Installation
&lt;/h2&gt;

&lt;p&gt;Check that everything is working:&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;# View Docker Swarm services&lt;/span&gt;
docker service &lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;# View running containers&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Verify ports are listening&lt;/span&gt;
ss &lt;span class="nt"&gt;-lntup&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'(:80|:443|:3000)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81yncuovtp3fgsxjdp01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81yncuovtp3fgsxjdp01.png" alt="Console up services" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now open your browser and access the Dokploy panel:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Complete the initial setup wizard by creating your administrator account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7dzlkajpvs6xif8zvy8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7dzlkajpvs6xif8zvy8.png" alt="Dashboard Home" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Configure Domain and HTTPS (optional but recommended)
&lt;/h2&gt;

&lt;p&gt;To access your applications with your own domain and HTTPS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your DNS provider's panel (Cloudflare, DigitalOcean, AWS Route53, etc.), add your domain if you haven't already.&lt;/li&gt;
&lt;li&gt;Create DNS records:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; record for &lt;code&gt;@&lt;/code&gt; pointing to your server IP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; record for &lt;code&gt;www&lt;/code&gt; pointing to your server IP&lt;/li&gt;
&lt;li&gt;Or a subdomain like &lt;code&gt;dokploy.yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Wait for DNS propagation (may take a few minutes).&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrict access to port 3000
&lt;/h3&gt;

&lt;p&gt;For security, once Dokploy is configured, restrict access to port 3000:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your cloud provider's firewall, limit it to your IP only if you need administrative access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Deploy Your First "Hello World" Application in Node.js
&lt;/h2&gt;

&lt;p&gt;Let's create a simple Node.js application and deploy it to Dokploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Create the project locally
&lt;/h3&gt;

&lt;p&gt;Create a folder for your project with the following files:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;package.json&lt;/strong&gt;:&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello-world-dokploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World application for Dokploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node app.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.18.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;strong&gt;app.js&lt;/strong&gt;:&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="kd"&gt;const&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="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;/&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World from Dokploy!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;environment&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;NODE_ENV&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;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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&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;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;PORT&lt;/span&gt;&lt;span class="p"&gt;,&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;&lt;strong&gt;Dockerfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt; (for reference):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=staging&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Deploy to Dokploy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Deploy part 1
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fei5sgxaa5p58rgg5sqgp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fei5sgxaa5p58rgg5sqgp.gif" alt="Deploy part 1" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Deploy part 2
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk437rlxfxy662zubyddy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk437rlxfxy662zubyddy.gif" alt="Deploy part 2" width="720" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the Dokploy panel, click &lt;strong&gt;Create Project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Give your project a name (e.g., "Tests")&lt;/li&gt;
&lt;li&gt;In the project panel, click &lt;strong&gt;Create Service&lt;/strong&gt; and select Application&lt;/li&gt;
&lt;li&gt;Name your application: &lt;strong&gt;Hello World&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Then access your application and in the bottom section &lt;strong&gt;Build Type&lt;/strong&gt; select Dockerfile and then Save.&lt;/li&gt;
&lt;li&gt;In the top section you have &lt;strong&gt;Provider&lt;/strong&gt;. For this test we'll select the Drop type, however for real cases the best option is through git repository.&lt;/li&gt;
&lt;li&gt;Once Drop is selected, drag to the &lt;strong&gt;Zip file&lt;/strong&gt; area the zip with the code we specified in point 7.1.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Deploy&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;Once deployment is complete, it will show the &lt;strong&gt;Deployments&lt;/strong&gt; tab where you should see a green dot and &lt;strong&gt;Done&lt;/strong&gt; indicating the process was successful. You can click &lt;strong&gt;View&lt;/strong&gt; to verify the process.&lt;/li&gt;
&lt;li&gt;Now, to deploy our Hello World, go to the &lt;strong&gt;Domains&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;For this test we'll use a free Traefik domain by clicking on the dice icon, specify that the &lt;strong&gt;Container Port&lt;/strong&gt; is 3000 and enable HTTPS with Let's Encrypt provider.&lt;/li&gt;
&lt;li&gt;Then click the &lt;strong&gt;Create&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;When finished, it will give us a URL where we can enter and see our web. Important: since we're using a test domain it will give security warnings. For production environments use your own domain.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7.3 Verify the deployment
&lt;/h3&gt;

&lt;p&gt;Once deployment is complete, access your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://tests-hello-world-puloud-d13d9c-167-172-as2dsaccc234-151.traefik.me/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the JSON "Hello World" message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1t1gls363gjabhue4xk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1t1gls363gjabhue4xk.png" alt="Browser Helo App" width="784" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Production Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Don't build on production server
&lt;/h3&gt;

&lt;p&gt;Dokploy recommends building Docker images in CI/CD (GitHub Actions, GitLab CI) and then deploying the pre-built image. This saves resources and reduces downtime risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Use health checks
&lt;/h3&gt;

&lt;p&gt;Configure health checks in your applications (like the &lt;code&gt;/health&lt;/code&gt; endpoint in our example) so Docker Swarm can monitor status.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Configure backups
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configure regular server backups&lt;/strong&gt; (if your provider offers this feature)&lt;/li&gt;
&lt;li&gt;Configure regular database backups&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;docker volume&lt;/code&gt; for persistent data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Monitoring and logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# View Dokploy logs&lt;/span&gt;
docker service logs dokploy &lt;span class="nt"&gt;--tail&lt;/span&gt; 100 &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# View application logs&lt;/span&gt;
docker service logs hello-world_app &lt;span class="nt"&gt;--tail&lt;/span&gt; 100 &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# View service status&lt;/span&gt;
docker service ps hello-world_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dokploy offers a robust, self-hosted solution for deploying applications on Docker Swarm. By implementing it on an Ubuntu server, you get a scalable, secure, and professional infrastructure at an accessible cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need a cloud server?&lt;/strong&gt; You can get an Ubuntu Droplet on DigitalOcean using our &lt;a href="https://m.do.co/c/2c579acd7121" rel="noopener noreferrer"&gt;referral link&lt;/a&gt; and receive initial credits to try this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dokploy.com" rel="noopener noreferrer"&gt;Official Dokploy Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dokploy.com/docs/core/remote-servers/security" rel="noopener noreferrer"&gt;Dokploy Security Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.digitalocean.com/products/networking/firewalls/" rel="noopener noreferrer"&gt;DigitalOcean Firewall Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dokploy/dokploy" rel="noopener noreferrer"&gt;Dokploy GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.gg/dokploy" rel="noopener noreferrer"&gt;Dokploy Discord Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Enjoyed this tutorial?&lt;/strong&gt; Share your experiences deploying applications with Dokploy in the comments or suggest topics for future articles.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>dokploy</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Cómo desplegar Dokploy en un servidor Ubuntu y crear tu primer "Hola Mundo" en Node.js</title>
      <dc:creator>Oscar Ricardo Sánche Gutierréz</dc:creator>
      <pubDate>Fri, 27 Mar 2026 22:38:03 +0000</pubDate>
      <link>https://dev.to/oscar_ricardosncheguti/como-desplegar-dokploy-en-un-servidor-ubuntu-y-crear-tu-primer-hola-mundo-en-nodejs-14b8</link>
      <guid>https://dev.to/oscar_ricardosncheguti/como-desplegar-dokploy-en-un-servidor-ubuntu-y-crear-tu-primer-hola-mundo-en-nodejs-14b8</guid>
      <description>&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Dokploy es una plataforma de despliegue auto-hospedada que simplifica la gestión de aplicaciones en contenedores Docker usando Docker Swarm. En este tutorial completo, te mostraré cómo instalar Dokploy en un &lt;strong&gt;servidor Ubuntu&lt;/strong&gt;, configurar seguridad con firewall, desplegar tu primera aplicación Node.js y seguir las mejores prácticas para producción.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85bwgux6b6zb9kbrh6s3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85bwgux6b6zb9kbrh6s3.gif" alt="Arquitectura" width="700" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Diagrama realizado con &lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;https://savnet.co&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué necesitas?
&lt;/h2&gt;

&lt;p&gt;Antes de comenzar, asegúrate de tener:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;servidor con Ubuntu 24.04 LTS&lt;/strong&gt; (2 GB de RAM mínimo para pruebas)&lt;/li&gt;
&lt;li&gt;Acceso por &lt;strong&gt;SSH&lt;/strong&gt; con claves configuradas&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;dominio o subdominio&lt;/strong&gt; (opcional, pero recomendado para HTTPS)&lt;/li&gt;
&lt;li&gt;Conocimientos básicos de terminal y Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 1: Preparar tu servidor Ubuntu
&lt;/h2&gt;

&lt;p&gt;Si ya tienes un servidor Ubuntu 24.04 LTS con acceso SSH, puedes saltar este paso. Si necesitas crear uno, sigue estas recomendaciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Elige un proveedor de cloud o VPS&lt;/strong&gt; que ofrezca Ubuntu 24.04 LTS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selecciona un plan&lt;/strong&gt; con al menos 2 GB de RAM para pruebas&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configura acceso SSH con claves&lt;/strong&gt; en lugar de contraseña (más seguro)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Considera activar backups y monitoreo&lt;/strong&gt; si es para producción&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anota la IP pública&lt;/strong&gt; de tu servidor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si usas un proveedor con firewall integrado (como Cloud Firewall de DigitalOcean, Security Groups de AWS, etc.), configura las reglas necesarias desde el panel de control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku8nrc9a6pjt628k29w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku8nrc9a6pjt628k29w4.png" alt="Servidor DitialOcean" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 2: Configuración inicial del servidor
&lt;/h2&gt;

&lt;p&gt;Conéctate al servidor por SSH:&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@TU_IP_PUBLICA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Actualizar sistema e instalar utilidades
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl wget git ufw ca-certificates gnupg lsb-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear usuario administrador (recomendado)
&lt;/h3&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
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;Ahora puedes conectarte con el nuevo usuario:&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@TU_IP_PUBLICA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paso 3: Configurar firewall con UFW
&lt;/h2&gt;

&lt;p&gt;Dokploy necesita puertos específicos abiertos. Configura UFW correctamente:&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;# Permitir SSH primero para no bloquearnos&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH

&lt;span class="c"&gt;# Abrir puertos necesarios para Dokploy y aplicaciones&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 80/tcp     &lt;span class="c"&gt;# HTTP para Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/tcp    &lt;span class="c"&gt;# HTTPS para Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/udp    &lt;span class="c"&gt;# HTTPS UDP para Traefik&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 3000/tcp   &lt;span class="c"&gt;# Panel de Dokploy (solo temporal)&lt;/span&gt;

&lt;span class="c"&gt;# Activar firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable
sudo &lt;/span&gt;ufw status numbered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: Docker puede saltarse reglas de UFW porque manipula &lt;code&gt;iptables&lt;/code&gt; directamente. Si tu proveedor de cloud ofrece firewall integrado (como Cloud Firewall de DigitalOcean, Security Groups de AWS, etc.), te recomendamos configurarlo también como capa adicional de seguridad.&lt;/p&gt;

&lt;p&gt;Configura las mismas reglas de firewall en el panel de tu proveedor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;22/TCP&lt;/strong&gt; desde tu IP o rango de confianza (SSH)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;80/TCP&lt;/strong&gt; desde Anywhere (HTTP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;443/TCP&lt;/strong&gt; desde Anywhere (HTTPS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;443/UDP&lt;/strong&gt; desde Anywhere (HTTPS UDP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3000/TCP&lt;/strong&gt; temporalmente desde tu IP (solo para configuración inicial)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68fg2sgmhbws48kp8hqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68fg2sgmhbws48kp8hqv.png" alt="Firewall de servidor" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 4: Instalar Dokploy
&lt;/h2&gt;

&lt;p&gt;La instalación oficial de Dokploy es sencilla con su script:&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;-sSL&lt;/span&gt; https://dokploy.com/install.sh | &lt;span class="nb"&gt;sudo &lt;/span&gt;sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este script automáticamente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instala Docker si no está presente&lt;/li&gt;
&lt;li&gt;Inicializa Docker Swarm&lt;/li&gt;
&lt;li&gt;Crea la red overlay &lt;code&gt;dokploy-network&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Despliega servicios de Postgres, Redis y Dokploy&lt;/li&gt;
&lt;li&gt;Levanta Traefik como reverse proxy&lt;/li&gt;
&lt;li&gt;Publica el panel en el puerto 3000&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 5: Verificar la instalación
&lt;/h2&gt;

&lt;p&gt;Comprueba que todo esté funcionando:&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;# Ver servicios de Docker Swarm&lt;/span&gt;
docker service &lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;# Ver contenedores en ejecución&lt;/span&gt;
docker ps

&lt;span class="c"&gt;# Verificar que los puertos estén escuchando&lt;/span&gt;
ss &lt;span class="nt"&gt;-lntup&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'(:80|:443|:3000)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yyavlrgbn1qy9h58g8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yyavlrgbn1qy9h58g8l.png" alt="Dashboard Dokploy" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora abre tu navegador y accede al panel de Dokploy:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Completa el asistente inicial creando tu cuenta de administrador.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13s0ydlj7piamh37mmbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F13s0ydlj7piamh37mmbg.png" alt="Home dokploy" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 6: Configurar dominio y HTTPS (opcional pero recomendado)
&lt;/h2&gt;

&lt;p&gt;Para acceder a tus aplicaciones con dominio propio y HTTPS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En el panel de DNS de tu proveedor (Cloudflare, DigitalOcean, AWS Route53, etc.), añade tu dominio si no lo tienes ya.&lt;/li&gt;
&lt;li&gt;Crea registros DNS:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; record para &lt;code&gt;@&lt;/code&gt; apuntando a la IP de tu servidor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; record para &lt;code&gt;www&lt;/code&gt; apuntando a la IP de tu servidor&lt;/li&gt;
&lt;li&gt;O un subdominio como &lt;code&gt;dokploy.tudominio.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Espera la propagación DNS (puede tomar unos minutos).&lt;/p&gt;

&lt;h3&gt;
  
  
  Restringir acceso al puerto 3000
&lt;/h3&gt;

&lt;p&gt;Por seguridad, una vez configurado Dokploy, restringe el acceso al puerto 3000:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;En el firewall de tu proveedor de cloud, limítala solo a tu IP si necesitas acceso administrativo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Paso 7: Desplegar tu primera aplicación "Hola Mundo" en Node.js
&lt;/h2&gt;

&lt;p&gt;Vamos a crear una aplicación Node.js simple y desplegarla en Dokploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Crear el proyecto localmente
&lt;/h3&gt;

&lt;p&gt;Crea una carpeta para tu proyecto y los siguientes archivos:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;package.json&lt;/strong&gt;:&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hola-mundo-dokploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Aplicación Hola Mundo para Dokploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node app.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.18.2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;strong&gt;app.js&lt;/strong&gt;:&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="kd"&gt;const&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="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;/&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;¡Hola Mundo desde Dokploy!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;environment&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;NODE_ENV&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;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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&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;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;PORT&lt;/span&gt;&lt;span class="p"&gt;,&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Servidor corriendo en puerto &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;&lt;strong&gt;Dockerfile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt; (para referencia):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=staging&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Desplegar en Dokploy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Despliegue parte 1
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo2i64a6w4f9i3jnoix3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foo2i64a6w4f9i3jnoix3.gif" alt="Despliegue parte 1" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Despliegue parte 2
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxwo1zm9ub2ywxa11jmz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxwo1zm9ub2ywxa11jmz.gif" alt="Despliegue parte 2" width="720" height="406"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;En el panel de Dokploy, haz clic en &lt;strong&gt;Create Project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Dale un nombre a tu proyecto (ej: "Tests")&lt;/li&gt;
&lt;li&gt;En el panel de proyecto, haz click en &lt;strong&gt;Create Service&lt;/strong&gt; y selecciona Application&lt;/li&gt;
&lt;li&gt;Dale un nombre a tu aplicación: &lt;strong&gt;Hello World&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Luego accede a tu aplicación y en la sección inferior &lt;strong&gt;Build Type&lt;/strong&gt; selecciona Dockerfile y luego Save.&lt;/li&gt;
&lt;li&gt;En la parte superior cuentas con la sección &lt;strong&gt;Provider&lt;/strong&gt;. Para esta prueba seleccionaremos el tipo Drop, sin embargo para casos reales la mejor opción es a través de repositorio git.&lt;/li&gt;
&lt;li&gt;Una vez seleccionado Drop, arrastra al área &lt;strong&gt;Zip file&lt;/strong&gt; el zip con el código que especificamos en el punto 7.1.&lt;/li&gt;
&lt;li&gt;Haz clic en el botón &lt;strong&gt;Deploy&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Una vez terminado el despliegue, te mostrará la pestaña &lt;strong&gt;Deployments&lt;/strong&gt; en la cual deberás ver un punto verde y &lt;strong&gt;Done&lt;/strong&gt; que indica que el proceso fue exitoso. Puedes hacer clic en &lt;strong&gt;View&lt;/strong&gt; para verificar el proceso.&lt;/li&gt;
&lt;li&gt;Ahora, para desplegar nuestro Hola Mundo, ve a la pestaña &lt;strong&gt;Domains&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Para esta prueba usaremos un dominio gratuito de Traefik haciendo click en el icono de un par de dados, especificamos que el &lt;strong&gt;Container Port&lt;/strong&gt; es 3000 y habilitamos el HTTPS con proveedor Let's Encrypt.&lt;/li&gt;
&lt;li&gt;Luego haz clic en el botón &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Al terminar nos dará una URL a la cual podremos ingresar y ver nuestra web. Importante: como estamos usando un dominio de prueba nos dará advertencia de seguridad. Para entornos de producción usa un dominio propio.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7.3 Verificar el despliegue
&lt;/h3&gt;

&lt;p&gt;Una vez completado el despliegue, accede a tu aplicación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://tests-hello-world-puloud-d13d9c-167-172-as2dsaccc234-151.traefik.me/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deberías ver el mensaje JSON de "Hola Mundo".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m7kcndy3bhchw2c4ous.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m7kcndy3bhchw2c4ous.png" alt=" " width="784" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 8: Buenas prácticas para producción
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No compilar en el servidor de producción
&lt;/h3&gt;

&lt;p&gt;Dokploy recomienda construir las imágenes Docker en CI/CD (GitHub Actions, GitLab CI) y luego desplegar la imagen ya construida. Esto ahorra recursos y reduce riesgo de downtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Usar health checks
&lt;/h3&gt;

&lt;p&gt;Configura health checks en tus aplicaciones (como el endpoint &lt;code&gt;/health&lt;/code&gt; en nuestro ejemplo) para que Docker Swarm pueda monitorear el estado.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Configurar backups
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configura backups regulares&lt;/strong&gt; de tu servidor (si tu proveedor ofrece esta funcionalidad)&lt;/li&gt;
&lt;li&gt;Configura backups de bases de datos regularmente&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;docker volume&lt;/code&gt; para datos persistentes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Monitoreo y logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ver logs de Dokploy&lt;/span&gt;
docker service logs dokploy &lt;span class="nt"&gt;--tail&lt;/span&gt; 100 &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# Ver logs de tu aplicación&lt;/span&gt;
docker service logs hola-mundo_app &lt;span class="nt"&gt;--tail&lt;/span&gt; 100 &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="c"&gt;# Ver estado de los servicios&lt;/span&gt;
docker service ps hola-mundo_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Dokploy ofrece una solución robusta y auto-hospedada para el despliegue de aplicaciones en Docker Swarm. Al implementarlo en un servidor Ubuntu, obtienes una infraestructura escalable, segura y profesional a un costo accesible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Necesitas un servidor en la nube?&lt;/strong&gt; Puedes obtener un Droplet Ubuntu en DigitalOcean usando nuestro &lt;a href="https://m.do.co/c/2c579acd7121" rel="noopener noreferrer"&gt;enlace de referido&lt;/a&gt; y recibir créditos iniciales para probar este tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recursos adicionales
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.dokploy.com" rel="noopener noreferrer"&gt;Documentación oficial de Dokploy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dokploy.com/docs/core/remote-servers/security" rel="noopener noreferrer"&gt;Guía de seguridad de Dokploy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.digitalocean.com/products/networking/firewalls/" rel="noopener noreferrer"&gt;Documentación de DigitalOcean sobre firewalls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dokploy/dokploy" rel="noopener noreferrer"&gt;Repositorio GitHub de Dokploy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.gg/dokploy" rel="noopener noreferrer"&gt;Comunidad Discord de Dokploy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;¿Te gustó este tutorial?&lt;/strong&gt; Comparte tus experiencias desplegando aplicaciones con Dokploy en los comentarios o sugiere temas para futuros artículos.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>dokploy</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Basic Load Balancing for a Web System on DigitalOcean</title>
      <dc:creator>Oscar Ricardo Sánche Gutierréz</dc:creator>
      <pubDate>Fri, 06 Mar 2026 20:43:27 +0000</pubDate>
      <link>https://dev.to/oscar_ricardosncheguti/basic-load-balancing-for-a-web-system-on-digitalocean-2hf7</link>
      <guid>https://dev.to/oscar_ricardosncheguti/basic-load-balancing-for-a-web-system-on-digitalocean-2hf7</guid>
      <description>&lt;p&gt;In this article we’ll build a &lt;strong&gt;simple and inexpensive load-balanced web setup on DigitalOcean&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The architecture is intentionally minimal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 DigitalOcean Load Balancer&lt;/li&gt;
&lt;li&gt;2 small droplets&lt;/li&gt;
&lt;li&gt;A lightweight web app running with &lt;strong&gt;Docker + PHP + Nginx&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to show how quickly you can build a &lt;strong&gt;basic scalable web entry point&lt;/strong&gt; without complex infrastructure.&lt;/p&gt;

&lt;p&gt;Architecture diagram created with &lt;strong&gt;&lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;savnet.co&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yoatkmjtxd5u51jmo92.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1yoatkmjtxd5u51jmo92.gif" alt="architecture" width="962" height="690"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Creating the first server
&lt;/h1&gt;

&lt;p&gt;Go to your &lt;strong&gt;DigitalOcean account&lt;/strong&gt; and create a small droplet.&lt;/p&gt;

&lt;p&gt;Configuration used in this guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image: &lt;strong&gt;Docker latest on Ubuntu 22.04&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Region: choose the closest to your users&lt;/li&gt;
&lt;li&gt;Authentication: &lt;strong&gt;SSH recommended&lt;/strong&gt; (Password also works)&lt;/li&gt;
&lt;li&gt;Hostname: &lt;code&gt;WebServer-1&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wj8xt2x7tox1kmq5683.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wj8xt2x7tox1kmq5683.gif" alt="create-server-1" width="720" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the droplet is ready, connect to the server.&lt;/p&gt;




&lt;h1&gt;
  
  
  Preparing the server
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Create a user
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;This user will run the application and manage Docker.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Create the application folder
&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/app
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Create the application files
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;index.php&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A very small script that prints the server IP responding to the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Hi. From ip '&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$_SERVER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SERVER_ADDR'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;code&gt;nginx.conf&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Basic Nginx configuration to serve PHP via PHP-FPM.&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;localhost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.php&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;try_files&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt; &lt;span class="sr"&gt;\.php$&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_pass&lt;/span&gt; &lt;span class="nf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_index&lt;/span&gt; &lt;span class="s"&gt;index.php&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;fastcgi_param&lt;/span&gt; &lt;span class="s"&gt;SCRIPT_FILENAME&lt;/span&gt; &lt;span class="nv"&gt;$document_root$fastcgi_script_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;include&lt;/span&gt; &lt;span class="s"&gt;fastcgi_params&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;h3&gt;
  
  
  &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This setup runs &lt;strong&gt;Nginx + PHP-FPM&lt;/strong&gt; using Docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-web&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./:/var/www/html&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx.conf:/etc/nginx/conf.d/default.conf&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;php-fpm&lt;/span&gt;

  &lt;span class="na"&gt;php-fpm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php:8.2-fpm&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;php-app&lt;/span&gt;
    &lt;span class="na"&gt;network_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;host&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./:/var/www/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Start the application
&lt;/h2&gt;

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

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

&lt;/div&gt;



&lt;p&gt;If everything is correct you should see the containers starting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ebfgjd2nbkb3i8cxmgu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ebfgjd2nbkb3i8cxmgu.png" alt="app-start" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;strong&gt;server IP in your browser&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi. From ip 10.x.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q5s7v1ykntmpwgwrze0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6q5s7v1ykntmpwgwrze0.png" alt="app-running" width="446" height="275"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Creating the Load Balancer
&lt;/h1&gt;

&lt;p&gt;Now we create the &lt;strong&gt;DigitalOcean Load Balancer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cbsc6m7jfhakj3kmpjv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cbsc6m7jfhakj3kmpjv.gif" alt="load-balancer" width="600" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP forwarding&lt;/li&gt;
&lt;li&gt;Attach &lt;strong&gt;WebServer-1&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once created, open the &lt;strong&gt;load balancer IP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You’ll see something similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljl8v6qz9wpe63dxr9qz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljl8v6qz9wpe63dxr9qz.png" alt="lb-response" width="395" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the response shows an &lt;strong&gt;internal server IP&lt;/strong&gt;, because traffic between the load balancer and droplets happens inside DigitalOcean’s network.&lt;/p&gt;




&lt;h1&gt;
  
  
  Creating the second server faster
&lt;/h1&gt;

&lt;p&gt;Instead of repeating the setup manually, we can &lt;strong&gt;create a snapshot&lt;/strong&gt; of the first droplet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawsi0hnl7so42xc3ilhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawsi0hnl7so42xc3ilhv.png" alt="snapshot" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then create a &lt;strong&gt;new droplet from that snapshot&lt;/strong&gt; in the same region.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhaxczvla64clgpfqmr9a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhaxczvla64clgpfqmr9a.png" alt="snapshot-server" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ac3ds1ktk5xo3mrzh2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4ac3ds1ktk5xo3mrzh2.gif" alt=" " width="600" height="589"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Adding the new node to the Load Balancer
&lt;/h1&gt;

&lt;p&gt;Go back to the Load Balancer configuration and attach the second server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft44g2ezvux5imh69t98b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft44g2ezvux5imh69t98b.png" alt="attach-node" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After about a minute, DigitalOcean will mark the droplet as &lt;strong&gt;healthy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now refresh the Load Balancer IP multiple times.&lt;/p&gt;

&lt;p&gt;You should see responses coming from &lt;strong&gt;different internal IPs&lt;/strong&gt;, meaning traffic is being distributed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcbf7jyehw5d1934bm47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcbf7jyehw5d1934bm47.png" alt="node1" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5ofclo5h1h1gr4jp5lc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5ofclo5h1h1gr4jp5lc.png" alt="node2" width="616" height="327"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Security recommendations
&lt;/h1&gt;

&lt;p&gt;This example focuses on the &lt;strong&gt;basic load balancing setup&lt;/strong&gt;, but in a real environment you should also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;strong&gt;DigitalOcean firewall&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Restrict droplets so they are &lt;strong&gt;only reachable from the load balancer&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;HTTPS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure &lt;strong&gt;health checks&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These small changes significantly improve the security of the system.&lt;/p&gt;




&lt;h1&gt;
  
  
  Tools used
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OBS&lt;/strong&gt; – screen recording&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kdenlive&lt;/strong&gt; – video editing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://savnet.co" rel="noopener noreferrer"&gt;savnet.co&lt;/a&gt;&lt;/strong&gt; – architecture diagrams used in this article&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>cloud</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
