Entendiendo el archivo /etc/hosts

Mascote do LinuxPro escrevendo com um marcador no quadro que mapeia endereços a nomes, com o atalho local mais curto que o caminho até o servidor DNS

Nota (2026): publicación de 2017, revisada. Una corrección importante: el texto original sugería dominios .dev para desarrollo local. No los uses. El .dev se convirtió en un TLD real de Google y está en la lista de HSTS preload — los navegadores fuerzan HTTPS en él, y tu sitio local en HTTP simplemente deja de abrirse. Lo correcto hoy es .test o .localhost. La explicación está en la sección sobre nombres.

O /etc/hosts es la lista de nombres que tu máquina resuelve por sí sola, sin preguntar a nadie. Una línea allí tiene precedencia sobre el DNS entero de internet — lo que lo convierte en una herramienta genial para desarrollo y pruebas, y una buena trampa cuando alguien olvida una línea dentro.

El formato

Cada línea mapea una dirección IP a uno o más nombres. El # comenta:

endereço_IP      nome_canônico      [apelido...]

Un archivo típico:

127.0.0.1       localhost
127.0.1.1       minha-maquina
192.168.0.10    servidor.local     servidor

# IPv6
::1             localhost ip6-localhost ip6-loopback

O 127.0.0.1 es el loopback: tu propia máquina. El 127.0.1.1, que aparece en Debian y en Ubuntu, existe para que el hostname de la máquina se resuelva incluso sin red configurada: no es un error ni un duplicado.

Para ver el tuyo:

cat /etc/hosts

Y para editarlo se necesitan privilegios, porque es un archivo del sistema:

sudo nano /etc/hosts

Cómo probar (y por qué no con ping)

La herramienta adecuada es getent, porque consulta exactamente la misma cadena de resolución que usan los programas:

getent hosts servidor.local
# 192.168.0.10    servidor.local servidor

Aquí vive una confusión clásica, con un giro moderno. Históricamente, dig e nslookup hablan directamente con el servidor DNS e ignoran /etc/hosts — de ahí el consejo, repetido durante años, de que probar con dig no sirve.

Solo que en las distribuciones con systemd-resolved (Ubuntu moderno, Fedora) el dig consulta el stub en 127.0.0.53, y el resolved responde a partir de /etc/hosts. Es decir: ahí el dig ve el archivo. Para ver lo que el DNS externo responde realmente, apunte un servidor explícitamente:

getent hosts site.exemplo         # o que a maquina resolve (le /etc/hosts)
dig +short @8.8.8.8 site.exemplo  # o que o DNS externo responde
curl -I http://site.exemplo       # o teste de verdade, ponta a ponta

O getent sigue siendo la respuesta correcta para “lo que esta máquina resuelve realmente”, porque es el único que recorre la misma cadena que usan los programas.

Quién decide el orden: el nsswitch.conf

O /etc/hosts tener prioridad sobre el DNS no es ley de la naturaleza: es configuración, y vive en otro archivo:

grep hosts /etc/nsswitch.conf
# algo como: hosts: files mdns4_minimal [NOTFOUND=return] dns mymachines

La línea exacta varía: el Debian puro trae solo files dns, y Fedora trae files myhostname resolve [!UNAVAIL=return] dns. Lo que importa es la posición relativa.

Se lee de izquierda a derecha. files es el /etc/hosts, y por aparecer primero se consulta antes que el dns. Si alguien invierte ese orden, el archivo pierde precedencia: es el primer sitio donde mirar cuando una entrada aparentemente correcta es ignorada.

En las distribuciones que usan systemd-resolved (Ubuntu moderno, Fedora), el /etc/resolv.conf suele apuntar a 127.0.0.53 y la caché queda en manos del servicio. Esto no cambia la precedencia del /etc/hosts, que sigue consultándose antes — pero cambia dónde investigar el resto:

resolvectl status              # quais servidores DNS estao em uso
resolvectl query site.exemplo  # como o resolved resolve esse nome
sudo resolvectl flush-caches   # limpar o cache do resolvedor

Nombres para desarrollo local: usa .test

Este es el error más común, y el motivo de esta revisión. Durante años se ha usado .dev para proyecto local:

127.0.0.1    meuapp.dev      # NAO FACA ISSO

La cronología suele contarse mal, y eso importa. El .dev es un TLD de Google desde 2014, pero lo que rompió el uso local no fue la venta de dominios: fue el HSTS preload. En septiembre de 2017 el TLD completo entró en la lista integrada de Chromium y, a partir de Chrome 63, en diciembre de 2017, cualquier dirección .dev pasó a forzarse a HTTPS antes incluso de salir una petición. El registro público solo abrió en febrero de 2019 — es decir, el .dev ya era inviable para desarrollo local más de un año antes de existir un único sitio .dev en el mundo.

Y no hay solución: la entrada cubre el TLD completo con include_subdomains, la lista viene integrada en Chrome, Firefox y Edge, y un dominio en HSTS preload tampoco ofrece el botón de “continuar de todas formas” en la pantalla de error de certificado. Tu servidor local en HTTP simplemente nunca se alcanza.

Usa los nombres que el RFC 6761 reserva precisamente para eso y que nunca se venderán como dominio:

127.0.0.1    meuapp.test
127.0.0.1    api.meuapp.test
127.0.0.1    blog.meuapp.test

Están reservados .test, .example, .invalid e .localhost. Para desarrollo, .test es lo indicado. Y hay una bonificación en .localhost: donde existe systemd-resolved o el módulo myhostname no nsswitch.conf, cualquier *.localhost ya va al loopback automáticamente — meuapp.localhost funciona sin editar ningún archivo. Esto viene de systemd, no de glibc: en una máquina sin ninguno de los dos, no funciona. Compruébelo con getent hosts meuapp.localhost.

Usos que valen en el día a día

Probar un servidor antes de cambiar el DNS. Es el uso más útil: apunta el dominio real al servidor nuevo solo en tu máquina, comprueba que todo está correcto y solo entonces cambias el DNS de verdad.

203.0.113.50    www.meusite.com.br    meusite.com.br

El navegador va al servidor nuevo mientras el resto del mundo sigue yendo al antiguo. Terminado la prueba, borra la línea — olvidarla ahí es el origen clásico del “el sitio cambió para todo el mundo, menos para mí”.

Bloquear dominios. Apuntar un nombre a 0.0.0.0 hace que la conexión falle inmediatamente:

0.0.0.0    dominio-indesejado.com

Con un matiz importante en Linux: conectar a 0.0.0.0 cae en su propio 127.0.0.1. Si ejecutas un servidor web local, el “bloqueo” mostrará el seu sitio en lugar de fallar. Solo hay rechazo inmediato cuando no hay nada escuchando en ese puerto.

Funciona para bloqueo puntual. Para bloqueo amplio, una lista enorme en /etc/hosts penaliza toda la resolución de nombres de la máquina — ahí el camino es un resolvedor con filtro, como Pi-hole o dnsmasq.

Acortar nombres de máquinas de la red local, para no memorizar IP:

192.168.0.10    nas
192.168.0.20    impressora
192.168.0.30    servidor-web    web

Con esto, ssh web e ping nas empiezan a funcionar. Combina bien con la ~/.ssh/config del post sobre claves SSH.

Cuando no funciona

Tres causas explican casi todos los casos:

  • Caché del navegador. Chrome y Firefox mantienen su propia caché de DNS. Prueba antes con getent hosts nome o curl; si responde correctamente en la terminal pero no en el navegador, el problema es su caché (en Chrome, chrome://net-internals/#dns).
  • Falta el nombre exacto. meusite.com.br e www.meusite.com.br son nombres diferentes. Ponlos ambos en la línea.
  • Orden en nsswitch.conf modificado, con dns antes de files.

También conviene saber que el /etc/hosts solo resuelve direcciones. No se puede mapear registros MX, SRV o TXT allí — quien intenta configurar el correo electrónico a través del archivo se da cabezazos en balde.

Y el aviso que cierra el tema: el /etc/hosts solo vale en la máquina donde se encuentra. No existe “propagar” — en un servidor, el lugar para mapear nombres es el DNS, asunto del post Conociendo el DNS.

Para continuar