[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-/blog/tutorial/traefik-reverse-proxy-docker":3,"prev-/blog/tutorial/traefik-reverse-proxy-docker":1965,"next-/blog/tutorial/traefik-reverse-proxy-docker":1968,"related-/blog/tutorial/traefik-reverse-proxy-docker":1971},{"id":4,"title":5,"author":6,"authorUrl":7,"body":8,"category":1932,"cta":1933,"date":1936,"dateModified":1936,"description":1937,"draft":1938,"extension":1939,"faq":1940,"featured":1938,"image":1953,"imageAlt":1954,"meta":1955,"navigation":111,"path":1956,"readingTime":214,"seo":1957,"stem":1958,"tags":1959,"__hash__":1964},"blog/blog/tutorial/traefik-reverse-proxy-docker.md","Configurar Traefik como reverse proxy para contenedores Docker","Syswork México","/nosotros",{"type":9,"value":10,"toc":1914},"minimark",[11,26,31,42,45,49,62,66,72,141,145,405,408,412,698,701,719,725,758,761,821,824,842,849,853,860,996,1018,1025,1041,1045,1048,1469,1471,1485,1489,1492,1497,1576,1580,1613,1617,1650,1654,1676,1680,1691,1770,1773,1795,1802,1804,1808,1811,1855,1859,1862,1901,1910],[12,13,14,15,20,21,25],"p",{},"Si gestionas múltiples aplicaciones con ",[16,17,19],"a",{"href":18},"/blog/docker-compose-guia-completa","Docker Compose",", sabes el dolor de mantener la configuración de ",[16,22,24],{"href":23},"/blog/nginx-reverse-proxy-ssl","Nginx"," sincronizada con tus contenedores. Cada vez que agregas un servicio, tienes que editar el archivo de Nginx, recargar la configuración y generar el certificado SSL. Traefik elimina ese trabajo: detecta tus contenedores automáticamente, crea las rutas y obtiene los certificados SSL — todo sin que toques un archivo de configuración.",[27,28,30],"h2",{"id":29},"arquitectura","Arquitectura",[32,33,38],"pre",{"className":34,"code":36,"language":37},[35],"language-text","┌──────────────────────────────────────────────────┐\n│                   Internet                        │\n│              :80 (HTTP) → :443 (HTTPS)            │\n└────────────────────┬─────────────────────────────┘\n                     │\n┌────────────────────▼─────────────────────────────┐\n│              Traefik (contenedor)                  │\n│   - Descubrimiento automático via Docker API      │\n│   - SSL automático con Let's Encrypt              │\n│   - Dashboard de monitoreo                        │\n└───┬────────────────┬──────────────────┬──────────┘\n    │                │                  │\n┌───▼───┐      ┌────▼────┐       ┌────▼────┐\n│  ERP  │      │   API   │       │ Grafana │\n│:8069  │      │  :8000  │       │  :3000  │\n│erp.   │      │api.     │       │monitor. │\n│empresa│      │empresa  │       │empresa  │\n│.com   │      │.com     │       │.com     │\n└───────┘      └─────────┘       └─────────┘\n","text",[39,40,36],"code",{"__ignoreMap":41},"",[12,43,44],{},"Traefik se conecta a la API de Docker, descubre los contenedores con labels específicas y automáticamente configura las rutas, middlewares y certificados.",[27,46,48],{"id":47},"requisitos-previos","Requisitos previos",[12,50,51,52,56,57,61],{},"Un servidor con ",[16,53,55],{"href":54},"/tecnologias/docker","Docker"," y Docker Compose instalados, un dominio que apunte al servidor (registro DNS tipo A) y los puertos 80 y 443 abiertos en tu ",[16,58,60],{"href":59},"/blog/configurar-firewall-ufw-linux","firewall UFW",".",[27,63,65],{"id":64},"paso-1-estructura-del-proyecto","Paso 1: Estructura del proyecto",[32,67,70],{"className":68,"code":69,"language":37},[35],"traefik/\n├── docker-compose.yml\n├── .env\n└── data/\n    ├── traefik.yml          # Configuración estática de Traefik\n    └── acme.json            # Certificados SSL (se genera solo)\n",[39,71,69],{"__ignoreMap":41},[32,73,77],{"className":74,"code":75,"language":76,"meta":41,"style":41},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","mkdir -p traefik/data\ncd traefik\n\n# Crear archivo de certificados con permisos correctos\ntouch data/acme.json\nchmod 600 data/acme.json\n","bash",[39,78,79,96,106,113,120,129],{"__ignoreMap":41},[80,81,84,88,92],"span",{"class":82,"line":83},"line",1,[80,85,87],{"class":86},"sbgvK","mkdir",[80,89,91],{"class":90},"stzsN"," -p",[80,93,95],{"class":94},"s_sjI"," traefik/data\n",[80,97,99,103],{"class":82,"line":98},2,[80,100,102],{"class":101},"sptTA","cd",[80,104,105],{"class":94}," traefik\n",[80,107,109],{"class":82,"line":108},3,[80,110,112],{"emptyLinePlaceholder":111},true,"\n",[80,114,116],{"class":82,"line":115},4,[80,117,119],{"class":118},"sutJx","# Crear archivo de certificados con permisos correctos\n",[80,121,123,126],{"class":82,"line":122},5,[80,124,125],{"class":86},"touch",[80,127,128],{"class":94}," data/acme.json\n",[80,130,132,135,139],{"class":82,"line":131},6,[80,133,134],{"class":86},"chmod",[80,136,138],{"class":137},"srdBf"," 600",[80,140,128],{"class":94},[27,142,144],{"id":143},"paso-2-configuración-estática-de-traefik","Paso 2: Configuración estática de Traefik",[32,146,148],{"className":74,"code":147,"language":76,"meta":41,"style":41},"cat > data/traefik.yml \u003C\u003C'EOF'\n# --- Entrypoints ---\nentryPoints:\n  web:\n    address: \":80\"\n    http:\n      redirections:\n        entryPoint:\n          to: websecure\n          scheme: https\n  websecure:\n    address: \":443\"\n\n# --- Proveedor Docker ---\nproviders:\n  docker:\n    endpoint: \"unix:///var/run/docker.sock\"\n    exposedByDefault: false    # Solo exponer contenedores con labels explícitas\n    network: proxy             # Red que comparten Traefik y los servicios\n\n# --- Let's Encrypt ---\ncertificatesResolvers:\n  letsencrypt:\n    acme:\n      email: admin@tuempresa.com\n      storage: /data/acme.json\n      httpChallenge:\n        entryPoint: web\n\n# --- Dashboard ---\napi:\n  dashboard: true\n  insecure: false    # Solo accesible via router con autenticación\n\n# --- Logs ---\nlog:\n  level: INFO\n\naccessLog:\n  filePath: \"/var/log/traefik/access.log\"\n  bufferingSize: 100\nEOF\n",[39,149,150,169,174,179,184,189,194,200,206,212,218,224,230,235,241,247,253,259,265,271,276,282,288,294,300,306,312,318,324,329,335,341,347,353,358,364,370,376,381,387,393,399],{"__ignoreMap":41},[80,151,152,155,159,162,165],{"class":82,"line":83},[80,153,154],{"class":86},"cat",[80,156,158],{"class":157},"smGrS"," >",[80,160,161],{"class":94}," data/traefik.yml",[80,163,164],{"class":157}," \u003C\u003C",[80,166,168],{"class":167},"sjJ54","'EOF'\n",[80,170,171],{"class":82,"line":98},[80,172,173],{"class":94},"# --- Entrypoints ---\n",[80,175,176],{"class":82,"line":108},[80,177,178],{"class":94},"entryPoints:\n",[80,180,181],{"class":82,"line":115},[80,182,183],{"class":94},"  web:\n",[80,185,186],{"class":82,"line":122},[80,187,188],{"class":94},"    address: \":80\"\n",[80,190,191],{"class":82,"line":131},[80,192,193],{"class":94},"    http:\n",[80,195,197],{"class":82,"line":196},7,[80,198,199],{"class":94},"      redirections:\n",[80,201,203],{"class":82,"line":202},8,[80,204,205],{"class":94},"        entryPoint:\n",[80,207,209],{"class":82,"line":208},9,[80,210,211],{"class":94},"          to: websecure\n",[80,213,215],{"class":82,"line":214},10,[80,216,217],{"class":94},"          scheme: https\n",[80,219,221],{"class":82,"line":220},11,[80,222,223],{"class":94},"  websecure:\n",[80,225,227],{"class":82,"line":226},12,[80,228,229],{"class":94},"    address: \":443\"\n",[80,231,233],{"class":82,"line":232},13,[80,234,112],{"emptyLinePlaceholder":111},[80,236,238],{"class":82,"line":237},14,[80,239,240],{"class":94},"# --- Proveedor Docker ---\n",[80,242,244],{"class":82,"line":243},15,[80,245,246],{"class":94},"providers:\n",[80,248,250],{"class":82,"line":249},16,[80,251,252],{"class":94},"  docker:\n",[80,254,256],{"class":82,"line":255},17,[80,257,258],{"class":94},"    endpoint: \"unix:///var/run/docker.sock\"\n",[80,260,262],{"class":82,"line":261},18,[80,263,264],{"class":94},"    exposedByDefault: false    # Solo exponer contenedores con labels explícitas\n",[80,266,268],{"class":82,"line":267},19,[80,269,270],{"class":94},"    network: proxy             # Red que comparten Traefik y los servicios\n",[80,272,274],{"class":82,"line":273},20,[80,275,112],{"emptyLinePlaceholder":111},[80,277,279],{"class":82,"line":278},21,[80,280,281],{"class":94},"# --- Let's Encrypt ---\n",[80,283,285],{"class":82,"line":284},22,[80,286,287],{"class":94},"certificatesResolvers:\n",[80,289,291],{"class":82,"line":290},23,[80,292,293],{"class":94},"  letsencrypt:\n",[80,295,297],{"class":82,"line":296},24,[80,298,299],{"class":94},"    acme:\n",[80,301,303],{"class":82,"line":302},25,[80,304,305],{"class":94},"      email: admin@tuempresa.com\n",[80,307,309],{"class":82,"line":308},26,[80,310,311],{"class":94},"      storage: /data/acme.json\n",[80,313,315],{"class":82,"line":314},27,[80,316,317],{"class":94},"      httpChallenge:\n",[80,319,321],{"class":82,"line":320},28,[80,322,323],{"class":94},"        entryPoint: web\n",[80,325,327],{"class":82,"line":326},29,[80,328,112],{"emptyLinePlaceholder":111},[80,330,332],{"class":82,"line":331},30,[80,333,334],{"class":94},"# --- Dashboard ---\n",[80,336,338],{"class":82,"line":337},31,[80,339,340],{"class":94},"api:\n",[80,342,344],{"class":82,"line":343},32,[80,345,346],{"class":94},"  dashboard: true\n",[80,348,350],{"class":82,"line":349},33,[80,351,352],{"class":94},"  insecure: false    # Solo accesible via router con autenticación\n",[80,354,356],{"class":82,"line":355},34,[80,357,112],{"emptyLinePlaceholder":111},[80,359,361],{"class":82,"line":360},35,[80,362,363],{"class":94},"# --- Logs ---\n",[80,365,367],{"class":82,"line":366},36,[80,368,369],{"class":94},"log:\n",[80,371,373],{"class":82,"line":372},37,[80,374,375],{"class":94},"  level: INFO\n",[80,377,379],{"class":82,"line":378},38,[80,380,112],{"emptyLinePlaceholder":111},[80,382,384],{"class":82,"line":383},39,[80,385,386],{"class":94},"accessLog:\n",[80,388,390],{"class":82,"line":389},40,[80,391,392],{"class":94},"  filePath: \"/var/log/traefik/access.log\"\n",[80,394,396],{"class":82,"line":395},41,[80,397,398],{"class":94},"  bufferingSize: 100\n",[80,400,402],{"class":82,"line":401},42,[80,403,404],{"class":167},"EOF\n",[406,407],"ad-banner",{},[27,409,411],{"id":410},"paso-3-docker-compose-con-traefik","Paso 3: Docker Compose con Traefik",[32,413,417],{"className":414,"code":415,"language":416,"meta":41,"style":41},"language-yaml shiki shiki-themes material-theme-lighter github-light github-dark","# docker-compose.yml\nservices:\n  traefik:\n    image: traefik:v3.2\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n      - ./data/traefik.yml:/etc/traefik/traefik.yml:ro\n      - ./data/acme.json:/data/acme.json\n      - traefik_logs:/var/log/traefik\n    networks:\n      - proxy\n    labels:\n      # Dashboard de Traefik\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.dashboard.rule=Host(`traefik.tuempresa.com`)\"\n      - \"traefik.http.routers.dashboard.entrypoints=websecure\"\n      - \"traefik.http.routers.dashboard.tls.certresolver=letsencrypt\"\n      - \"traefik.http.routers.dashboard.service=api@internal\"\n      # Autenticación básica para el dashboard\n      # Genera con: echo $(htpasswd -nB admin) | sed -e 's/\\$/\\$\\$/g'\n      - \"traefik.http.routers.dashboard.middlewares=dashboard-auth\"\n      - \"traefik.http.middlewares.dashboard-auth.basicauth.users=${DASHBOARD_AUTH}\"\n\nnetworks:\n  proxy:\n    name: proxy\n    external: true\n\nvolumes:\n  traefik_logs:\n","yaml",[39,418,419,424,434,441,452,462,469,483,494,501,508,515,522,529,536,543,550,555,566,577,588,599,610,615,620,631,642,646,653,660,669,680,684,691],{"__ignoreMap":41},[80,420,421],{"class":82,"line":83},[80,422,423],{"class":118},"# docker-compose.yml\n",[80,425,426,430],{"class":82,"line":98},[80,427,429],{"class":428},"sQzsp","services",[80,431,433],{"class":432},"sP7_E",":\n",[80,435,436,439],{"class":82,"line":108},[80,437,438],{"class":428},"  traefik",[80,440,433],{"class":432},[80,442,443,446,449],{"class":82,"line":115},[80,444,445],{"class":428},"    image",[80,447,448],{"class":432},":",[80,450,451],{"class":94}," traefik:v3.2\n",[80,453,454,457,459],{"class":82,"line":122},[80,455,456],{"class":428},"    restart",[80,458,448],{"class":432},[80,460,461],{"class":94}," unless-stopped\n",[80,463,464,467],{"class":82,"line":131},[80,465,466],{"class":428},"    ports",[80,468,433],{"class":432},[80,470,471,474,477,480],{"class":82,"line":196},[80,472,473],{"class":432},"      -",[80,475,476],{"class":167}," \"",[80,478,479],{"class":94},"80:80",[80,481,482],{"class":167},"\"\n",[80,484,485,487,489,492],{"class":82,"line":202},[80,486,473],{"class":432},[80,488,476],{"class":167},[80,490,491],{"class":94},"443:443",[80,493,482],{"class":167},[80,495,496,499],{"class":82,"line":208},[80,497,498],{"class":428},"    volumes",[80,500,433],{"class":432},[80,502,503,505],{"class":82,"line":214},[80,504,473],{"class":432},[80,506,507],{"class":94}," /var/run/docker.sock:/var/run/docker.sock:ro\n",[80,509,510,512],{"class":82,"line":220},[80,511,473],{"class":432},[80,513,514],{"class":94}," ./data/traefik.yml:/etc/traefik/traefik.yml:ro\n",[80,516,517,519],{"class":82,"line":226},[80,518,473],{"class":432},[80,520,521],{"class":94}," ./data/acme.json:/data/acme.json\n",[80,523,524,526],{"class":82,"line":232},[80,525,473],{"class":432},[80,527,528],{"class":94}," traefik_logs:/var/log/traefik\n",[80,530,531,534],{"class":82,"line":237},[80,532,533],{"class":428},"    networks",[80,535,433],{"class":432},[80,537,538,540],{"class":82,"line":243},[80,539,473],{"class":432},[80,541,542],{"class":94}," proxy\n",[80,544,545,548],{"class":82,"line":249},[80,546,547],{"class":428},"    labels",[80,549,433],{"class":432},[80,551,552],{"class":82,"line":255},[80,553,554],{"class":118},"      # Dashboard de Traefik\n",[80,556,557,559,561,564],{"class":82,"line":261},[80,558,473],{"class":432},[80,560,476],{"class":167},[80,562,563],{"class":94},"traefik.enable=true",[80,565,482],{"class":167},[80,567,568,570,572,575],{"class":82,"line":267},[80,569,473],{"class":432},[80,571,476],{"class":167},[80,573,574],{"class":94},"traefik.http.routers.dashboard.rule=Host(`traefik.tuempresa.com`)",[80,576,482],{"class":167},[80,578,579,581,583,586],{"class":82,"line":273},[80,580,473],{"class":432},[80,582,476],{"class":167},[80,584,585],{"class":94},"traefik.http.routers.dashboard.entrypoints=websecure",[80,587,482],{"class":167},[80,589,590,592,594,597],{"class":82,"line":278},[80,591,473],{"class":432},[80,593,476],{"class":167},[80,595,596],{"class":94},"traefik.http.routers.dashboard.tls.certresolver=letsencrypt",[80,598,482],{"class":167},[80,600,601,603,605,608],{"class":82,"line":284},[80,602,473],{"class":432},[80,604,476],{"class":167},[80,606,607],{"class":94},"traefik.http.routers.dashboard.service=api@internal",[80,609,482],{"class":167},[80,611,612],{"class":82,"line":290},[80,613,614],{"class":118},"      # Autenticación básica para el dashboard\n",[80,616,617],{"class":82,"line":296},[80,618,619],{"class":118},"      # Genera con: echo $(htpasswd -nB admin) | sed -e 's/\\$/\\$\\$/g'\n",[80,621,622,624,626,629],{"class":82,"line":302},[80,623,473],{"class":432},[80,625,476],{"class":167},[80,627,628],{"class":94},"traefik.http.routers.dashboard.middlewares=dashboard-auth",[80,630,482],{"class":167},[80,632,633,635,637,640],{"class":82,"line":308},[80,634,473],{"class":432},[80,636,476],{"class":167},[80,638,639],{"class":94},"traefik.http.middlewares.dashboard-auth.basicauth.users=${DASHBOARD_AUTH}",[80,641,482],{"class":167},[80,643,644],{"class":82,"line":314},[80,645,112],{"emptyLinePlaceholder":111},[80,647,648,651],{"class":82,"line":320},[80,649,650],{"class":428},"networks",[80,652,433],{"class":432},[80,654,655,658],{"class":82,"line":326},[80,656,657],{"class":428},"  proxy",[80,659,433],{"class":432},[80,661,662,665,667],{"class":82,"line":331},[80,663,664],{"class":428},"    name",[80,666,448],{"class":432},[80,668,542],{"class":94},[80,670,671,674,676],{"class":82,"line":337},[80,672,673],{"class":428},"    external",[80,675,448],{"class":432},[80,677,679],{"class":678},"syTEX"," true\n",[80,681,682],{"class":82,"line":343},[80,683,112],{"emptyLinePlaceholder":111},[80,685,686,689],{"class":82,"line":349},[80,687,688],{"class":428},"volumes",[80,690,433],{"class":432},[80,692,693,696],{"class":82,"line":355},[80,694,695],{"class":428},"  traefik_logs",[80,697,433],{"class":432},[12,699,700],{},"Crea la red externa que compartirán Traefik y todos tus servicios:",[32,702,704],{"className":74,"code":703,"language":76,"meta":41,"style":41},"docker network create proxy\n",[39,705,706],{"__ignoreMap":41},[80,707,708,711,714,717],{"class":82,"line":83},[80,709,710],{"class":86},"docker",[80,712,713],{"class":94}," network",[80,715,716],{"class":94}," create",[80,718,542],{"class":94},[12,720,721,722,448],{},"Crea el archivo ",[39,723,724],{},".env",[32,726,728],{"className":74,"code":727,"language":76,"meta":41,"style":41},"# .env\n# Genera con: echo $(htpasswd -nB admin) | sed -e 's/\\$/\\$\\$/g'\nDASHBOARD_AUTH=admin:$$2y$$05$$abc123...tu-hash-aqui\n",[39,729,730,735,740],{"__ignoreMap":41},[80,731,732],{"class":82,"line":83},[80,733,734],{"class":118},"# .env\n",[80,736,737],{"class":82,"line":98},[80,738,739],{"class":118},"# Genera con: echo $(htpasswd -nB admin) | sed -e 's/\\$/\\$\\$/g'\n",[80,741,742,746,749,752,755],{"class":82,"line":108},[80,743,745],{"class":744},"su5hD","DASHBOARD_AUTH",[80,747,748],{"class":157},"=",[80,750,751],{"class":94},"admin:",[80,753,754],{"class":744},"$$2y$$05$$abc123",[80,756,757],{"class":94},"...tu-hash-aqui\n",[12,759,760],{},"Genera el hash de contraseña para el dashboard:",[32,762,764],{"className":74,"code":763,"language":76,"meta":41,"style":41},"sudo apt install apache2-utils -y\necho $(htpasswd -nB admin) | sed -e 's/\\$/\\$\\$/g'\n",[39,765,766,783],{"__ignoreMap":41},[80,767,768,771,774,777,780],{"class":82,"line":83},[80,769,770],{"class":86},"sudo",[80,772,773],{"class":94}," apt",[80,775,776],{"class":94}," install",[80,778,779],{"class":94}," apache2-utils",[80,781,782],{"class":90}," -y\n",[80,784,785,788,791,794,797,800,803,806,809,812,815,818],{"class":82,"line":98},[80,786,787],{"class":101},"echo",[80,789,790],{"class":432}," $(",[80,792,793],{"class":86},"htpasswd",[80,795,796],{"class":90}," -nB",[80,798,799],{"class":94}," admin",[80,801,802],{"class":432},")",[80,804,805],{"class":157}," |",[80,807,808],{"class":86}," sed",[80,810,811],{"class":90}," -e",[80,813,814],{"class":167}," '",[80,816,817],{"class":94},"s/\\$/\\$\\$/g",[80,819,820],{"class":167},"'\n",[12,822,823],{},"Levanta Traefik:",[32,825,827],{"className":74,"code":826,"language":76,"meta":41,"style":41},"docker compose up -d\n",[39,828,829],{"__ignoreMap":41},[80,830,831,833,836,839],{"class":82,"line":83},[80,832,710],{"class":86},[80,834,835],{"class":94}," compose",[80,837,838],{"class":94}," up",[80,840,841],{"class":90}," -d\n",[12,843,844,845,848],{},"Verifica que funciona accediendo a ",[39,846,847],{},"https://traefik.tuempresa.com"," — deberías ver el dashboard con autenticación.",[27,850,852],{"id":851},"paso-4-agregar-tu-primera-aplicación","Paso 4: Agregar tu primera aplicación",[12,854,855,856,859],{},"Ahora la magia. Crea un servicio que Traefik descubra automáticamente. En otro directorio, crea un ",[39,857,858],{},"docker-compose.yml"," para tu aplicación:",[32,861,863],{"className":414,"code":862,"language":416,"meta":41,"style":41},"# ~/apps/mi-app/docker-compose.yml\nservices:\n  app:\n    image: nginx:alpine\n    restart: unless-stopped\n    networks:\n      - proxy\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.mi-app.rule=Host(`app.tuempresa.com`)\"\n      - \"traefik.http.routers.mi-app.entrypoints=websecure\"\n      - \"traefik.http.routers.mi-app.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.mi-app.loadbalancer.server.port=80\"\n\nnetworks:\n  proxy:\n    external: true\n",[39,864,865,870,876,883,892,900,906,912,918,928,939,950,961,972,976,982,988],{"__ignoreMap":41},[80,866,867],{"class":82,"line":83},[80,868,869],{"class":118},"# ~/apps/mi-app/docker-compose.yml\n",[80,871,872,874],{"class":82,"line":98},[80,873,429],{"class":428},[80,875,433],{"class":432},[80,877,878,881],{"class":82,"line":108},[80,879,880],{"class":428},"  app",[80,882,433],{"class":432},[80,884,885,887,889],{"class":82,"line":115},[80,886,445],{"class":428},[80,888,448],{"class":432},[80,890,891],{"class":94}," nginx:alpine\n",[80,893,894,896,898],{"class":82,"line":122},[80,895,456],{"class":428},[80,897,448],{"class":432},[80,899,461],{"class":94},[80,901,902,904],{"class":82,"line":131},[80,903,533],{"class":428},[80,905,433],{"class":432},[80,907,908,910],{"class":82,"line":196},[80,909,473],{"class":432},[80,911,542],{"class":94},[80,913,914,916],{"class":82,"line":202},[80,915,547],{"class":428},[80,917,433],{"class":432},[80,919,920,922,924,926],{"class":82,"line":208},[80,921,473],{"class":432},[80,923,476],{"class":167},[80,925,563],{"class":94},[80,927,482],{"class":167},[80,929,930,932,934,937],{"class":82,"line":214},[80,931,473],{"class":432},[80,933,476],{"class":167},[80,935,936],{"class":94},"traefik.http.routers.mi-app.rule=Host(`app.tuempresa.com`)",[80,938,482],{"class":167},[80,940,941,943,945,948],{"class":82,"line":220},[80,942,473],{"class":432},[80,944,476],{"class":167},[80,946,947],{"class":94},"traefik.http.routers.mi-app.entrypoints=websecure",[80,949,482],{"class":167},[80,951,952,954,956,959],{"class":82,"line":226},[80,953,473],{"class":432},[80,955,476],{"class":167},[80,957,958],{"class":94},"traefik.http.routers.mi-app.tls.certresolver=letsencrypt",[80,960,482],{"class":167},[80,962,963,965,967,970],{"class":82,"line":232},[80,964,473],{"class":432},[80,966,476],{"class":167},[80,968,969],{"class":94},"traefik.http.services.mi-app.loadbalancer.server.port=80",[80,971,482],{"class":167},[80,973,974],{"class":82,"line":237},[80,975,112],{"emptyLinePlaceholder":111},[80,977,978,980],{"class":82,"line":243},[80,979,650],{"class":428},[80,981,433],{"class":432},[80,983,984,986],{"class":82,"line":249},[80,985,657],{"class":428},[80,987,433],{"class":432},[80,989,990,992,994],{"class":82,"line":255},[80,991,673],{"class":428},[80,993,448],{"class":432},[80,995,679],{"class":678},[32,997,999],{"className":74,"code":998,"language":76,"meta":41,"style":41},"cd ~/apps/mi-app\ndocker compose up -d\n",[39,1000,1001,1008],{"__ignoreMap":41},[80,1002,1003,1005],{"class":82,"line":83},[80,1004,102],{"class":101},[80,1006,1007],{"class":94}," ~/apps/mi-app\n",[80,1009,1010,1012,1014,1016],{"class":82,"line":98},[80,1011,710],{"class":86},[80,1013,835],{"class":94},[80,1015,838],{"class":94},[80,1017,841],{"class":90},[12,1019,1020,1021,1024],{},"En segundos, Traefik detecta el nuevo contenedor, crea la ruta ",[39,1022,1023],{},"app.tuempresa.com",", obtiene el certificado SSL de Let's Encrypt y empieza a enrutar tráfico. Sin editar ningún archivo de Traefik, sin recargar nada.",[1026,1027,1030],"alert",{"title":1028,"type":1029},"Así de simple","info",[12,1031,1032,1033,1036,1037,1040],{},"Cada nueva aplicación es un ",[39,1034,1035],{},"docker compose up -d"," con las labels correctas. Traefik se encarga del resto — ruta, SSL, redirección HTTP→HTTPS. Cuando haces ",[39,1038,1039],{},"docker compose down",", Traefik elimina la ruta automáticamente.",[27,1042,1044],{"id":1043},"paso-5-ejemplo-con-aplicación-real-api-postgresql","Paso 5: Ejemplo con aplicación real — API + PostgreSQL",[12,1046,1047],{},"Un stack más realista con tu API FastAPI y PostgreSQL:",[32,1049,1051],{"className":414,"code":1050,"language":416,"meta":41,"style":41},"# ~/apps/api/docker-compose.yml\nservices:\n  api:\n    build: .\n    restart: unless-stopped\n    environment:\n      DATABASE_URL: postgresql+asyncpg://app:${DB_PASSWORD}@db:5432/miapi\n      SECRET_KEY: ${SECRET_KEY}\n    depends_on:\n      db:\n        condition: service_healthy\n    networks:\n      - proxy\n      - backend\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.api.rule=Host(`api.tuempresa.com`)\"\n      - \"traefik.http.routers.api.entrypoints=websecure\"\n      - \"traefik.http.routers.api.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.api.loadbalancer.server.port=8000\"\n      # Rate limiting\n      - \"traefik.http.routers.api.middlewares=api-ratelimit\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.average=100\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.burst=50\"\n\n  db:\n    image: postgres:16-alpine\n    restart: unless-stopped\n    environment:\n      POSTGRES_DB: miapi\n      POSTGRES_USER: app\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - pg_data:/var/lib/postgresql/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U app -d miapi\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    networks:\n      - backend\n\nnetworks:\n  proxy:\n    external: true\n  backend:\n\nvolumes:\n  pg_data:\n",[39,1052,1053,1058,1064,1071,1081,1089,1096,1106,1116,1123,1130,1140,1146,1152,1159,1165,1175,1186,1197,1208,1219,1224,1235,1246,1257,1261,1268,1277,1285,1291,1301,1311,1321,1327,1334,1341,1372,1382,1392,1402,1408,1414,1418,1425,1432,1441,1449,1454,1461],{"__ignoreMap":41},[80,1054,1055],{"class":82,"line":83},[80,1056,1057],{"class":118},"# ~/apps/api/docker-compose.yml\n",[80,1059,1060,1062],{"class":82,"line":98},[80,1061,429],{"class":428},[80,1063,433],{"class":432},[80,1065,1066,1069],{"class":82,"line":108},[80,1067,1068],{"class":428},"  api",[80,1070,433],{"class":432},[80,1072,1073,1076,1078],{"class":82,"line":115},[80,1074,1075],{"class":428},"    build",[80,1077,448],{"class":432},[80,1079,1080],{"class":137}," .\n",[80,1082,1083,1085,1087],{"class":82,"line":122},[80,1084,456],{"class":428},[80,1086,448],{"class":432},[80,1088,461],{"class":94},[80,1090,1091,1094],{"class":82,"line":131},[80,1092,1093],{"class":428},"    environment",[80,1095,433],{"class":432},[80,1097,1098,1101,1103],{"class":82,"line":196},[80,1099,1100],{"class":428},"      DATABASE_URL",[80,1102,448],{"class":432},[80,1104,1105],{"class":94}," postgresql+asyncpg://app:${DB_PASSWORD}@db:5432/miapi\n",[80,1107,1108,1111,1113],{"class":82,"line":202},[80,1109,1110],{"class":428},"      SECRET_KEY",[80,1112,448],{"class":432},[80,1114,1115],{"class":94}," ${SECRET_KEY}\n",[80,1117,1118,1121],{"class":82,"line":208},[80,1119,1120],{"class":428},"    depends_on",[80,1122,433],{"class":432},[80,1124,1125,1128],{"class":82,"line":214},[80,1126,1127],{"class":428},"      db",[80,1129,433],{"class":432},[80,1131,1132,1135,1137],{"class":82,"line":220},[80,1133,1134],{"class":428},"        condition",[80,1136,448],{"class":432},[80,1138,1139],{"class":94}," service_healthy\n",[80,1141,1142,1144],{"class":82,"line":226},[80,1143,533],{"class":428},[80,1145,433],{"class":432},[80,1147,1148,1150],{"class":82,"line":232},[80,1149,473],{"class":432},[80,1151,542],{"class":94},[80,1153,1154,1156],{"class":82,"line":237},[80,1155,473],{"class":432},[80,1157,1158],{"class":94}," backend\n",[80,1160,1161,1163],{"class":82,"line":243},[80,1162,547],{"class":428},[80,1164,433],{"class":432},[80,1166,1167,1169,1171,1173],{"class":82,"line":249},[80,1168,473],{"class":432},[80,1170,476],{"class":167},[80,1172,563],{"class":94},[80,1174,482],{"class":167},[80,1176,1177,1179,1181,1184],{"class":82,"line":255},[80,1178,473],{"class":432},[80,1180,476],{"class":167},[80,1182,1183],{"class":94},"traefik.http.routers.api.rule=Host(`api.tuempresa.com`)",[80,1185,482],{"class":167},[80,1187,1188,1190,1192,1195],{"class":82,"line":261},[80,1189,473],{"class":432},[80,1191,476],{"class":167},[80,1193,1194],{"class":94},"traefik.http.routers.api.entrypoints=websecure",[80,1196,482],{"class":167},[80,1198,1199,1201,1203,1206],{"class":82,"line":267},[80,1200,473],{"class":432},[80,1202,476],{"class":167},[80,1204,1205],{"class":94},"traefik.http.routers.api.tls.certresolver=letsencrypt",[80,1207,482],{"class":167},[80,1209,1210,1212,1214,1217],{"class":82,"line":273},[80,1211,473],{"class":432},[80,1213,476],{"class":167},[80,1215,1216],{"class":94},"traefik.http.services.api.loadbalancer.server.port=8000",[80,1218,482],{"class":167},[80,1220,1221],{"class":82,"line":278},[80,1222,1223],{"class":118},"      # Rate limiting\n",[80,1225,1226,1228,1230,1233],{"class":82,"line":284},[80,1227,473],{"class":432},[80,1229,476],{"class":167},[80,1231,1232],{"class":94},"traefik.http.routers.api.middlewares=api-ratelimit",[80,1234,482],{"class":167},[80,1236,1237,1239,1241,1244],{"class":82,"line":290},[80,1238,473],{"class":432},[80,1240,476],{"class":167},[80,1242,1243],{"class":94},"traefik.http.middlewares.api-ratelimit.ratelimit.average=100",[80,1245,482],{"class":167},[80,1247,1248,1250,1252,1255],{"class":82,"line":296},[80,1249,473],{"class":432},[80,1251,476],{"class":167},[80,1253,1254],{"class":94},"traefik.http.middlewares.api-ratelimit.ratelimit.burst=50",[80,1256,482],{"class":167},[80,1258,1259],{"class":82,"line":302},[80,1260,112],{"emptyLinePlaceholder":111},[80,1262,1263,1266],{"class":82,"line":308},[80,1264,1265],{"class":428},"  db",[80,1267,433],{"class":432},[80,1269,1270,1272,1274],{"class":82,"line":314},[80,1271,445],{"class":428},[80,1273,448],{"class":432},[80,1275,1276],{"class":94}," postgres:16-alpine\n",[80,1278,1279,1281,1283],{"class":82,"line":320},[80,1280,456],{"class":428},[80,1282,448],{"class":432},[80,1284,461],{"class":94},[80,1286,1287,1289],{"class":82,"line":326},[80,1288,1093],{"class":428},[80,1290,433],{"class":432},[80,1292,1293,1296,1298],{"class":82,"line":331},[80,1294,1295],{"class":428},"      POSTGRES_DB",[80,1297,448],{"class":432},[80,1299,1300],{"class":94}," miapi\n",[80,1302,1303,1306,1308],{"class":82,"line":337},[80,1304,1305],{"class":428},"      POSTGRES_USER",[80,1307,448],{"class":432},[80,1309,1310],{"class":94}," app\n",[80,1312,1313,1316,1318],{"class":82,"line":343},[80,1314,1315],{"class":428},"      POSTGRES_PASSWORD",[80,1317,448],{"class":432},[80,1319,1320],{"class":94}," ${DB_PASSWORD}\n",[80,1322,1323,1325],{"class":82,"line":349},[80,1324,498],{"class":428},[80,1326,433],{"class":432},[80,1328,1329,1331],{"class":82,"line":355},[80,1330,473],{"class":432},[80,1332,1333],{"class":94}," pg_data:/var/lib/postgresql/data\n",[80,1335,1336,1339],{"class":82,"line":360},[80,1337,1338],{"class":428},"    healthcheck",[80,1340,433],{"class":432},[80,1342,1343,1346,1348,1351,1354,1357,1359,1362,1364,1367,1369],{"class":82,"line":366},[80,1344,1345],{"class":428},"      test",[80,1347,448],{"class":432},[80,1349,1350],{"class":432}," [",[80,1352,1353],{"class":167},"\"",[80,1355,1356],{"class":94},"CMD-SHELL",[80,1358,1353],{"class":167},[80,1360,1361],{"class":432},",",[80,1363,476],{"class":167},[80,1365,1366],{"class":94},"pg_isready -U app -d miapi",[80,1368,1353],{"class":167},[80,1370,1371],{"class":432},"]\n",[80,1373,1374,1377,1379],{"class":82,"line":372},[80,1375,1376],{"class":428},"      interval",[80,1378,448],{"class":432},[80,1380,1381],{"class":94}," 10s\n",[80,1383,1384,1387,1389],{"class":82,"line":378},[80,1385,1386],{"class":428},"      timeout",[80,1388,448],{"class":432},[80,1390,1391],{"class":94}," 5s\n",[80,1393,1394,1397,1399],{"class":82,"line":383},[80,1395,1396],{"class":428},"      retries",[80,1398,448],{"class":432},[80,1400,1401],{"class":137}," 5\n",[80,1403,1404,1406],{"class":82,"line":389},[80,1405,533],{"class":428},[80,1407,433],{"class":432},[80,1409,1410,1412],{"class":82,"line":395},[80,1411,473],{"class":432},[80,1413,1158],{"class":94},[80,1415,1416],{"class":82,"line":401},[80,1417,112],{"emptyLinePlaceholder":111},[80,1419,1421,1423],{"class":82,"line":1420},43,[80,1422,650],{"class":428},[80,1424,433],{"class":432},[80,1426,1428,1430],{"class":82,"line":1427},44,[80,1429,657],{"class":428},[80,1431,433],{"class":432},[80,1433,1435,1437,1439],{"class":82,"line":1434},45,[80,1436,673],{"class":428},[80,1438,448],{"class":432},[80,1440,679],{"class":678},[80,1442,1444,1447],{"class":82,"line":1443},46,[80,1445,1446],{"class":428},"  backend",[80,1448,433],{"class":432},[80,1450,1452],{"class":82,"line":1451},47,[80,1453,112],{"emptyLinePlaceholder":111},[80,1455,1457,1459],{"class":82,"line":1456},48,[80,1458,688],{"class":428},[80,1460,433],{"class":432},[80,1462,1464,1467],{"class":82,"line":1463},49,[80,1465,1466],{"class":428},"  pg_data",[80,1468,433],{"class":432},[406,1470],{},[12,1472,1473,1474,1477,1478,1481,1482,1484],{},"Nota las dos redes: ",[39,1475,1476],{},"proxy"," (conecta al API con Traefik) y ",[39,1479,1480],{},"backend"," (conecta al API con PostgreSQL). La base de datos no está en la red ",[39,1483,1476],{}," — no es accesible desde internet, solo desde el contenedor de la API.",[27,1486,1488],{"id":1487},"paso-6-middlewares-útiles","Paso 6: Middlewares útiles",[12,1490,1491],{},"Traefik soporta middlewares que aplicas con labels. Los más útiles:",[1493,1494,1496],"h3",{"id":1495},"headers-de-seguridad","Headers de seguridad",[32,1498,1500],{"className":414,"code":1499,"language":416,"meta":41,"style":41},"labels:\n  - \"traefik.http.middlewares.security-headers.headers.stsSeconds=31536000\"\n  - \"traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true\"\n  - \"traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true\"\n  - \"traefik.http.middlewares.security-headers.headers.frameDeny=true\"\n  - \"traefik.http.middlewares.security-headers.headers.browserXssFilter=true\"\n  - \"traefik.http.routers.mi-app.middlewares=security-headers\"\n",[39,1501,1502,1509,1521,1532,1543,1554,1565],{"__ignoreMap":41},[80,1503,1504,1507],{"class":82,"line":83},[80,1505,1506],{"class":428},"labels",[80,1508,433],{"class":432},[80,1510,1511,1514,1516,1519],{"class":82,"line":98},[80,1512,1513],{"class":432},"  -",[80,1515,476],{"class":167},[80,1517,1518],{"class":94},"traefik.http.middlewares.security-headers.headers.stsSeconds=31536000",[80,1520,482],{"class":167},[80,1522,1523,1525,1527,1530],{"class":82,"line":108},[80,1524,1513],{"class":432},[80,1526,476],{"class":167},[80,1528,1529],{"class":94},"traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true",[80,1531,482],{"class":167},[80,1533,1534,1536,1538,1541],{"class":82,"line":115},[80,1535,1513],{"class":432},[80,1537,476],{"class":167},[80,1539,1540],{"class":94},"traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true",[80,1542,482],{"class":167},[80,1544,1545,1547,1549,1552],{"class":82,"line":122},[80,1546,1513],{"class":432},[80,1548,476],{"class":167},[80,1550,1551],{"class":94},"traefik.http.middlewares.security-headers.headers.frameDeny=true",[80,1553,482],{"class":167},[80,1555,1556,1558,1560,1563],{"class":82,"line":131},[80,1557,1513],{"class":432},[80,1559,476],{"class":167},[80,1561,1562],{"class":94},"traefik.http.middlewares.security-headers.headers.browserXssFilter=true",[80,1564,482],{"class":167},[80,1566,1567,1569,1571,1574],{"class":82,"line":196},[80,1568,1513],{"class":432},[80,1570,476],{"class":167},[80,1572,1573],{"class":94},"traefik.http.routers.mi-app.middlewares=security-headers",[80,1575,482],{"class":167},[1493,1577,1579],{"id":1578},"compresión-gzip","Compresión gzip",[32,1581,1583],{"className":414,"code":1582,"language":416,"meta":41,"style":41},"labels:\n  - \"traefik.http.middlewares.gzip.compress=true\"\n  - \"traefik.http.routers.mi-app.middlewares=gzip\"\n",[39,1584,1585,1591,1602],{"__ignoreMap":41},[80,1586,1587,1589],{"class":82,"line":83},[80,1588,1506],{"class":428},[80,1590,433],{"class":432},[80,1592,1593,1595,1597,1600],{"class":82,"line":98},[80,1594,1513],{"class":432},[80,1596,476],{"class":167},[80,1598,1599],{"class":94},"traefik.http.middlewares.gzip.compress=true",[80,1601,482],{"class":167},[80,1603,1604,1606,1608,1611],{"class":82,"line":108},[80,1605,1513],{"class":432},[80,1607,476],{"class":167},[80,1609,1610],{"class":94},"traefik.http.routers.mi-app.middlewares=gzip",[80,1612,482],{"class":167},[1493,1614,1616],{"id":1615},"ip-whitelist-restringir-acceso-por-ip","IP whitelist (restringir acceso por IP)",[32,1618,1620],{"className":414,"code":1619,"language":416,"meta":41,"style":41},"labels:\n  - \"traefik.http.middlewares.internal-only.ipallowlist.sourcerange=10.0.1.0/24,192.168.1.0/24\"\n  - \"traefik.http.routers.admin.middlewares=internal-only\"\n",[39,1621,1622,1628,1639],{"__ignoreMap":41},[80,1623,1624,1626],{"class":82,"line":83},[80,1625,1506],{"class":428},[80,1627,433],{"class":432},[80,1629,1630,1632,1634,1637],{"class":82,"line":98},[80,1631,1513],{"class":432},[80,1633,476],{"class":167},[80,1635,1636],{"class":94},"traefik.http.middlewares.internal-only.ipallowlist.sourcerange=10.0.1.0/24,192.168.1.0/24",[80,1638,482],{"class":167},[80,1640,1641,1643,1645,1648],{"class":82,"line":108},[80,1642,1513],{"class":432},[80,1644,476],{"class":167},[80,1646,1647],{"class":94},"traefik.http.routers.admin.middlewares=internal-only",[80,1649,482],{"class":167},[1493,1651,1653],{"id":1652},"combinar-múltiples-middlewares","Combinar múltiples middlewares",[32,1655,1657],{"className":414,"code":1656,"language":416,"meta":41,"style":41},"labels:\n  - \"traefik.http.routers.mi-app.middlewares=security-headers,gzip,api-ratelimit\"\n",[39,1658,1659,1665],{"__ignoreMap":41},[80,1660,1661,1663],{"class":82,"line":83},[80,1662,1506],{"class":428},[80,1664,433],{"class":432},[80,1666,1667,1669,1671,1674],{"class":82,"line":98},[80,1668,1513],{"class":432},[80,1670,476],{"class":167},[80,1672,1673],{"class":94},"traefik.http.routers.mi-app.middlewares=security-headers,gzip,api-ratelimit",[80,1675,482],{"class":167},[27,1677,1679],{"id":1678},"paso-7-monitorear-traefik-con-prometheus","Paso 7: Monitorear Traefik con Prometheus",[12,1681,1682,1683,1687,1688,448],{},"Traefik expone métricas para ",[16,1684,1686],{"href":1685},"/blog/monitoreo-grafana-prometheus","Prometheus",". Agrega a tu ",[39,1689,1690],{},"traefik.yml",[32,1692,1694],{"className":414,"code":1693,"language":416,"meta":41,"style":41},"metrics:\n  prometheus:\n    entryPoint: metrics\n    addServicesLabels: true\n    addEntryPointsLabels: true\n\nentryPoints:\n  metrics:\n    address: \":8082\"\n",[39,1695,1696,1703,1710,1720,1729,1738,1742,1749,1756],{"__ignoreMap":41},[80,1697,1698,1701],{"class":82,"line":83},[80,1699,1700],{"class":428},"metrics",[80,1702,433],{"class":432},[80,1704,1705,1708],{"class":82,"line":98},[80,1706,1707],{"class":428},"  prometheus",[80,1709,433],{"class":432},[80,1711,1712,1715,1717],{"class":82,"line":108},[80,1713,1714],{"class":428},"    entryPoint",[80,1716,448],{"class":432},[80,1718,1719],{"class":94}," metrics\n",[80,1721,1722,1725,1727],{"class":82,"line":115},[80,1723,1724],{"class":428},"    addServicesLabels",[80,1726,448],{"class":432},[80,1728,679],{"class":678},[80,1730,1731,1734,1736],{"class":82,"line":122},[80,1732,1733],{"class":428},"    addEntryPointsLabels",[80,1735,448],{"class":432},[80,1737,679],{"class":678},[80,1739,1740],{"class":82,"line":131},[80,1741,112],{"emptyLinePlaceholder":111},[80,1743,1744,1747],{"class":82,"line":196},[80,1745,1746],{"class":428},"entryPoints",[80,1748,433],{"class":432},[80,1750,1751,1754],{"class":82,"line":202},[80,1752,1753],{"class":428},"  metrics",[80,1755,433],{"class":432},[80,1757,1758,1761,1763,1765,1768],{"class":82,"line":208},[80,1759,1760],{"class":428},"    address",[80,1762,448],{"class":432},[80,1764,476],{"class":167},[80,1766,1767],{"class":94},":8082",[80,1769,482],{"class":167},[12,1771,1772],{},"Y la label para el contenedor de Traefik:",[32,1774,1776],{"className":414,"code":1775,"language":416,"meta":41,"style":41},"labels:\n  - \"traefik.http.services.traefik-metrics.loadbalancer.server.port=8082\"\n",[39,1777,1778,1784],{"__ignoreMap":41},[80,1779,1780,1782],{"class":82,"line":83},[80,1781,1506],{"class":428},[80,1783,433],{"class":432},[80,1785,1786,1788,1790,1793],{"class":82,"line":98},[80,1787,1513],{"class":432},[80,1789,476],{"class":167},[80,1791,1792],{"class":94},"traefik.http.services.traefik-metrics.loadbalancer.server.port=8082",[80,1794,482],{"class":167},[12,1796,1797,1798,1801],{},"Dashboard recomendado para Grafana: ID ",[39,1799,1800],{},"17346"," (Traefik Official).",[406,1803],{},[27,1805,1807],{"id":1806},"checklist-de-producción","Checklist de producción",[12,1809,1810],{},"Antes de exponer Traefik a internet, verifica:",[1812,1813,1814,1822,1829,1838,1841,1844,1847,1850],"ul",{},[1815,1816,1817,1818,1821],"li",{},"✅ ",[39,1819,1820],{},"exposedByDefault: false"," — solo contenedores con labels se exponen",[1815,1823,1824,1825,1828],{},"✅ Docker socket montado como ",[39,1826,1827],{},":ro"," (read-only)",[1815,1830,1817,1831,1834,1835],{},[39,1832,1833],{},"acme.json"," con permisos ",[39,1836,1837],{},"600",[1815,1839,1840],{},"✅ Dashboard protegido con autenticación",[1815,1842,1843],{},"✅ Headers de seguridad aplicados",[1815,1845,1846],{},"✅ Rate limiting en APIs públicas",[1815,1848,1849],{},"✅ Logs de acceso habilitados",[1815,1851,1852,1853],{},"✅ Base de datos y servicios internos en red separada de ",[39,1854,1476],{},[27,1856,1858],{"id":1857},"siguientes-pasos","Siguientes pasos",[12,1860,1861],{},"Con Traefik configurado, puedes expandir:",[1812,1863,1864,1871,1877,1886,1892],{},[1815,1865,1866,1870],{},[1867,1868,1869],"strong",{},"Canary deployments"," — enviar un porcentaje de tráfico a una nueva versión antes de cortar completamente",[1815,1872,1873,1876],{},[1867,1874,1875],{},"Circuit breaker"," — detener tráfico a un servicio que está fallando para que se recupere",[1815,1878,1879,1885],{},[1867,1880,1881],{},[16,1882,1884],{"href":1883},"/tecnologias/kubernetes","Kubernetes"," — Traefik funciona como Ingress Controller nativo para clusters K8s",[1815,1887,1888,1891],{},[1867,1889,1890],{},"Traefik + Authelia"," — single sign-on (SSO) para proteger múltiples aplicaciones con una sola autenticación",[1815,1893,1894,1900],{},[1867,1895,1896],{},[16,1897,1899],{"href":1898},"/servicios/infraestructura","Infraestructura Docker"," profesional — diseño de arquitectura, seguridad y monitoreo",[1902,1903],"call-to-action",{"description":1904,"eyebrow":1905,"icon":1906,"label":1907,"title":1908,"to":1909},"Diseñamos la arquitectura de contenedores con Traefik, Docker Compose, monitoreo y seguridad para tu operación.","Contenedores en producción","i-lucide-container","Solicitar evaluación","¿Necesitas una infraestructura Docker profesional?","/contacto",[1911,1912,1913],"style",{},"html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":41,"searchDepth":98,"depth":108,"links":1915},[1916,1917,1918,1919,1920,1921,1922,1923,1929,1930,1931],{"id":29,"depth":98,"text":30},{"id":47,"depth":98,"text":48},{"id":64,"depth":98,"text":65},{"id":143,"depth":98,"text":144},{"id":410,"depth":98,"text":411},{"id":851,"depth":98,"text":852},{"id":1043,"depth":98,"text":1044},{"id":1487,"depth":98,"text":1488,"children":1924},[1925,1926,1927,1928],{"id":1495,"depth":108,"text":1496},{"id":1578,"depth":108,"text":1579},{"id":1615,"depth":108,"text":1616},{"id":1652,"depth":108,"text":1653},{"id":1678,"depth":98,"text":1679},{"id":1806,"depth":98,"text":1807},{"id":1857,"depth":98,"text":1858},"tutorial",{"title":1934,"description":1935,"label":1907,"to":1909,"icon":1906},"¿Necesitas una infraestructura de contenedores profesional?","Diseñamos e implementamos tu arquitectura Docker con Traefik, SSL, monitoreo y alta disponibilidad.","2026-02-28","Guía paso a paso para instalar Traefik como reverse proxy con descubrimiento automático de contenedores Docker, SSL con Let's Encrypt y dashboard de monitoreo.",false,"md",[1941,1944,1947,1950],{"question":1942,"answer":1943},"¿Cuál es la diferencia entre Traefik y Nginx como reverse proxy?","Nginx es un reverse proxy estático — tú defines manualmente cada ruta en archivos de configuración. Traefik descubre automáticamente los contenedores Docker mediante labels y configura las rutas sin que toques ningún archivo. Cuando levantas un nuevo contenedor con las labels correctas, Traefik lo detecta, crea la ruta y obtiene el certificado SSL en segundos. Para infraestructura con Docker, Traefik reduce drásticamente el trabajo operativo.",{"question":1945,"answer":1946},"¿Traefik obtiene certificados SSL automáticamente?","Sí. Traefik integra el protocolo ACME de Let's Encrypt de forma nativa. Cuando detecta un nuevo dominio en las labels de un contenedor, solicita el certificado automáticamente y lo renueva antes de que expire. No necesitas instalar Certbot ni configurar nada adicional.",{"question":1948,"answer":1949},"¿Traefik funciona con Docker Compose?","Sí, perfectamente. Traefik se ejecuta como un contenedor más en tu docker-compose.yml y descubre los demás servicios mediante la API de Docker. Es la configuración más común y la que usamos en esta guía.",{"question":1951,"answer":1952},"¿Puedo usar Traefik sin Docker?","Sí. Traefik soporta múltiples proveedores de descubrimiento: Docker, Kubernetes, archivos estáticos, Consul, etcd y más. Pero donde realmente brilla es con contenedores, donde el descubrimiento automático elimina la configuración manual.","/images/blog/traefik-docker.jpg","Dashboard de Traefik mostrando rutas automáticas hacia múltiples contenedores Docker con SSL activo",{},"/blog/tutorial/traefik-reverse-proxy-docker",{"title":5,"description":1937},"blog/tutorial/traefik-reverse-proxy-docker",[1960,710,1961,1962,1963,1932],"traefik","reverse-proxy","ssl","devops","9HUJnBrvixzjQpg5fJBWmbjwAdGo89yZR5Py5JDsp0k",{"path":1966,"title":1967},"/blog/tutorial/nginx-reverse-proxy-ssl","Configurar Nginx como reverse proxy con SSL gratuito",{"path":1969,"title":1970},"/blog/tutorial/configurar-firewall-ufw-linux","Configurar firewall en Linux con UFW — reglas esenciales",[1972,1979,1984],{"path":1973,"title":1974,"description":1975,"date":1976,"category":1932,"image":1977,"imageAlt":1978,"readingTime":226},"/blog/tutorial/apis-rest-python-fastapi","Crear APIs REST con Python y FastAPI para integraciones empresariales","Guía paso a paso para construir una API REST profesional con Python y FastAPI que conecte tu ERP, CRM o cualquier sistema con validación, autenticación y documentación automática.","2026-03-04","/images/blog/fastapi-api-rest.jpg","Editor de código mostrando una API FastAPI con documentación Swagger generada automáticamente",{"path":1969,"title":1970,"description":1980,"date":1981,"category":1932,"image":1982,"imageAlt":1983,"readingTime":202},"Guía paso a paso para configurar UFW (Uncomplicated Firewall) en Ubuntu y Debian con las reglas esenciales para proteger servidores de producción.","2026-03-01","/images/blog/ufw-firewall-linux.jpg","Terminal de Linux mostrando reglas de firewall UFW activas protegiendo un servidor de producción",{"path":1966,"title":1967,"description":1985,"date":1986,"category":1932,"image":1987,"imageAlt":1988,"readingTime":208},"Guía paso a paso para configurar Nginx como proxy inverso con certificados SSL de Let's Encrypt para exponer aplicaciones web de forma segura en producción.","2026-02-25","/images/blog/nginx-reverse-proxy.jpg","Diagrama de arquitectura mostrando Nginx como reverse proxy con SSL frente a múltiples aplicaciones backend"]