배너 이미지

캐시 서버 구축하기

최종 수정일 : (1년 전)

Github

라엘 님의 이미지 캐시 서버 구축하기 (나만의 CloudFlare 구축하기)를 참고하여 제작했습니다.
Apache를 사용하시거나, WebP로 파일 전환이 필요 없으시면, 원본 글을 참고하시면 됩니다.

서버 선택

아마존 라이트세일 가격

라엘 님께서 캐시 서버에 중요한 것은 해외망과 디스크 용량이라 하셨습니다.
실제로 사용해보니 WebP로 변환하는 것까지도 CPU와 RAM이 그렇게 크게 필요하진 않았고, 어차피 자주 접근하는 파일은 한 번 변환되면 캐시 서버에 지워지지 않고 남아있을 거라 더욱 중요치 않아 보이더라고요.

Amazon Lightsail에서 5달러짜리 상품이나 10달러짜리 상품이면 충분합니다.

도메인 정하기

저는 img.marshallku.com을 사용하다, i1.marshallku.com으로 변경했습니다.
혹시 서버 변경하며 주소를 바꿀 일이 있을까 싶어 1을 붙였는데, 글 적으며 생각해보니 그냥 i.marshallku.com이 제일 나았을 것 같기도 하네요.

외에도 cdn, c 등이 있으니 편한대로 고르시면 됩니다.

서버 세팅

sudo apt update

항상 세팅 시작 전엔 업데이트할 게 있나 확인부터 해주세요.

Nginx

sudo apt install nginx

WebP로 변환하는 건 PHP만 변경하시면 되는 거라, Apache를 사용하려면 상술한 라엘 님의 포스트를 참고하셔서 세팅하셔도 무관합니다.

PHP

아래엔 외부 저장소를 이용해 최신 버전의 PHP를 설치하는 방법을 작성했으나, Ubuntu의 저장소를 이용하셔서 PHP를 설치하셔도 무관합니다.
또한, 버전도 8.0보다 아래인 7.x 등에서도 잘 작동합니다.

sudo apt -y install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt install -y php7.4-{gd,cli,fpm,opcache,curl}

인증서 발급하기

우분투에 워드프레스 설치하기에서 'Let's Encrypt 인증서 발급' 부분을 참고하셔서 작업해주세요.

캐시 서버 설치

Nginx 설정

nginx.conf 파일 확인

sudo vim /etc/nginx/sites-available/example.com

vim, nano 등 편한 텍스트 편집기로 /etc/nginx/sites-available 폴더에 도메인 명으로 파일을 생성해주세요.
굳이 도메인 명이 아니라도 큰 상관이 없긴 합니다.

상술한 nginx.conf 파일의 내용을 붙여 넣으신 뒤, 네 개의 example.com을 본인 도메인으로 변경해주세요.
혹시 dhparam.pem 파일을 생성하지 않으셨으면

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

명령어를 입력하셔서 생성해주세요.

PHP 버전이 8.0이 아니시라면 76번째 줄의 unix:/run/php/php8.0-fpm.sock도 본인 버전에 맞게 수정해주셔야 합니다.

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

sites-available 폴더에서 sites-enabled 폴더로 파일을 링크해줍니다.

sudo nginx -t

위 명령어로 nginx 설정 파일에 문제가 없는지 확인하실 수 있습니다.

웹 루트 폴더에 파일 추가

웹 루트 폴더 확인

웹 루트 폴더(예제에선 /home/cdn/www)에 상술한 링크에 있는 파일들을 추가해주시면 됩니다.

index.php의 129번째 줄에 example.com이 있으니 그것만 본인 도메인으로 수정해주세요.

Nginx, PHP-fpm 재시작

sudo systemctl nginx restart
sudo systemctl php8.0-fpm restart

캐싱할 파일 변경하기

index.php의 132번째 줄, nginx.conf의 45번째 줄을 수정하시면 됩니다.
기본적으론 png, jpg, jpeg, gif, webp, mp4, webm, svg 파일의 요청이 들어왔을 때만 저장하도록 해뒀습니다.

Crontab 설정

sudo crontab -e

오래된 파일 삭제를 위해 Crontab으로 반복 명령을 설정합니다.
매일 정해진 시간에 해당 명령어를 반복해줍니다.

00 4 * * * /usr/bin/find /home/cdn/www -mindepth 2 -atime +5 -type f \( -iname \*.png -o -iname \*.jpg -o -iname \*.jpeg -o -iname \*.gif -o -iname \*.webp -o -iname \*.mp4 -o -iname \*.webm -o -iname \*.svg \) | xargs rm 1>/dev/null 2>/dev/null

-atime +5 : 마지막으로 접근한 게 5일이 넘은 파일을 삭제하는 옵션입니다. 적절하게 조절해주시면 됩니다.

05 4 * * * sudo systemctl restart nginx

매일 재시작 하실 필요까진 없지만, 적당한 주기론 재시작 해주셔야 인증서가 갱신됩니다.

웹사이트의 이미지 링크 수정

웹사이트의 이미지 링크를 이미지 캐시 서버의 주소로 변경하고(예: marshallku.com/images/tmp.png => img.marshallku.com/images/tmp.png), WebP 파일로 변환하려면 이미지 마지막에 .webp를 추가하시면 됩니다(예: img.marshallku.com/images/tmp.png => img.marshallku.com/images/tmp.png.webp).

function imgToPicture($content)
{
preg_match_all('/<img(.+?)(src=\"(.+?)\")(.+?)(srcset="(.+?)")? ?\/?>/', $content, $matches);
$i = 0;
foreach ($matches[0] as &$image) {
// Replace domain to cache server domain
// Replaces https://example.com/img.png to https://img.example.com/img.png
$src = str_replace('//example', '//img.example', $matches[3][$i]);
$srcset = $matches[6][$i] ?? '';
$srcset = $srcset != '' ? preg_replace('/\/\/example/', '//img.example', $srcset) : '';

$webpSrcset = $srcset != '' ? preg_replace('/\.(png|jpe?g)/', '.$1.webp', $srcset) : '';

$tmp = "<picture><source type=\"image/webp\" srcset=\"{$src}.webp 1x,{$webpSrcset}\"></source><source srcset=\"{$src} 1x,{$srcset}\"></source><img{$matches[1][$i]}src=\"{$src}\"{$matches[4][$i]}srcset=\"{$srcset}\"></picture>";

$content = str_replace($image, $tmp, $content);
$i++;
}
return $content;
}

add_filter('the_content', 'imgToPicture');

위 코드는 제 워드프레스 테마에 사용한 코드를 살짝 정리한 겁니다.
참고하시면 img 태그를 WebP 링크가 포함된 picture 태그로 변경하실 수 있습니다.

정규표현식에 능하지 못해 코드가 좀 아름답지 않은데, 아무리 봐도 srcset 안의 모든 png, jpeg, jpg를 모두 png.webp, jpeg.webp, jpg.webp로 수정하는 게 정규표현식 하나론 힘들어 보이더라고요. 혹시 좀 더 깔끔하고 아름다운 정규표현식이 있다면 알려주시면 감사하겠습니다.

작동 확인

응답 헤더 확인

개발자 도구의 네트워크 탭에서 이미지를 선택하시면 요청 / 응답 헤더를 확인하실 수 있습니다.
주소가 캐시 서버의 주소로 잘 변경되었는지, 두 번 이상 요청했을 땐 My-Cache-Status 헤더가 HIT인지 확인해주세요.

tail -f /var/log/nginx/access.log

위 명령어를 이용하시면 Ctrl + C로 작동을 취소시킬 때까지 로그를 실시간으로 확인하실 수 있습니다.


profile

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

주의 : 비밀 댓글 사용 시 수정 기능을 이용할 수 있는 시간이 지나면 작성자도 내용 확인이 불가능합니다.