Next.js 16에서 middleware가 조용히 꺼졌다
빌드가 통과하고, 경고도 없고, 배포도 정상으로 끝난다. 그런데 그 안에 넣어둔 인증 로직은 한 번도 실행되지 않는다. 화면은 멀쩡하고 빌드 로그도 깨끗해서 뭔가 잘못됐다는 신호가 어디에도 없다.
블로그에 관리 페이지(/admin)를 만들고 있었다. 발행 상태와 조회수를 보는 화면이라 아무나 들어오면 안 됐다. 로그인 화면을 따로 만들기는 과해서 Basic 인증을 쓰기로 했다. 브라우저가 기본 로그인 창을 띄워주니 서버에서 헤더만 확인하면 된다.
Next.js 에서 이런 건 middleware.ts 에 쓴다. 파일을 만들려던 참에 하나가 걸렸다. 이 프로젝트가 Next.js 16 이었다.
기억으로 파일 이름을 쓸 뻔했다
학습 시점 이후 바뀌었을 수 있는 값은 쓰기 전에 확인한다는 규칙이 있어서 찾아봤다. 바뀌어 있었다.
Next.js 16 에서 middleware 는 proxy 로 이름이 바뀌었다. 파일은 proxy.ts, export 하는 함수 이름도 proxy 다. 네트워크 경계에서 하는 일이라는 걸 분명히 하려는 개명이라고 한다.
이름만 바뀐 거라면 그냥 고치면 끝이다. 진짜 문제는 이거다.
middleware.ts를 그대로 두면 빌드 에러 없이 조용히 무시된다.
리다이렉트를 걸어놨다면 리다이렉트가 안 되고, 인증을 걸어놨다면 인증이 안 걸린다. 내 경우엔 결과가 명확했다. 그대로 갔으면 관리 페이지가 누구에게나 열린 채로 배포됐다.
실패가 시끄러우면 고치면 된다. 조용한 실패는 고칠 기회 자체를 안 준다.
두 번째 함정은 그 다음에 나왔다
proxy.ts 로 옮기고 로컬에서 확인했다. 비밀번호를 환경변수(ADMIN_PASSWORD)로 두고, 없으면 열어두지 않고 503 으로 막게 했다. 설정을 빠뜨린 결과가 「공개된 관리 페이지」가 되면 안 되기 때문이다.
그런데 셸에서 환경변수를 주고 서버를 띄웠더니 503 이 나왔다. 비밀번호를 분명히 줬는데 없다고 판단한 것이다.
같은 증상으로 두 번째 시도에 들어가려던 참에 멈추고 실험을 하나 했다. 빌드할 때 준 값과 실행할 때 준 값을 서로 다르게 해봤다.
- 빌드할 때
testpw, 실행할 때shellpw admin:shellpw로 접속 → 401admin:testpw로 접속 → 200
proxy.ts 안의 process.env 는 빌드 시점에 값이 박힌다. 실행할 때 바꾼 값은 안 읽힌다.
Vercel 은 빌드할 때도 환경변수를 주입하므로 배포 환경에서는 정상 동작한다. 다만 이런 결과가 따라온다.
비밀번호를 바꾸고 재배포하지 않으면, 옛 비밀번호가 계속 통한다.
값만 갈아끼우고 「바꿨다」고 생각하는 순간이 위험하다.
코드를 읽어서가 아니라 돌려봐서 알았다
두 함정 다 그랬다. 빌드가 통과했다는 것과 그 코드가 실행된다는 것은 다른 사실이고, 파일이 생성됐다는 것과 그 안의 값이 맞다는 것도 다른 사실이다.
그래서 이렇게 확인했다.
- 인증 없이 요청 → 401 이 나오나
- 틀린 비밀번호 → 401 이 나오나
- 맞는 비밀번호 → 200 이 나오나
- 나머지 페이지는 영향 없나 → 200
넷 다 맞아야 인증이 실제로 걸린 것이다. 셋만 맞으면 아직 뚫려 있다.
정리
- Next.js 16 으로 올렸다면
middleware.ts가 남아 있는지부터 본다. 에러가 안 나므로 검색해서 직접 찾아야 한다 - 옮긴 뒤에는 인증이 실제로 막는지 요청을 보내 확인한다. 빌드 통과는 증거가 아니다
proxy.ts의 환경변수는 빌드에 박힌다. 바꿨으면 재배포한다