Home Nginx
Post
Cancel

Nginx

NGINX로 Front 배포하기

EC2 인스턴스

이 전에 언급했던 내용이므로 요약

1
2
3
4
5
6
7
8
9
10
11
sudo ssh -i {keypair}.pem ubuntu@{ec2 ipv4 주소}

docker 설치

sudo docker login -u {github username} ghcr.io

sudo docker pull ghcr.io/haedal/cicd:latest

sudo docker images

sudo docker run --name cicd -p 8080:8080 -e hello.world="hello world" -d  ghcr.io/haedal/cicd:latest





NGINX 설치 및 연습용 HTML 페이지 띄우기

install

Installing NGINX Open Source

1
2
3
sudo apt-get update
sudo apt-get install nginx
sudo nginx -v




연습용 page 띄워보기

1
curl -X GET http://localhost



1
cd /

root 폴더로 이동



1
2
cd var/www/html
cat index.nginx-debian.html

image




변경해보기

1
2
sudo nano index.nginx-debian.html
cat index.nginx-debian.html

image

image




html 새로 생성

1
2
sudo nano home.html
sudo cat home.html

서버에서 작성한 rest api 주소를 넣어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<html>
<head>

<title>HELLO-WORLD</title>

</head>
<body>
<h2> HELLO</h2>
<h5>WORLDd</h5>
<script>

fetch('http://{ec2 ipv4 주소}:8080/hello')
    .then(res => {
        if (res.ok) {
            return res.json();
        } else {
            throw new Error('Response was not OK.');
        }
    })
    .then(data => {
        document.write(data);
    })
    .catch(error => {
        console.error(error);
    });
</script>
</body>
</html>

image





*nginx.conf 파일은 /etc/nginx 폴더 안에 있음

*home.html은 /var/www/html 폴더 안에 있음


nginx config

1
2
cd /
cd etc/nginx


1
ls

nginx.conf, conf.d : 기본 설정 파일

nginx.conf는 NGINX의 주요 설정 파일이며, conf.d 디렉토리는 추가 설정 파일들을 포함하는 디렉토리



nginx config 설정

location 블록과 proxy_pass 지시어를 사용하여 요청이 특정 경로로 들어오면 해당 경로에 대한 프록시 전달을 설정할 수 있다.

1
2
3
location /api {
    proxy_pass http://backend_server;
}

위의 설정은 /api 경로로 들어오는 요청을 http://backend_server로 프록시 전달한다.

예를 들어, /api/users로 요청이 들어오면, NGINX는 http://backend_server/users라는 프록시 서버로 전달한다.

이를 통해 NGINX는 BE 서버의 경로 구조를 Client에 노출시키지 않고, 요청을 전달할 수 있다.

따라서, location 블록과 proxy_pass 지시어를 사용하여 경로를 지정하고 프록시 전달을 구성할 수 있다.

이를 통해 특정 경로의 요청을 다른 서버로 전달하거나 경로를 변경하여 요청을 처리할 수 있다.

실제로 작성을 해본다.




CORS 문제 해결을 위한 NGINX 설정

CORS (Cross-Origin Resource Sharing)는 웹 애플리케이션에서 도메인 간의 리소스 공유를 제한하는 보안 메커니즘이다.

서로 다른 도메인에서 리소스를 요청하거나 전달할 때, 브라우저는 CORS 정책을 적용하여 요청의 유효성을 확인한다.

이로 인해 동일 출처 정책(Same-Origin Policy)을 위반하는 요청은 브라우저에서 차단될 수 있다.

1
2
sudo nano nginx.conf
sudo cat nginx.conf




NGINX는 Client의 요청을 받아 Proxy Server로 전달하는 역할을 수행한다.

FE의 80 포트로 들어오는 요청을 BE의 8080 포트로 전달하여 CORS 문제를 해결한다.

이를 위해 NGINX의 설정 파일에 다음과 같이 proxy 설정을 추가한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
http{
    server{
        listen 80;
        server_name {ec2 ipv4 주소};

        
        location /api/ {
            proxy_pass http://{docker gateway 주소}:8080/;
        }
    }
    
    ...
    

☑️ NGINX의 proxy_pass 설정은 Client와 BE 서버 간의 통신을 중계하는 역할

☑️ BE 서버에서는 해당 경로에 대한 요청을 처리하여 Client에게 응답을 전달

☑️ docker gateway 주소 : 172.17.0.1, docker ip 주소 : 172.17.0.2
sudo docker inspect {container name}



Configuring NGINX and NGINX Plus as a Web Server

image

위 사진처럼 location /api//를 양 옆에 작성해준다.




예시

proxy_pass를 http://domain.com:8080;로 설정

Frontend (FE)는 도메인 domain.com에서 호스팅되며, 포트 80을 사용한다.

Backend (BE)는 도메인 domain.com에서 호스팅되며, 포트 8080을 사용한다.


/api로 들어오는 요청은 http://{docker gateway 주소}:8080/로 전달된다.

Client가 http://domain.com:8080/api/hello로 요청을 보내면

NGINX가 해당 요청을 proxy하여 BE의 도메인인 http://domain.com:8080으로 전달한다.

BE 서버에서 /hello에 해당하는 controller를 찾아서 처리한다.

/api/hello로 들어오는 요청은 BE 서버에서는 /hello에 해당하는 Controller로 라우팅되어 처리된다.

Client는 NGINX를 경유하여 응답을 받지만, 실제로 처리되는 서버는 BE다.


→ 프록시를 통해 요청이 전달되고 Backend에서는 적절한 Controller로 라우팅되므로,

CORS(Cross-Origin Resource Sharing) 문제를 해결할 수 있다.


☑️ proxy : client와 server 사이에서 중계 역할을 수행하는 server

☑️ 라우팅 : client가 보낸 요청이 BE 서버에서 적절한 handler or Controller로 전달하는 과정




Reverse Proxy

port는 서비스가 동작하는 특정 번호로, 웹 서버는 일반적으로 80 포트를 사용하여 Client의 요청을 처리한다.

그러나 외부 서비스로 요청을 전달해야 할 때 port 중복 문제가 발생할 수 있다. 이때 Reverse Proxy 설정이 유용하다.

Reverse Proxy는 Client의 요청을 받아 다른 서버로 전달하고, Server로부터 받은 응답을 Client에게 반환하는 방식이다.

Client는 원래의 서버에 직접 요청하는 것처럼 Reverse Proxy Server를 통해 요청을 보내지만,

실제로는 Reverse Proxy가 요청을 End Server로 전달한다.


☑️ Reverse Proxy : Client로부터의 요청을 받아 해당 요청을 다른 서버로 전달하는 방식

☑️ Reverse Proxy Server : Reverse Proxy를 실행하는 서버

Client의 요청을 받아서 End Server로 전달하고 End Server로부터 받은 응답을 Client에게 반환

☑️ End Server : Client로부터의 요청을 실제로 처리하고 응답을 생성하는 Server


예를 들어, Nginx는 80 포트에서 동작하는 웹 서버이고 BE 서버는 8080 포트에서 동작한다.

Client는 80 포트로 Nginx에 요청을 보내면, Nginx가 이를 받아 BE 서버로 전달한다.

BE 서버는 요청을 처리하고 응답을 Nginx로 반환한 다음, Nginx는 Client에게 응답을 전달한다.

이렇게 보내는 포트(80)와 받는 포트(8080)가 다르기 때문에 Reverse Proxy 설정을 사용하여 요청을 올바르게 전달할 수 있다.


Nginx에서는 proxy_pass 지시문을 사용하여 Reverse Proxy 설정을 구성할 수 있다.

이를 통해 Client로부터의 요청을 받은 Nginx는 해당 요청을 백엔드 서버로 전달하고,

Server로부터 받은 응답을 Client에게 반환한다.

이렇게 port가 다른 상황에서 Reverse Proxy 설정을 통해 Client는 BE 서버의 존재를 알 필요가 없고

Nginx를 통해 원할한 통신을 할 수 있다.


Reverse Proxy를 사용하는 이유는 로드 밸런싱을 위해 여러 개의 백엔드 서버에 요청을 분산할 수 있으며,

보안을 강화하기 위해 백엔드 서버를 직접 노출하지 않을 수 있다.

Reverse Proxy 설정은 포트 연결을 간편하게 처리하며, 유연하고 안전한 웹 서비스 구축을 돕는다.




Docker gateway

웹 사이트에 접속할 때 대부분은 도메인 주소만 입력하면 되는 경우가 많다.

하지만 특정 서비스나 애플리케이션에 접근하기 위해서는 포트 번호를 입력해야 하는 경우도 있다.

이때 포트 번호까지 입력하는 것은 사용자 경험에 좋지 않을 수 있다.

예를 들어, 네이버에 접속하기 위해 www.naver.com이라고 입력하면 될 것을

www.naver.com:8080과 같이 포트 번호를 입력해야 한다면 조금 이상하게 느껴질 것이다.

이러한 상황에서 우리를 도와주는 역할을 하는 것이 Docker Gateway(게이트웨이)다.


Docker Gateway는 Docker 네트워크에 속한 컨테이너 간 통신을 가능하게 하는 네트워크 요소다.

각각의 Docker 컨테이너는 고유한 IP 주소를 가지고 있지만, 외부로부터 접근하려면 해당 컨테이너의 IP 주소와 포트 번호를 알아야 한다.

이는 사용자 경험을 해치는 요소가 될 수 있다.

따라서 Docker 게이트웨이를 사용하여 외부에서 접근 가능한 포트 번호와 컨테이너 내부의 포트 번호를 매핑시킬 수 있다.

이렇게 하면 사용자는 Gateway 주소를 통해 서비스에 접근할 수 있고, 실제로 해당 서비스는 Docker 컨테이너 내의 포트 번호로 전달된다.

Gateway를 사용함으로써 포트 번호를 외부로 노출시키지 않고도 서비스에 접근할 수 있으며, Docker 컨테이너의 내부 구조를 숨길 수 있다.

Gateway는 사용자가 도메인 주소만 입력하면 서비스의 실제 위치인 포트 번호까지 자동으로 연결해준다.

예를 들어, api.naver.com이라는 도메인 주소를 입력하면 게이트웨이는 이를 localhost:8080으로 자동으로 연결해준다.

이렇게 Gateway를 사용하면 사용자는 편리하게 서비스에 접근할 수 있고

서비스 제공자는 Gateway를 통해 포트 번호를 노출시키지 않고도 서비스를 제공할 수 있다.

사용자는 단순히 도메인 주소를 입력하여 서비스에 접근할 수 있으며, 게이트웨이가 포트 번호를 자동으로 연결해준다.




Nginx 서버의 설정을 다시 불러와서 변경 사항을 적용

1
sudo service nginx reload

Nginx의 설정을 수정한 후에는 변경 사항을 적용하기 위해 위 명령어를 실행해 서버의 중단없이 설정 변경이 반영된다.



{ec2 ipv4 주소}/api/hello로 입력하면 기존의 rest api에서 뜨던 coco가 제대로 뜬다.

→ 기존에 세팅되던 project server는 문제 없이 띄워진다.

image


{ec2 ipv4 주소}/home.html로 띄우면 404 Not Found 에러가 뜬다.

→ 해당 설정에서 /api 주소로 가라는 설정은 있지만 그 외의 설정을 해두지 않아서 에러가 뜬 것 같다.




nginx.conf 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http{
    server{
        listen 80;
        server_name {ec2 ipv4 주소};
            
        location / {
            root /var/www/html;
        }        
        
        location /api/ {
            proxy_pass http://{docker gateway 주소}:8080/;
        }
    }
    
    ...

정적 파일들은 그대로 전달해주면 되므로 location / 처럼 작성하면 된다.

☑️ project에 적용할 때는 js의 url만 앞에 /api를 붙여주면 된다.



home.html에서 “api”를 추가한다.

1
fetch('http://{ec2 ipv4 주소}/api/hello')

image






정리

NGINX와 Spring Boot를 사용하여 FE와 BE를 분리

NGINX는 FE 애플리케이션인 정적인 파일 (HTML, CSS, JavaScript)을 제공하는 역할을 담당한다.

주로 HTML, CSS, JavaScript를 사용하여 웹 페이지를 구성하고, 사용자와 상호작용을 가능하게 한다.

NGINX는 웹 서버 소프트웨어로, 정적인 파일들을 제공하는 데에 특화되어 있다.

FE에서 사용되는 HTML, CSS, JavaScript 파일들은 NGINX 서버에 배포되어 사용자에게 전달된다.

BE는 FE와 상호작용하여 데이터를 처리하고, 동적인 기능을 제공한다.

FE에서 필요한 데이터를 요청하면 BE는 해당 요청을 처리하고 필요한 데이터를 가져와서 JSON 형식으로 FE에게 반환한다.

FE는 NGINX 서버에서 정적인 파일을 받고, 사용자의 요청에 따라 동적인 데이터를 BE에 요청한다.

이때 FE는 HTTP 통신을 통해 백엔드에 요청을 보내고, JSON 형식으로 데이터를 받는다.

BE는 받은 요청을 처리하고, 필요한 데이터를 JSON 형식으로 FE에게 반환다.

실제 서비스에서 DTO(Data Transfer Object)를 사용하여 데이터를 정의하고 전달한다.

FE는 받은 데이터를 가공하고,

필요한 부분을 동적으로 렌더링(데이터와 템플릿을 결합하여 최종적으로 사용자에게 보여지는 결과물을 생성하는 과정)하여

사용자에게 보여준다.




NGINX를 통한 FE와 BE의 분리

NGINX의 설정 파일에서 FE와 BE의 경로를 설정하고,

FE에 대한 요청은 NGINX에서 처리하고, BE에 대한 요청은 proxy로 전달하도록 설정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
http{
    server{
        listen 80;
        server_name {ec2 ipv4 주소};
            
        location / {
            root /var/www/html;
        }        
        
        location /api/ {
            proxy_pass http://{docker gateway 주소}:8080/;
        }
    }

FE에 대한 요청은 / 경로로 오는 요청을 /var/www/html 디렉토리에서 처리하도록 설정되어 있다.

반면 BE에 대한 요청은 /api/ 경로로 오는 요청을

백엔드의 Docker Gateway 주소와 port 8080으로 proxy로 전달하도록 설정되어 있다.

이렇게 설정하면 FE는 NGINX 서버에서 정적인 파일을 받고, BE에 필요한 데이터를 요청한다.

BE는 요청을 처리하고 데이터를 반환하면, FE는 받은 데이터를 가공하여 사용자에게 동적인 내용을 렌더링하여 보여준다.



EC2 인스턴스 내부에는 Docker와 Nginx가 설치되어 있으며,

Docker 내부에는 기본적으로 제공되는 ‘bridge’라는 네트워크가 있다.

image

‘bridge’ 네트워크의 주소는 172.17.0.1이며, 해당 네트워크에는 Spring Boot와 MySQL이 실행되고 있다.

Spring Boot는 172.17.0.2, MySQL은 172.17.0.3의 IP 주소를 할당받아 서로 연결되어 있다.

Nginx는 Docker 내부의 Spring Boot에 직접 연결할 수 없기 때문에(주소를 알 수 없음) Docker의 ‘bridge’를 활용하여 연결한다.

따라서, Nginx 설정에서는 localhost 대신 ‘bridge’의 주소를 사용하여 연결을 설정한다.

1
2
3
location /api/ {
    proxy_pass http://{docker gateway 주소}:8080/;
}

bridge는 기본적으로 제공되는 network다.

Docker로 연결했기 때문에 위와 같은 주소로 연결을 했을 뿐 naver 주소를 쓰면 naver로 연결된다.

MSA를 적용해서 Docker container를 2개로 분리하고 port를 8080, 8081로 만들면 network를 새로 생성해야한다.

Docker network



EC2 보안 규칙에서 8080 포트를 지우고 80 포트만 남겨도 되는 이유는 proxy_pass 때문이다.

Nginx 서버는 Client의 요청을 받아들이는 포트로 80 포트를 사용한다.

80 포트로 들어온 요청을 다른 포트로 전달하기 위해 사용하는 설정이 reverse proxy 설정인 proxy_pass이다.

8080 포트는 필요한 경우에만 proxy_pass 설정을 통해 사용하면 된다.



Nginx 설정에서는 /api/로 시작하는 요청은 백엔드(Back-End) 서버로 전달되고,

그 외의 요청은 정적인 콘텐츠로 처리된다.

이를 통해 백엔드와 프론트엔드(Back-End와 Front-End) 간의 역할을 분리할 수 있었다.

백엔드는 REST API를 통해 데이터를 처리하고, 프론트엔드는 정적인 콘텐츠를 제공하며 동적인 사용자 인터페이스를 구성할 수 있다.

이렇게 역할을 분리함으로써 시스템을 확장하고 유연하게 개발할 수 있으며, 보안과 성능도 개선할 수 있다.



front 배포할 때 html, css, js만 넣어주면 된다.

폴더를 하나 만들어서 git clone 해주면 끝!



Docker에서 사용 가능한 네트워크

1
sudo docker network ls

image

This post is licensed under CC BY 4.0 by the author.