{"id":"IL-0356","org":"Railway","date":"2026-09-30","docs":[],"title":{"en":"Every domain hosted on Railway returned HTTP 404 to new connections for five minutes because route lookups failed","ko":"Railway 에 호스팅된 모든 도메인으로 오는 새 연결이 5분 동안 HTTP 404 를 받았다"},"domain":["networking"],"impact":{"scope":"New connections to all domains hosted on Railway, custom and *.up.railway.app, returned HTTP 404; public access and some private networking lookups between services failed; existing connections and running workloads were not affected","users":"all customers","region":"all regions"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":null,"related":[],"sources":[{"url":"https://blog.railway.com/p/incident-report-sept-30-2026-routing-disruption","kind":"blog","archived":"https://web.archive.org/web/20261103025318/https://blog.railway.com/p/incident-report-sept-30-2026-routing-disruption"}],"summary":{"en":"Railway's distributed routing control plane tells its origin proxies where to send requests for each domain. It had recently been split out of a monolith so that it would keep running through a major cloud outage, and it runs in many places with rollout pipelines that run in parallel. A new authentication layer that lets customers put a login in front of their services needed a changed data type in the database table that stores routing data and a new routing service version that reads the new format. The schema update runs as a migration job in one system and the routing service is built and deployed by another. In the monolith a single pipeline had enforced the order; after the split, a configuration error let the migration and the deployment run in parallel, a race that shows most with larger migrations.\n\nOn 30 September 2026 the routing service build won the race. As it rolled out in every region it queried columns that did not exist yet, and every route lookup returned an error. The change also touched the domain fallback behaviour, so the origin proxies could not fall back to the last known route and returned 404 for every new connection to every domain, and private network DNS lookups failed too. At about 07:40 the CI system finished the schema update, the routing service's retried lookups returned 200, and domains routed normally again. Engineers found the cause at 07:44, confirmed full recovery at 07:47 without a rollback, posted a public incident at 07:48 and marked it resolved at 08:17. Railway states that no data was lost.","ko":"Railway 의 분산 라우팅 제어 플레인은 오리진 프록시에 도메인마다 그 뒤의 워크로드로 사용자 요청을 어떻게 보낼지 알려 주는 시스템이다. Railway 는 큰 클라우드 장애에도 버티도록 최근 이 제어 플레인을 모놀리스에서 떼어 내 전 세계에서 운영했고, 배포 파이프라인도 병렬로 돌렸다. 모놀리스 시절에는 파이프라인 하나가 스키마 변경과 서비스 배포의 순서를 지켰다. 분리한 뒤에는 둘이 서로 다른 파이프라인으로 배포됐고, 파이프라인 설정의 오류로 스키마 마이그레이션까지 병렬로 돌 수 있었다.\n\nRailway 는 고객이 서비스 앞에 로그인을 둘 수 있게 하는 인증 계층을 만들고 있었다. 이 기능에는 라우팅 데이터를 담는 데이터베이스의 데이터 타입을 바꾸는 스키마 변경과, 새 테이블 형식을 읽는 라우팅 서비스 새 버전이 함께 필요했다. 엔지니어는 2026-09-30 07:29 UTC 에 스테이징에서 시험한 이 변경을 병합했다. 07:35 무렵 새 라우팅 서비스가 마이그레이션보다 먼저 모든 리전에 배포됐고, 아직 없는 컬럼을 조회하면서 모든 경로 조회가 오류를 냈다. 이 변경은 조회가 실패했을 때 도메인이 마지막 경로로 되돌아가는 대체 동작도 바꿨다. 그래서 오리진 프록시는 조회 실패를 경로가 없는 도메인처럼 다뤄 404 를 냈고, 그 도메인의 마지막 경로로 되돌아가지 못했다. 모든 도메인의 새 연결이 오류를 받았고, 라우팅 서비스가 맡은 사설 네트워크 DNS 조회 일부도 실패했다.\n\n07:40 무렵 CI 시스템이 스키마 변경을 적용했고, 라우팅 서비스의 다음 재시도가 성공해 라우팅이 돌아왔다. 07:44 에 엔지니어들이 원인을 찾았고 07:47 에 완전 복구를 확인했다. 롤백은 필요하지 않았다. Railway 는 07:48 에 상태 페이지에 공개 사고를 올렸고 08:17 에 해결로 표시했다. 데이터 손실은 없었다."},"trigger":{"en":"At 07:29 UTC an engineer merged a change to the routing control plane that contained a database schema update and a new version of the routing service. At about 07:35 the deployment system rolled the new routing service out to every region before the schema update had been applied.","ko":"07:29 에 병합된 라우팅 제어 플레인 변경을 배포할 때, 파이프라인 설정의 오류로 스키마 변경 파이프라인과 새 라우팅 서비스 배포 파이프라인이 동시에 돌았다. 두 파이프라인이 경쟁하다가 새 라우팅 서비스가 스키마 변경보다 먼저 모든 리전에 올라왔다."},"severity":"unknown","symptoms":["service-unavailable","dns-resolution-failures"],"timeline":{"detected_after":"0m","resolved_after":"5m"},"date_kind":"incident","detection":{"en":"Internal alerting engaged the on-call response team as soon as route lookups began to fail at about 07:35 UTC.","ko":"경로 조회가 실패하기 시작하자 곧바로 내부 알림이 울려 당직 대응팀이 소집됐다."},"components":["network-control-plane","database","ci-system"],"root_cause":"deploy-rollout","remediation":[{"text":{"en":"Let the CI system finish the schema update, after which the routing service's retried lookups succeeded and routing recovered without a rollback","ko":"CI 시스템이 스키마 변경을 적용했고, 라우팅 서비스가 조회를 재시도하면서 도메인 라우팅이 곧바로 정상으로 돌아왔다."}}],"action_items":[{"text":{"en":"Force the migration rollout to run in serial order and unify the deployment pipeline so deploy order and blast radius are checked before merge","ko":"배포 파이프라인을 하나로 합쳐 마이그레이션 롤아웃이 차례대로 돌게 하고, 병합 전에 배포 순서와 피해 범위를 검사한다."}},{"text":{"en":"Block the routing service's blue/green rollout until the database schema matching its version is in place","ko":"블루/그린 롤아웃에서 바이너리마다 작성 당시의 스키마 버전을 검증하고, 맞는 데이터베이스 스키마가 갖춰질 때까지 서비스가 운영에 올라가지 않게 한다."}},{"text":{"en":"Add shard based rollouts per region to the distributed control plane to isolate impact","ko":"새 구성 요소인 분산 제어 플레인에 리전별 샤드 단위 롤아웃을 더해 앞으로는 피해를 샤드 안에 가둔다."}}],"contributing":["unsafe-failure-mode","no-staged-rollout","blast-radius-too-wide"],"recurrence_of":null,"symptoms_text":{"en":"On 30 September 2026, between about 07:35 and 07:40 UTC, new connections to every domain hosted on Railway, both custom domains and *.up.railway.app domains, got HTTP 404 in all regions. Internal alerting paged the on-call team as soon as route lookups started to fail.\n\nThe 404 came from Railway's origin proxies. For each request, an origin proxy asks the routing service which workloads serve the domain. The routing service's lookups were failing, and the origin proxies answered a failed lookup the same way as a domain with no routes, with a 404, instead of using the last route they had seen for the domain. Private networking lookups between services also failed in the same window, because the same routing service resolves private network DNS.\n\nConnections that were already open kept working, and the workloads behind the domains kept running; only new visits failed. Routing came back on its own about five minutes later, when the routing service's retried lookups started to succeed, and engineers confirmed full recovery at 07:47 without a rollback.","ko":"2026-09-30 07:35 UTC 무렵부터 Railway 에 호스팅된 모든 도메인이 새 연결에 HTTP 404 not found 를 냈다. 경로 조회가 실패하기 시작하자 곧바로 내부 알림이 울려 당직 대응팀이 소집됐다.\n\n오류는 커스텀 도메인과 *.up.railway.app 도메인에서 모든 리전에 걸쳐 났다. 이미 맺어진 연결은 끊기지 않았고 사용자 워크로드도 계속 돌았다. 스키마가 맞지 않는 동안 사용자 페이지를 새로 방문하면 오류를 받았다.\n\n라우팅 서비스는 사설 네트워크 DNS 도 맡고 있어서, 같은 시간 동안 서비스 사이의 사설 네트워킹 조회 일부도 실패했다.\n\n라우팅 서비스는 아직 없는 컬럼을 조회했고 모든 경로 조회가 오류로 끝났다. 오리진 프록시는 조회 실패를 경로가 없는 도메인과 똑같이 다뤄 404 를 냈고, 그 도메인에서 마지막으로 본 경로로 되돌아가지 않았다.\n\n07:40 무렵 스키마 변경이 적용되자 라우팅 서비스의 다음 재시도가 성공했고 도메인 라우팅이 곧바로 정상으로 돌아왔다. 엔지니어들은 07:44 에 원인을 찾았다. 원인은 새 라우팅 서비스가 자기가 의존하는 스키마 변경보다 먼저 올라온 데 있었다."},"updated_at":"2026-11-14T12:34:01.003438Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0356","org_slug":"railway"}