<?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: Valen Torassa</title>
    <description>The latest articles on DEV Community by Valen Torassa (@vtsecurity).</description>
    <link>https://dev.to/vtsecurity</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4194222%2Fd6e7d980-90ca-47fc-982c-f8b19d281143.png</url>
      <title>DEV Community: Valen Torassa</title>
      <link>https://dev.to/vtsecurity</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vtsecurity"/>
    <language>en</language>
    <item>
      <title>Address already in use: quién tiene el puerto y por qué kill -9 va al final</title>
      <dc:creator>Valen Torassa</dc:creator>
      <pubDate>Tue, 27 Oct 2026 18:00:02 +0000</pubDate>
      <link>https://dev.to/vtsecurity/address-already-in-use-quien-tiene-el-puerto-y-por-que-kill-9-va-al-final-2e5k</link>
      <guid>https://dev.to/vtsecurity/address-already-in-use-quien-tiene-el-puerto-y-por-que-kill-9-va-al-final-2e5k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Cómo encontrar el proceso con &lt;code&gt;ss&lt;/code&gt;, ver quién lo levantó y cortarlo sin &lt;code&gt;kill -9&lt;/code&gt;. Y qué significa que esté escuchando en &lt;code&gt;0.0.0.0&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pasa así: levantás tu app, la terminal te devuelve &lt;code&gt;EADDRINUSE&lt;/code&gt; y no arranca. Buscás el error y la primera respuesta dice &lt;code&gt;kill -9 $(lsof -t -i:3000)&lt;/code&gt;. Lo corrés y anda.&lt;/p&gt;

&lt;p&gt;Casi siempre. A veces el puerto vuelve a estar ocupado un segundo después. Otras, lo que mataste era la base de otro proyecto que tenías abierto. Y en el camino se pasa por alto algo que importa más que el error: ese proceso que no sabías que seguía corriendo también podía estar atendiendo a otras máquinas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quién tiene el puerto
&lt;/h2&gt;

&lt;p&gt;El error solo dice el puerto. Para saber quién lo tiene está &lt;code&gt;ss&lt;/code&gt;, que viene en cualquier distro actual:&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="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"require('http').createServer().listen(3000)"&lt;/span&gt;
Error: listen EADDRINUSE: address already &lt;span class="k"&gt;in &lt;/span&gt;use :::3000
&lt;span class="nv"&gt;$ &lt;/span&gt;ss &lt;span class="nt"&gt;-ltnp&lt;/span&gt; &lt;span class="s1"&gt;'sport = :3000'&lt;/span&gt;
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      5            0.0.0.0:3000      0.0.0.0:&lt;span class="k"&gt;*&lt;/span&gt;    &lt;span class="nb"&gt;users&lt;/span&gt;:&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="s2"&gt;"python3"&lt;/span&gt;,pid&lt;span class="o"&gt;=&lt;/span&gt;3365731,fd&lt;span class="o"&gt;=&lt;/span&gt;3&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-l&lt;/code&gt; muestra lo que está escuchando, &lt;code&gt;-t&lt;/code&gt; TCP, &lt;code&gt;-n&lt;/code&gt; números en vez de nombres y &lt;code&gt;-p&lt;/code&gt; el proceso. La última columna es la respuesta: un &lt;code&gt;python3&lt;/code&gt; con PID 3365731. Si esa columna sale vacía, el proceso es de otro usuario y con &lt;code&gt;sudo&lt;/code&gt; adelante aparece.&lt;/p&gt;

&lt;p&gt;Con el PID, &lt;code&gt;ps&lt;/code&gt; te dice qué es y hace cuánto corre:&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="nv"&gt;$ &lt;/span&gt;ps &lt;span class="nt"&gt;-o&lt;/span&gt; pid,ppid,user,etime,cmd &lt;span class="nt"&gt;-p&lt;/span&gt; 3365731
    PID    PPID USER         ELAPSED CMD
3365731 3365724 valen          00:01 python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acá dice un segundo porque lo levanté para el ejemplo; uno olvidado suele decir días. &lt;code&gt;python3 -m http.server&lt;/code&gt; es un clásico: lo usaste para pasar un archivo y quedó corriendo en otra terminal, sirviendo la carpeta entera donde lo levantaste, archivos ocultos incluidos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;En macOS &lt;code&gt;ss&lt;/code&gt; no existe.&lt;/em&gt; &lt;code&gt;lsof -i :3000&lt;/code&gt; te da lo mismo, y en Linux también anda.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Qué quiere decir &lt;code&gt;0.0.0.0&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Volvé a la columna &lt;code&gt;Local Address&lt;/code&gt;. &lt;code&gt;0.0.0.0:3000&lt;/code&gt; quiere decir que el proceso acepta conexiones por cualquier interfaz de la máquina: le puede hablar cualquiera que esté en tu red.&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://vtsecurity.com.ar/articulo/address-already-in-use?ref=devto#que-quiere-decir-0000" rel="noopener noreferrer"&gt;artículo original&lt;/a&gt; esto es una figura donde mandás pedidos y cambiás la dirección mientras llegan. Con &lt;code&gt;0.0.0.0&lt;/code&gt;, cualquiera en tu red llega al puerto y se baja el &lt;code&gt;.env&lt;/code&gt;. Con &lt;code&gt;127.0.0.1&lt;/code&gt;, solo tu navegador:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tu máquina: python3 -m http.server sirve .env y app.js

escucha en 0.0.0.0:3000
  tu navegador             recibe la respuesta
  otra máquina de tu red   se lleva el .env (OPENAI_API_KEY=sk-…)
  internet                 lo corta el router

escucha en 127.0.0.1:3000
  tu navegador             recibe la respuesta
  otra máquina de tu red   conexión rechazada
  internet                 lo corta el router
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Red de ejemplo. El router corta lo que entra de internet mientras nadie le abra el puerto.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lo probé con ese mismo servidor, levantado en una carpeta de prueba con un &lt;code&gt;.env&lt;/code&gt;. Desde otra máquina de la red:&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="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://&amp;lt;ip&amp;gt;:3000/.env
&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-proj-demo-no-es-real
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La key es de mentira y &lt;code&gt;&amp;lt;ip&amp;gt;&lt;/code&gt; reemplaza la de mi máquina. Levantado con &lt;code&gt;--bind 127.0.0.1&lt;/code&gt;, el mismo curl devuelve &lt;code&gt;Couldn't connect to server&lt;/code&gt;. Y si lo corrés en tu home, la carpeta que se sirve incluye &lt;code&gt;.ssh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El error de Node de más arriba también lo dice: &lt;code&gt;:::3000&lt;/code&gt;. Si no le pasás una dirección, &lt;code&gt;listen(3000)&lt;/code&gt; escucha en &lt;code&gt;::&lt;/code&gt;, que son todas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Un firewall o el router pueden cortar la conexión antes.&lt;/em&gt; En una red que no es tuya, no contaría con eso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;kill&lt;/code&gt; manda una señal
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;kill&lt;/code&gt; no mata: le manda una señal al proceso. Si no le decís cuál, manda &lt;code&gt;TERM&lt;/code&gt;, que le pide terminar y lo deja cerrar lo que tiene abierto. &lt;code&gt;kill -9&lt;/code&gt; manda &lt;code&gt;KILL&lt;/code&gt;, que el programa no puede atender: el kernel lo saca en el acto.&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://vtsecurity.com.ar/articulo/address-already-in-use?ref=devto#kill-manda-una-senal" rel="noopener noreferrer"&gt;artículo original&lt;/a&gt; hay una figura con un programa que atiende pedidos y cada tanto guarda en el disco. Le mandás una señal, lo levantás de nuevo y probás la otra. Esto es lo que pasa con cada una:&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;# app (PID 4321) atiende pedidos, cada tanto guarda en datos.db y tiene su lock en app.pid&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;kill &lt;/span&gt;4321       &lt;span class="c"&gt;# TERM&lt;/span&gt;
&lt;span class="c"&gt;# deja de aceptar pedidos nuevos y termina los que tenía&lt;/span&gt;
&lt;span class="c"&gt;# guarda todo en datos.db y borra app.pid&lt;/span&gt;
&lt;span class="c"&gt;# lo que llega después rebota: no hay nadie escuchando&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; 4321    &lt;span class="c"&gt;# KILL&lt;/span&gt;
&lt;span class="c"&gt;# el kernel lo saca en el acto&lt;/span&gt;
&lt;span class="c"&gt;# el pedido a medio atender se corta y los cambios que tenía en memoria se pierden&lt;/span&gt;
&lt;span class="c"&gt;# app.pid queda, y sigue diciendo que ya está corriendo (PID 4321)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Programa de ejemplo. No todos dejan un lock, pero cualquiera pierde lo que no alcanzó a escribir.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Señal&lt;/th&gt;
&lt;th&gt;Número&lt;/th&gt;
&lt;th&gt;Qué pide&lt;/th&gt;
&lt;th&gt;¿La puede atender el proceso?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HUP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Varios servicios la usan para releer la configuración&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;INT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Es lo que manda Ctrl+C&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TERM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;Que termine: cerrar lo que tiene abierto y salir&lt;/td&gt;
&lt;td&gt;Sí&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;KILL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Nada. El kernel lo saca en el momento&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;El orden es &lt;code&gt;kill&lt;/code&gt;, esperar unos segundos, y &lt;code&gt;kill -9&lt;/code&gt; solo si sigue ahí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Si vuelve solo, es un servicio
&lt;/h2&gt;

&lt;p&gt;A veces matás el proceso y el puerto vuelve a estar ocupado al segundo. Lo reproduje con un servicio de systemd que se reinicia solo, y pasó exactamente eso.&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://vtsecurity.com.ar/articulo/address-already-in-use?ref=devto#si-vuelve-solo-es-un-servicio" rel="noopener noreferrer"&gt;artículo original&lt;/a&gt; hay una figura donde le mandás pedidos, lo matás y mirás qué pasa con los que llegan mientras no está:&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;# systemd --user vigila demo-web.service (Restart=always)&lt;/span&gt;
&lt;span class="c"&gt;# python3 -m http.server, con PID 3366803, tiene el puerto :3000&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; 3366803
&lt;span class="c"&gt;# el proceso murió: lo que llega rebota hasta que systemd lo levanta&lt;/span&gt;
&lt;span class="c"&gt;# un segundo después hay otro PID, 3366835, y el puerto vuelve a contestar&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; stop demo-web
&lt;span class="c"&gt;# systemctl stop le avisa a systemd: nadie lo relanza y todo lo que llega rebota&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Los dos PID son los de la prueba real.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;El padre de ese proceso es systemd, así que matarlo no sirve. &lt;code&gt;systemctl status&lt;/code&gt; acepta un PID y te dice de qué servicio es:&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="nv"&gt;$ &lt;/span&gt;systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; status 3366835 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-4&lt;/span&gt;
● demo-web.service - &lt;span class="o"&gt;[&lt;/span&gt;systemd-run] /usr/bin/python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 3000 &lt;span class="nt"&gt;--bind&lt;/span&gt; 127.0.0.1
     Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/run/user/1000/systemd/transient/demo-web.service&lt;span class="p"&gt;;&lt;/span&gt; transient&lt;span class="o"&gt;)&lt;/span&gt;
  Transient: &lt;span class="nb"&gt;yes
     &lt;/span&gt;Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Fri 2026-09-25 11:21:28 &lt;span class="nt"&gt;-03&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 1s ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con eso sabés qué parar: &lt;code&gt;systemctl --user stop demo-web&lt;/code&gt;. En un servidor lo normal es un servicio del sistema, y va sin &lt;code&gt;--user&lt;/code&gt;. &lt;code&gt;systemctl disable&lt;/code&gt; hace que no vuelva a arrancar con la máquina.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Si en la columna del proceso dice &lt;code&gt;docker-proxy&lt;/code&gt;&lt;/em&gt;, el puerto lo publicó un contenedor. &lt;code&gt;docker ps&lt;/code&gt; te dice cuál, y se para con &lt;code&gt;docker stop&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  El criterio
&lt;/h2&gt;

&lt;p&gt;Antes de matar un proceso, fijate qué es y quién lo levantó: &lt;code&gt;ss -ltnp&lt;/code&gt; y &lt;code&gt;ps&lt;/code&gt; te lo dicen en dos líneas. Si vuelve solo, es un servicio y se para con &lt;code&gt;systemctl stop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Y mirá la dirección en la que escucha. Si dice &lt;code&gt;0.0.0.0&lt;/code&gt; y no sabés por qué, arreglá eso antes que el error.&lt;/p&gt;




&lt;p&gt;Practicalo en el lab: &lt;a href="https://securitylabs.valentorassa.com/labs/linux-real/proceso-socket-evidencia-demo/" rel="noopener noreferrer"&gt;Del proceso al socket: una investigación con datos de juguete&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lo publiqué primero en &lt;a href="https://vtsecurity.com.ar/articulo/address-already-in-use?ref=devto" rel="noopener noreferrer"&gt;vtsecurity.com.ar&lt;/a&gt;, donde las figuras son interactivas.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>webdev</category>
      <category>espanol</category>
    </item>
  </channel>
</rss>
