WordPress Undefined array key “host” in /wp-includes/canonical.php 문제 해결하기

nginx 1.26 업데이트 뉴스

nginx 안정 버전이 4월 23일에 1.26으로 올라오면서 드디어 공식적으로 http3를 지원하기 시작했습니다. 그래서 서버에 적용을 했는데 이전에 메인라인 버전으로 적용했을 때처럼 PHP Warning 로그가 엄청나게 기록되길래 이번엔 에러의 원인에 대해 고민해 보기로 했습니다.

Undefined array key “host” in /wp-includes/canonical.php on line 716
Undefined array key “host” in /wp-includes/canonical.php on line 727
Undefined array key “host” in /wp-includes/canonical.php on line 730
Undefined array key “scheme” in /wp-includes/canonical.php on line 751

에러 로그파일에 남는 PHP Warning 들
/wp-includes/canonical.php 에서 에러나는 부분
/wp-includes/canonical.php

로그를 보면 canonical.php 파일 내부에서 original, redirect 에 해당 키들이 정의되지 않았다고 하는데 저 original, redirect가 어디서 선언되는지 확인을 해보니

문제의 변수가 선언되는곳
/wp-includes/canonical.php

redirect_canonical() 함수 초반부에 선언이 되고 있었고 여기서 문제가 시작합니다.

일단 75라인 위치에서 requested_url 값을 확인해 보니 string 타입 빈 문자열로 들어오는 걸 확인했습니다. 그리고 빈 문자열이 parse_url 함수를 거치면 original 변수에 false 값을 가질 거라 생각했지만…

{
	path => ""
}

위와 같은 array가 리턴됩니다. 그래서 716, 727, 730 라인에서 PHP Warning이 발생했던 거고 그 array를 그대로 복사해서 사용한 redirect 변수도 751 라인에서 PHP Warning이 발생한 것입니다.

근데 이 문제는 바로 윗줄에 있는 68라인 함수에서 발생하지 않게 해주는 건데 처음에 이걸 못 보고 한참 삽질을 했습니다. (68라인은 requested_url 값이 비어있으면 _SERVER 값을 참고해서 url을 생성하는데 HTTP_HOST 값이 존재하지 않아서 저 부분을 비껴나간 것입니다)

그래서 해결법은…

두 가지 방법이 있습니다. 하나는 PHP로 해결하는 거고 다른 하나는 nginx 설정을 변경하는 것입니다. (이 방법은 워드프레스 단일 사이트는 테스트 해봤지만 멀티사이트는 안해봐서 안될수도 있습니다)

1. PHP로 코드 삽

if(!isset($_SERVER['HTTP_HOST'])) {
	$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'];
}

테마 functions.php 파일에 위 코드를 넣어줍니다. 위 코드는 HTTP_HOST가 없으면 SERVER_NAME 값을 넣어서 해결하는 간단한 방법입니다.

단점이라면 페이지가 호출될 때마다 체크를 하고 변수 복제를 한다는 점이죠.

2. nginx 설정을 변경하기

fastcgi_param  HTTP_HOST        $server_name;

nginx 설정 파일에 위 한 줄을 추가해 주고 서버 재시작을 해주면 됩니다. 그러면 잘 작동하는 걸 확인할 수 있습니다.

그런데 말입니다…

SERVER_NAME과 HTTP_HOST에 차이가 있습니다.

근본적인 차이는 SERVER_NAME은 서버에 설정되어 있는 값을 가져오는것이고 HTTP_HOST는 클라이언트가 요청한 값에서 가져온다는 점입니다.

입력 : https://www.lineoo.pe.kr
HTTP_HOST = www.lineoo.pe.kr
SERVER_NAME = lineoo.pe.kr

입력 : https://1.2.3.4
HTTP_HOST = 1.2.3.4
SERVER_NAME = lineoo.pe.kr

입력 : https://1.2.3.4:8080
HTTP_HOST = 1.2.3.4:8080
SERVER_NAME = lineoo.pe.kr

그래서 좀 더 정확히 할려면

fastcgi_param  HTTP_HOST        $host;

위와 같이 설정에 입력해줘야 하고, 만약 80, 443 포트가 아닌 다른 포트를 사용한다면

fastcgi_param  HTTP_HOST        $host:$server_port;

이렇게 변경해야 http2랑 동일한 결과를 볼 수 있습니다.

그럼 처음부터 $host 를 쓰는걸 설명하지 굳이 $server_name으로 설명한 이유는 $host 를 사용하는게 보안에 취약할 수 있다 라는 논쟁이 있기 때문입니다.

개인적으로도 클라이언트가 입력한 값을 그대로 쓰는건 안전하다고 생각을 하지 않기 때문에 저는 server_name을 사용합니다.


Comments

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다