20210713 TIL
NGINX
Apache는 서버사이드언어가 있어서 그 안에서 프로세싱하는 방법이지만 nginx는 서버사이드언어가 없고 프록시서버로서 작동하지만 일반적인 static file을 다룰때는 서버 역활도 하는 그런 방법으로 고안되었다. 때문에 아파치보다는 훨씬 빠르고 동시성이 원활하게 이루어진다(1개 프로세스당 수천개의 연결이 가능).
아이피는 동일한테 서버가 바뀌어서 에러메시지가 뜰 경우
ssh-keygen -R 167.99.93.26
해주면 yes 해서 저장했던거 삭제되었음.
ubuntu에서는 apt-get으로 인스톨이 되는데 naive CentOS는 안되서 yum install epel-release 해주고 나서 yum install nginx 해줘야 깔림. 우분투에서는 apt-get으로 설치하면 자동으로 깔은거 데몬으로 돌아갈꺼 돌려주는데 CentOS는 안그래서 시작해줘야함. (ps -ef | grep nginx 또는 ps aux | grep nignx)
바이너리 소스 다운 받아서 까는 부분이 있는데 ... 몇년 안에도 안쓸거 같아서 정리 안함.
nginx의 시스템 서비스
systemd 서비스로 nginx를 추가(systemd는 ubuntu 15.0.4, centos7.0.0 이상만 가능)하게 되면 nginx를 표준화된 방식으로 재부팅되어도 다시뜨는 등등등..의 기능을 사용할 수 있다. (이거 systemctl에 필요한 내용을 파일에 적어서 나중에 재부팅되었을때 systemctl이 알아서 뜨게끔 해주는 것. systemd나 systemctl이나 같은 맥락이었네)
Configuration
conf에서는 2가지의 주 용어가 있는데, 하나는 context와 directive이다. directive는 conf 파일에 키-밸류로 명시되어 있는 값을 말하고 context는 하나의 블록을 묶어주는 그 단위를 말한다.
보통 conf 파일 안에 싹 지우고 http 블록부터 시작하는데 events 블록은 이벤트의 컨택스트를 유지하기 위해서 남기는 것을 권장한다.
서버 블록은 virtual host라고 불리우는 WAS 또는 기능을 하는 서버를 말한다. V host 라고 부르더라.
listen은 없으면 80 port를 기본으로 하고 있는데 명시해주는 것이 좋다.
서버 네임에 아이피 어드레스를 넣어도 된다. 서버네임에 *.naver.com 처럼 별표를 달아주면 별표에 아무거나 와도 되는 와일드카드이다.
root는 파일들을 찾을 수 있는 기본 주소를 명시해놓음. /image/cat.png 라고 conf에 명시해놓으면 거기에 root에 명시한 주소를 붙여서 /root/path/images/cat.png 로 인식한다.(저 주소는 실제 파일 시스템 주소인거임)
conf 파일을 수정하고 나서 systemctl restart nginx로 해도 되지만 에러가 생기면 정상적이었던 서버가 작동을 멈추게 되고 downtime이 발생한다. 때문에 restart 하기 전에 nginx -t를 해주면 conf 파일에 문제가 없는지 syntax 검사를 해준다. 그 후에 reload를 해준다. systemctl로 해도 되고 nginx -s reload 해도 되고.
nginx에서 static file을 제공할때 파일 타입을 지정해줄 수 있음. types 블록을 http 블록 안에 명시하고 그 안에 key value 형태로 넣어주면된다. text/css css; text/html html; 등과 같이. 근데 언제 이걸 일일이 다 치고 잇냐? 그렇기 때문에 미리 적어둔 /etc/nginx/mime.types 라는 파일이 존재한다. 이제 types 블록을 지우고(다른 정보가 필요하면 기입해도 되나?) 기본 타입들의 정보를 불러오기 위해 include mime.types; 를 적어주면 된다.
location을 이용하여 uri에 적힌 특정 요청을 인터셉트 할 수 있다.
# Prefix match
location /greet {
return 200 'HI!!';
}
# Exact match
location = /greet {
return 200 'This is perfect match';
}
# REGEX match
location ~ /greet[0-9] {
return 200 'This is regex match';
}
# REGEX match - non case sensitive
location ~* /greet[0-9] {
return 200 'This is regex match - non case sense';
}
location 블록 안에 return [응답코드] [내용]을 작성하여 바로 응답할 수도 있음. ( return 200 'hi welcome'; ) 근데 문제는 /greet라고 작성했다고 가정했을때, /greet이나 /greeting이나 /greeting/good/ 이나 모두 intercept 당해버림. 정확하게 매칭하려면 = 기호를 사용해야함. 그거보다 더 정확하게 정규표현식을 이용해서 구분하려면 ~ 기호(틸다)를 사용하면 된다. 근데 알다시피 정규표현식을 사용하면 대소문자가 다른 의미인데 uri 세계에서는 그딴거 없거덩. 그래서 uri에 대문자로 막 치고 들어가기도 한단 말야. 그런걸 하기 위해서는 ~* 기호를 써야한다. 만약 기본 모드랑 정규표현식 모드랑 겹치게 된다면? 그럼 정규표현식을 따라 감. 근데 기본 모드가 먼저 이고 싶을때가 있잖아? 그러면 ^~ 기호를 사용하면 된다. 그것에 대한 우선순위는 다음과 같다.
- Exact Match ( = )
- Preferential Prefix Match ( ^~ )
- REGEX Match ( ~* )
- Prefix Match (기본)
Conf에 작성할 수 있는 변수
Configuration Variables
set $var 'something';
NGINX Module Variables
$http, $uri, $args
nginx 변수는 nginx.org/en/docs에 alphabetical index of variables에 잘 나와 있음.
괄호 안에 그 변수를 사용하는 모듈에 대한 이름이 적혀있다.
location /inspect {
return 200 "$host\\n$uri\\n$args"; # 쌍따옴표를 써야함.
}
# 167.99.93.26/inspect?name=ray
# 167.99.93.26
# /inpect
# name=ray
location /inspect {
return 200 "$arg_name";
}
# 167.99.93.26/inspect?name=ray
# name: ray
호스트와 주소 그리고 uri에 담긴 (? 기호 뒤에 붙은) 인자를 출력해준다.
nginx는 if 문을 지원한다.
if ( $arg_apikey != 1234 ) {
return 401 "Incorrect API Key";
}
내부에서 custom 변수 선언해서 쓰기
set $weekend 'ohNo';
if ( $date_local ~ 'Saturday|Sunday' ) {
set $weekend 'ohYes';
}
location /is_weekend {
return 200 $weekend;
}
$date_local을 하게 되면 nginx가 떠있는 서버의 시간을 ISO 날짜시간 표준 표현 방식으로 가져 올 수 있다.
if 문에서 조건을 걸때 ~를 사용하게 되면 포함하는가 에 대한 기호이고 문자열 중간에 있는 파이프 ( | ) 는 or라는 의미임.
ISO datetime string
Monday, 16-Apr-2020 22:15:04 Pacific Daylight Time
이런 방식으로 redirects를 할 수 있다.
Redirect
rewrite과 return을 이용해서 리다이렉트 할 수 있음.
return 300번대(리다이렉트) 값(스트링)
location /imagefile {
return 307 /logo.png;
}
# [IPaddr]/imagefile
# 그림파일 나옴.
# URL 주소는 /logo.png 로 바뀌어 있음.
logo 라는 주소로 들어가면 logo.png 라는 주소로 리다이렉트하지만 주소입력창에 보면 우리가 입력한 주소가 아닌 우리가 리다이렉트한 주소로 들어가게 된다. rewrite으로 리다이렉트하면 우리가 입력한 주소로 표시되게 된다. 즉, 받은 주소를 다른 주소로 바로 연결하느냐 아니면 그 주소를 nginx 내부에서 알아서 그 주소지만 다른데로 연결하게끔 해주느냐 차이이다.
rewrite ^/user/\\w+ /greet;
location /greet {
return 200 "hihi user";
}
# [IPaddr]/user/john
# hihi user
# URL 주소는 입력한 대로 고대로 남아있음.
# rewrite으로 /user/john은 /greet으로 변경되었고 그건 nginx internally only 이다.
# 만약 /user/뒤에 붙은 내용을 가져가고 싶다면, 아래와 같이 구성하면 된다.
rewrite ^/user/(\\w+) /greet/$1; # 첫번째 괄호의 내용이 $1에 할당된다. 두번째 괄호는 $2
location /greet {
return 200 "hihi user"; # /user/jane이라면 여기에 걸리고
}
location = /greet/john {
return 200 "hihi john!!"; # /user/john이라면 여기에 걸리고
}
여러번 rewrite을 명시하여 여러번 바꿀 수 있다.
rewrite ^/user/(\\w+) /greet/$1;
rewrite ^/great/john /logo.png;
# /user/john -> /logo.png
# 이렇게 여러번 바꾸는거 말고 원하는 거 만큼만 바꾸고 싶다면 원하는 rewrite 위치에 last를 써준다.
rewrite ^/user/(\\w+) /greet/$1 last;
rewrite ^/great/john /logo.png;
# /user/john -> /greet/john
^ : start with
\w+ : more than one word character with the second arg.
rewrite을 선언하면 /user/john이라는 주소로 요청이 오면 그 주소를 /greet라고 내부적으로 변경(인식)하고 re-evaluation을 시작한다. 이 re-evaluation은 rewrite를 더욱 강력크하게 만들지만 리소스를 잡아먹는다는 사실을 잊지 말길 바란다.
try_files & named location
try_files /logo.png /greet;
# root 디렉토리에 logo.png 라는 파일이 있으면 /greet로 바꿔준다.
# 어떤 uri가 들어오더라도 바꿔준다.
try_files $uri /not_exist_file.txt /greet;
location /greet {
return 200 "hello";
}
# uri로 통해서 들어오는 주소가 root 디렉토리 안에 있는 파일에 합당하면 그 파일을 돌려주고
# 아니라면 다음 인자로 넘어가고
# 여기서는 두번째 인자도 없으므로 /greet 로 바뀌어서(rewrite) re-evaluation한다.
try_files $uri /not_exist_file.txt /greet /ohmygod_404;
location /ohmygod_404 {
return 404 "oh no! 404 not found!";
}
location /greet {
return 200 "hello";
}
# [IPaddr]/nothing
# $uri에 해당하는 파일이 없어서 두번째 인자로 넘어가고 그것도 없어서
# [rootPath]/greet 라는 파일이 없어서 그 다음으로 넘어가서 uri가 /ohmygod_404로
# rewrite되어 re-evaluation이 된다.
# 중요한건 아무것도 루트폴더에 없을때 맨 마지막 인자로 rewrite 된다는 사실을 기억해야한다.
try_files $uri /not_exist_file.txt /greet @ohmygod_404;
location @ohmygod_404 {
return 404 "oh no! 404 not found!";
}
location /greet {
return 200 "hello";
}
# 마지막으로 named location이라는 것이 있는데
# 첫 인자부터 루트 폴더에 파일이 있는지 쭈욱 검사하고 없으면 마지막 인자로 rewrite되는게
# 일반적인 try_files의 역할인데
# rewrite이 아니라 특정한 location에 바로 연결해주는 것이다.
# 즉, named location(@ 기호로)은 re-evaluation을 하지 않는 것을 보장한다.
logging
nginx에서는 2가지 타입의 로그를 남긴다.
error.log 와 access.log 이다.
보통의 일반적인 웹 서버는 로그를 남기는 것이 당연하다. 하지만 특정한 파일들에 대해 특별한 로그 규칙을 지정한다든지 어떠한 상황에서는 로그를 남기지 않도록 하게 만드는 것은 더 적은 리소스를 사용하게 하고, 로그 파일에 필요한 정보를 남기게 한다는 이유가 있기 때문에 커스터마이징을 알아두면 좋다.
nginx -V 라는 명령어를 치면 거기에 로그파일이 어디에 저장되는지 나와있다.
재밌는 사실은 404는 에러가 아니다. nginx 측면에서 바라보면 정상적인 웹 서버로 응답이 간 것이기 때문이다.
location /secure {
access_log /var/log/nginx/secure.access.log;
access_log /var/log/nginx/access.log;
return 200 "welcome";
}
location /secure {
access_log off;
return 200 "welcome";
}
access_log , error_log 를 절대 경로와 함께 써주게 되면 access.log에 로그 메세지를 남기지 않고 또는 둘다 남기게 하되 secure에는 secure에 관한 로그만 우리가 지정한 파일에 로그를 남기게 된다. 만약 끄고 싶다면 off를 적어주면 되는데 error 로그는 건드리지 않았으므로 에러로그는 남겨진다. 이 뿐만 아니라 로그의형식과 버퍼 파일 사이즈, 압축 형태 등등의 다양한 세부 설정이 있다.
inheritance & directive types
events {}
######################
# (1) Array Directive
######################
# Can be specified multiple times without overriding a previous setting
# Gets inherited by all child contexts
# Child context can override inheritance by re-declaring directive
access_log /var/log/nginx/access.log;
access_log /var/log/nginx/custom.log.gz custom_format;
http {
# Include statement - non directive
include mime.types;
server {
listen 80;
server_name site1.com;
# Inherits access_log from parent context (1)
}
server {
listen 80;
server_name site2.com;
#########################
# (2) Standard Directive
#########################
# Can only be declared once. A second declaration overrides the first
# Gets inherited by all child contexts
# Child context can override inheritance by re-declaring directive
root /sites/site2;
# Completely overrides inheritance from (1)
access_log off;
location /images {
# Uses root directive inherited from (2)
try_files $uri /stock.png;
}
location /secret {
#######################
# (3) Action Directive
#######################
# Invokes an action such as a rewrite or redirect
# Inheritance does not apply as the request is either stopped (redirect/response) or re-evaluated (rewrite)
return 403 "You do not have permission to view this.";
}
}
}
3가지 directive type이 있다.
- standard - 이전 실습때 봐왔던 그러한 것들이다. array와 다른 점은 블록 안에 있다는 것이다.
- array - 맨 상위에 한번만 선언해 놓으면 된다.
- action - 어떠한 이벤트나 return 같은 무언가를 작동시키는 행위
댓글을 작성해보세요.