쿠키에 토큰정보를 넣어서 요청을 보내면  서버는 쿠키에서 인증 토큰을 꺼내서 검증하는 로직을 만들었다.

 

 

먼저 처음로 Cookies 파란글자 버튼을 클릭해서 넣음  > 전혀 인식하지 않음. 

 

검색을 해본 결과 다른 방법이 있어서 시도해보니 정상적으로 동작한다. 

 

 

 

 

아래 사진과 같이 넣어서 요청을 보내면 인식하고 동작한다. 

 

 

 

 

참고로 헤더에 값을 넣어서 인증을 할 때는 

key value
Authorization Bearer 토튼값

이런식으로 넣어서 요청을 보내면 된다. 

OAuth2.0 인증까지 완료하고 리다이렉트후 클라이언트에서 인증관련 토큰 정보가 확인이 안 되는 문제다. 

 

 

 

✅ CORS란?

=Cors Origin Resource Sharing(교차 출처 리소스 공유)의 약자

추가 HTTP헤더를 사용하여 서로 다른 출처(도메인, 프로토콜, 포트)에 있는 웹 페이지나 서버가 서로 다른 자원에 접근할 수 있도록 허용하는 보안 메커니즘이다. 

 

도메인, 프로토콜, 포트 예시 

  • 프로토콜 =>  HTTPS, HTTP
  • 포트 => 8080, 80
  • 도메인  => www.naver.com  

 

 

CORS는 브라우저가 임의의 웹 페이지에 다른 웹 페이지의 자원에 무분별하게 접근하는 것을 막아 XSS(Cross-site Scripting)와 같은 보안 위협으로부터 웹페이지를 보안한다.
기본적으로 모든 브라우저는 같은 정책을 따르는데, "해당 페이지와 같은 출처의 리소스에만 접근 가능하다."

따라서 다른 출처로부터 자원을 요청하려면  CORS헤더를 넣어줘야한다.

 

 

"도메인, 프로토콜, 포트가 다른데 리소스에 접근이 필요하다면 CORS 헤더를 설정해주자!"

 

단! 도메인이 아예 다르면 접근 불가능 www.naver.com   - api.naver.com  CORS헤더 설정으로 접근 가능 

www.naver.com  - api.google.com CORS설정을 해도 접근 불가능 

 

자세한건 아래 포스팅을 참고하자. 

https://whdudev.tistory.com/27

 

[OAuth2.0] [Errror] 서로 다른 도메인간 쿠키 공유

서버는 도메인 무료 사이트에서 배포하고 프론트는 vercel로 배포했다.  이는 필연적으로 서로 다른 도메인을 사용하게 된다는 문제점이 있었다. cors설정을 바꿔도 쿠키 관련 설정을 바꿔도 same s

whdudev.tistory.com

 

 

 

 

 

✅ CORS작동 원리 

Access-Control-Allow-Origin은 CORS에서 사용되는 HTTP 응답 헤더 중 하나로, 다른 도메인에서의 요청을 허용하는 경우 어떤 도메인에서 요청을 허용할 것인지를 명시합니다.
스프링기준 설정법 : WebMvcConfigurer(전역설정),@CrossOrigin(개별 컨트럴러),CorsFilter(커스텀)

 

 

브라우저다른 출처의 리소스에 접근하려고 시도하면, 브라우저는 요청 헤더에 "Origin" 필드를 포함하여 요청을 보낸다. "Origin" 필드에는 요청을 보낸 웹 페이지의 출처 정보가 담긴다.

 

서버는 요청을 받고, "Origin" 필드를 확인하여 요청이 허용되는 출처인지 판단한다.

허용된 출처라면 응답 헤더에 "Access-Control-Allow-Origin" 헤더를 포함하여 클라이언트에게 알린다. 이 헤더에는 허용된 출처의 목록이 포함되며, "*"는 모든 출처를 허용한다는 뜻이다.

 

브라우저는 서버의 응답을 받아 "Access-Control-Allow-Origin" 헤더를 확인한다. 요청을 보낸 출처가 허용 목록에 포함되어 있으면 응답을 처리하고, 그렇지 않으면 거부한다.

 

 

 

 

✅ CORS설정하는 법

 

일단 필자의 프로젝트에서는 api.*.com(서버)과 www.*.com(클라이언트)로 서로 다른 도메인을 가지고 
Https통신을 하며  서버에는 ec2내부에 Nginx를 두어서 HTTPS설정을 했고 스프링부트 애플리케이션도 같은 ec2에서 실행중이다. 

 

Spring Boot에서 CORS 설정을 한다는 것은 결과적으로 HTTP 응답 헤더에 Access-Control-Allow-Origin을 포함시키는 과정이다.

 

 

CORS 허용 

@Configuration
public class CorsMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry corsRegistry) {
        corsRegistry.addMapping("/**")
                .allowedOrigins("https://*:3000", "https://www.*.shop") // 정확한 도메인 지정
                .allowedMethods("*") // 모든 HTTP 메서드 허용
                .allowedHeaders("*") // 모든 헤더 허용
                .allowCredentials(true) // ✅ 쿠키 전송 허용 (allowedOrigins("*")와 함께 사용 불가)
                .exposedHeaders("Authorization", "Set-Cookie"); // ✅ 클라이언트가 Authorization 헤더 받을 수 있도록 허용
    }
}

 

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


        http
                .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {

                    @Override
                    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {

                        CorsConfiguration configuration = new CorsConfiguration();

                        configuration.setAllowedOrigins(Arrays.asList(
                                "https://*:3000",
                                "https://www.*.shop"
                        ));
                        configuration.setAllowedMethods(Collections.singletonList("*"));
                        configuration.setAllowCredentials(true); // ✅ 쿠키 전송 허용
                        configuration.setAllowedHeaders(Collections.singletonList("*"));
                        configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization"));
                        configuration.setMaxAge(3600L); // 1시간 캐시


                        return configuration;
                    }
                }));
                
                
     }

 


쿠키 설정 

 

쿠키에도 도메인과 Path가 있이서 설정해줘야함.

   private Cookie createCookie(String key, String value) {

        Cookie cookie = new Cookie(key, value);
        cookie.setMaxAge(60 * 60 * 60 * 60);


        cookie.setSecure(true); // 로컬 개발 환경에서는 Secure=false

        // Secure=false → 쿠키가 HTTP와 HTTPS 둘 다 전송됨 클라가 Https일때는 true
        // HTTPS가 아닐 때도 테스트할 수 있도록 설정

        cookie.setDomain("*.shop"); // 서브도메인 간 공유

        cookie.setHttpOnly(true);

        // CORS 문제 해결 (리디렉션 후에도 쿠키 유지)
        cookie.setAttribute("SameSite", "None");
        cookie.setPath("/");


        return cookie;
    }

yml

server:
  servlet:
    session:
      cookie:
        secure: true
        samesite: None




Nginx 설정 

        # ✅ CORS 설정 (쿠키 포함 허용)
        add_header Access-Control-Allow-Origin $origin always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Set-Cookie" always;

        # ✅ 쿠키 유지
        proxy_pass_header Set-Cookie;
        proxy_cookie_path / "/; Secure;  HttpOnly; SameSite=None Domain=.*.shop";

 

 

 

 

 

✅  출처

 

https://namu.wiki/w/CORS

 

CORS

C ross O rigin R esource S haring(교차 출처 리소스 공유)의 약자로, 추가 HTT

namu.wiki

https://docs.tosspayments.com/resources/glossary/cors

 

CORS(교차 출처 리소스 공유) | 토스페이먼츠 개발자센터

CORS를 번역하면 “교차 출처 리소스 공유”에요. ‘두 출처가 서로 다르다’는 뜻인데요. CORS를 설정한다는 건 ‘출처가 다른 서버 간의 리소스 공유’를 허용한다는 거죠.

docs.tosspayments.com

https://duklook.tistory.com/209

 

[단순용어] CORS 와 Access-Control-Allow-Origin

CORS (Cross-Origin Resource Sharing) CORS (Cross-Origin Resource Sharing)는 웹 브라우저에서 실행되는 스크립트가 다른 도메인의 자원에 접근할 수 있는 권한을 부여하는 보안 기능입니다. 일반적으로 웹 브라우

duklook.tistory.com

 

 

서버는 도메인 무료 사이트에서 배포하고 프론트는 vercel로 배포했다.  이는 필연적으로 서로 다른 도메인을 사용하게 된다는 문제점이 있었다. cors설정을 바꿔도 쿠키 관련 설정을 바꿔도 same site설정을 바꿔도 할건 다해도 서버와 프론트 사이에 쿠키가 전달되지 않았다. 

결론적으로 같은  도메인명, 최상위 도메인명을 맞추거나  Redicrect URI 쿼리파라미터로 전달하면 된다.  

 

현재 상황 

https://*.kro.kr > 서버 

https://*.vercel.app > 프론트 


 

 

  서로 다른 도메인이란? 

 도메인이란 www.naver.com   이런게 도메인이다.  "도메인이 다르다"  간단하게 도메인 주소가 다른것이다. 

 

기본적으로는 같은 도메인 에서만 쿠키를 공유한다. 

"도메인이 다르면 서버와 클라이언트가 쿠키를 공유할 수 있나요?"

경우에 따라서 다르다

 

 

도메인명, 최상위 도메인명이 같으면 설정을 통해 공유가 가능하다. 즉, www.naver.com에서 발급한 쿠키는 blod.naver.com과 같이 naver.com이 동일하면 공유가 된다.

 

아래 처럼 설정하면 된다.

 

  • Set-Cookie: session=abc123; Domain=naver.com; Path=/; HttpOnly; Secure
  • 이렇게 설정하면 *.naver.com의 모든 서브도메인에서 쿠키를 공유할 수 있습니다.
  • 만약 Domain=www.naver.com으로 설정하면 blog.naver.com에서는 쿠키를 사용할 수 없습니다.

 

https://www.beusable.net/blog/?p=4507

 

 

✅ 해결

어떻게 해결할 수 있을까? 일단 쿼리파라미터로 응답하는 방법이나 쿼리파라미터로 구현하는 방법  또는 가능하다면 도메인을 맞추는 방법이 있겠다.

 

필자의 경우에는 그냥 도메인을 맞추는 방법을 사용하기로 했다. 

 

 

이런식으로 호스트명만 다른 도메인을 발급받아서 사용하면 될 것 이다. 

 

✅ 정확한 정리

백엔드(https://어쩌구.kro.kr), 프론트엔드(https://어쩌구.vercel.app)일 때,
✔️ 최상위 도메인이 다르므로 쿠키 공유는 불가능하다!

📌 설정(SameSite=None; Secure, CORS 등)을 아무리 해도 브라우저 보안 정책상 쿠키는 자동 전송되지 않는다.

 

 

 

 

 

 

 

 

참고

https://velog.io/@jojeon4515/%EC%84%9C%EB%A1%9C-%EB%8B%A4%EB%A5%B8-%EB%8F%84%EB%A9%94%EC%9D%B8%EC%97%90%EC%84%9C-%EC%BF%A0%ED%82%A4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-React-Express

 

서로 다른 도메인에서 쿠키 사용하기 (React, Express)

💫 서론 MERN 조합으로 진행한 개인프로젝트의 기능 개발을 완료한 후 프론트엔드는 vercel에, 백엔드는 GCP(Google Cloud Platform)에 배포하여 서로 다른 프론트엔드와 백엔드의 도메인을 얻게 되었다.

velog.io

 

 

https://www.beusable.net/blog/?p=4507

 

데이터 분석을 위한 기초, URL 이해하기 | 뷰저블

데이터 분석을 위한 URL

www.beusable.net

 

구조 

먼저 지금까지 한 세팅된 것들에 대해서 말해주겠다!

우분투 ec2 8080포트로 서버 올라감 + DNS(Domain Name System)발급

 

 

내가 지금 구현할 구조다 Ec2 내부에 Nginx와 Spring Boot를 띄울꺼다. 이번 프로젝트에서 이 기능을 사용하는 이유는 

SSL기능과 서버를 보호하기 위해서 사용하기 때문에 이렇게 구성해도 문제 없다. 


✅ Ubuntu 환경에서 Nginx 설치하기

# apt에서 설치 가능한 패키지 리스트(최신 패키지, 버전 등)를 최신화시킨다.
# apt는 리눅스에서 사용되는 소프트웨어 패키지를 설치 및 관리할 수 있게 도와주는 툴이다.
# npm 또는 gradle과 같은 패키지 관리 도구와 비슷하다고 생각하면 된다. 
$ sudo apt update

# nginx 설치에 필요한 라이브러리 설치
$ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring

# nginx 공식 패키지를 안전하게 설치하기 위한 보안 조치이다. 자세한 코드 의미는 몰라도 된다. 
# 다만, curl, gpg, tee, |, >, /dev/null, echo가 무슨 기능을 하는 명령어인지는 정리해두자. 
$ curl <https://nginx.org/keys/nginx_signing.key> | gpg --dearmor \\
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
$ gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \\
<http://nginx.org/packages/ubuntu> `lsb_release -cs` nginx" \\
    | sudo tee /etc/apt/sources.list.d/nginx.list

# nginx 설치
$ sudo apt update
$ sudo apt install nginx




✅ Nginx 실행하기

# nginx 상태 확인
$ sudo systemctl status nginx

# nginx 시작
$ sudo systemctl start nginx

# nginx 상태 확인
$ sudo systemctl status nginx
  • 참고) systemctl 명령어는 자주 사용하니 따로 찾아서 정리해두자.

 

 

✅ Nginx 로그 확인하는 방법

Nginx의 로그 파일 위치는 /var/log/nginx/이다. 이 경로로 이동하면 access.log와 error.log 파일이 있다. access.log 파일에는 Nginx 서버로 접근한 요청에 대한 정보가 기록으로 남아있고, error.log 파일에는 에러 메시지에 대한 내용이 담겨있다.

# Nginx 로그 파일이 위치한 곳으로 이동
$ cd /var/log/nginx

# 파일의 마지막 10줄을 출력
$ tail access.log
$ tail error.log

실시간으로 access.log가 쌓이는 걸 눈으로 확인해보자

# 파일의 마지막 10줄을 출력 + 실시간으로 파일에 추가되는 내용을 출력
$ tail -f access.log

 

 

✅ Nginx의 설정 파일 위치

  1. /etc/nginx/nginx.conf
    • Nginx에서 가장 근본이 되는 설정 파일(루트 설정 파일)
    • 전역적으로 설정되어야 하는 내용(워커 프로세스 개수, 로그 저장 위치 등)이 포함되어 있다.
  2. /etc/nginx/conf.d/default.conf
    • 기본 웹 서버(Web Server) 설정 파일

이렇게 크게 2가지 설정 파일이 존재한다. 여기서 /etc/nginx/conf.d/default.conf 파일 위주로 코드를 해석해보자.

 

 

✅ 기본적인 Nginx 문법 해석

/etc/nginx/conf.d/default.conf

server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \\.php$ {
    #    proxy_pass   <http://127.0.0.1>;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \\.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\\.ht {
    #    deny  all;
    #}
}

위 파일을 열어보면 위와 같이 코드가 작성되어 있다. 주석 부분을 빼고 보자.

/etc/nginx/conf.d/default.conf

# server : '하나의 웹 사이트에 관련된 설정'을 관리하는 단위 ('server 블럭'이라고 부름)
server {
    # localhost:80으로 들어오는 요청을 이 server 블럭에서 처리하도록 설정
    # (server_name이 일치하는 server 블럭이 없는 경우 첫 번째 정의되어 있는 server 블럭을 기반으로 처리)
    # (아직은 정확히 몰라도 된다. 나중에 '멀티 도메인' 기능을 배우면 쉽게 이해할 수 있다.)
    listen       80;
    server_name  localhost;

    # / 으로 시작하는 모든 경로를 처리 (ex. /index.html)
    location / {
        # /jscode.html로 요청이 들어오면 /usr/share/nginx/html/jscode.html 파일로 응답
        root   /usr/share/nginx/html;
        
        # /로 요청이 들어오면 /usr/share/nginx/html/index.html로 응답
        # 만약 /usr/share/nginx/html/index.html이 없을 경우, /usr/share/nginx/html/index.htm으로 응답
        index  index.html index.htm;
    }

    # Nginx에서 500, 502, 503, 504의 상태 코드가 발생했을 때 /50x.html로 redirect
    error_page   500 502 503 504  /50x.html;
    
    # /50x.html과 완전히 일치하는 경로를 처리
    location = /50x.html {
        # /50x.html로 요청이 들어오면 /usr/share/nginx/html/50x.html 파일로 응답
        root   /usr/share/nginx/html;
    }
}
  • 주의) ‘중괄호({...}) 형태의 구문’과 ‘세미 콜론(;)으로 끝나는 구문’ 2가지가 있다. 설정 파일을 작성할 때 세미 콜론(;)을 빠트려서 에러가 뜨는 경우가 많으니 주의하자.

 

 

 

 

✅ Nginx 에러 디버깅 방법

Nginx가 정상적으로 실행되고 있는 지 체크

$ sudo systemctl status nginx

문법 에러 체크하기

$ sudo nginx -t

로그 파일 실시간으로 확인하기

# 제대로 요청이 들어오고 있는 지 확인 
$ sudo tail -f /var/log/nginx/access.log 
# 에러 메시지 확인 
$ sudo tail -f /var/log/nginx/error.log

 

 

 

✅ Nginx, Certbot을 활용해 HTTPS 적용시키기

참고 문서 : https://certbot.eff.org/instructions?ws=nginx&os=snap

  1. Certbot 설치하기
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

 

2.HTTPS 인증서 발급받기

$ sudo cerbot --nginx -d <도메인주소>

 

- 이메일 입력 

-  동의  

> 인증서 발급

 

 

 

✅ Nginx와 Srping Boot 연동

참고한 강의를 따라하면 /etc/nginx/conf.d/default.conf 경로에 설정파일이 생긴다고 했다. 하지만 무슨 이유에서인지 생기지 않았다.하지만 nginx에 정상적으로 접속이 되는 상태이다.

 

/etc/nginx/nginx.conf 

$ cat /etc/nginx/nginx.conf

nginx설정 파일을 열어보면 

위 사진과 같은 경로을 include하는걸 알 수가 있다. 우리가 직접 만들어주자!

 

 

 

/etc.nginx/sites-enabled/default로 Certbotdl가 만들어준게 있길래 수정했다.

server {
    listen 80;
    listen [::]:80;
    server_name <도메인 hello.kro.kr>;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    return 301 https://$host$request_uri; # HTTP 요청을 HTTPS로 리디렉트
}

server {
    listen 443 ssl;
    listen [::]:443 ssl ipv6only=on;
    server_name <도메인 hello.kro.kr>;

    ssl_certificate /etc/letsencrypt/live/<도메인 hello.kro.kr>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<도메인 hello.kro.kr>/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

 

 

  • HTTP(80) 요청HTTPS(443)로 강제 리디렉트.
  • HTTPS(443) 요청localhost:8080에서 실행 중인 애플리케이션으로 프록시 처리.
  • Let's Encrypt SSL 인증서를 사용하여 보안 강화.

 

 

아래 명령어로 테스트! 

$ sudo nginx -t  # 설정 문법 확인
$ sudo systemctl restart nginx  # Nginx 재시작

 

여기까지 문제가 없다면 Nginx가 최초 클라이언트의 요청을 받고 8080포트의 애플리케이션에 전달하는 기능을 완성한 거다! 

SSL기능 구현 HTTPS로 동작하도록 설정함. 

 

 서버를 더욱 보호하기! 

한 IP에서 1초당 보낼 수 있는 요청 제한하기 

 

/etc.nginx/sites-enabled/default 수정

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=4r/s;

server {

    limit_req zone=mylimit;
    limit_req_status 429;
    listen 80;
    listen [::]:80;
    server_name <도메인>;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    return 301 https://$host$request_uri; # HTTP 요청을 HTTPS로 리디렉트
}

server {
    listen 443 ssl;
    listen [::]:443 ssl ipv6only=on;
    server_name auctify.kro.kr;

    ssl_certificate /etc/letsencrypt/live/<도메인>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<도메인>/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    limit_req zone=mylimit;
    limit_req_status 429;
    
    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

 

 

많은 1초에 많은 요청에 대해 429 Too Many Requests응답 

 

 참고

 

 

https://velog.io/@goat_hoon/Nginx-nginx.conf-vs-default.conf-include-%EC%95%8C%EA%B3%A0-%EC%82%AC%EC%9A%A9%ED%95%98%EC%9E%90

 

[Nginx] nginx.conf vs default.conf (include 알고 사용하자)

Nginx의 include 지시자와 상위,하위 블록간의 Directive 상속관계를 알아보자

velog.io

 

https://www.inflearn.com/course/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90%EB%8F%84-%EC%9D%B4%ED%95%B4-nginx-%EC%9E%85%EB%AC%B8-%EC%8B%A4%EC%A0%84

 

비전공자도 이해할 수 있는 Nginx 입문/실전 강의 | JSCODE 박재성 - 인프런

JSCODE 박재성 | , 🤬 Nginx는 혼자서 공부하기 왜 이렇게 어려운거야?!비전공자로 개발을 시작해 여러 회사에서 CTO로 활동하다가, 현재는 교육자로 활동하고 있는 박재성이라고 합니다. 저도 비전

www.inflearn.com

 

https://www.youtube.com/watch?v=6FAwAXXj5N0

 

 

프로젝트를 진행하면서 서버에 도메인을 연결해야지 HTTPS를 적용할 수 있음을 알았다. 
유료로 할 수도 있지만 개인프로젝트에 굳이 유로를 사용할 필요가 있나 싶다. 그래서 무료로 연동하는 법에 대해서 포스팅하려고한다. 

 

 

 

https://xn--220b31d95hq8o.xn--3e0b707e/

 

내도메인.한국 - 한글 무료 도메인 등록센터

한글 무료 도메인 내도메인.한국, 웹포워딩, DNS 등 무료 도메인 기능 제공

xn--220b31d95hq8o.xn--3e0b707e

도메인을 발급해줄 사이트다. 

 

 

 

 

 

 

 

 

 

 

고급설정 맨 첫번째 EC2 IP주소 입력 부분에 IP주소를 입력하면 된다. 

 

 

 

이제 발급받은 도메인으로 접속하면  ec2로 연결되는 것을 확인할 수 있다. 

(80아닐 경우 포트번호 확인하자!)

 

 

 

단점 

1. 도메인 주소가 조큼 이상하다.  .com이 일반적은데 안 그럼 

2. 서버가 가끔 불안정적이여서 끊길 수 있다. 

 

CICD란?

CI/CD는 지속적 통합(CI)과 지속적 제공/배포(CD)를 의미하는 IT 용어입니다.

CICD를 왜 사용하는가?

배포를 해보시면 아시겠지만 변경이 있을 때 마다 테스트하고 배포하는 과정은 번거롭고 많은 시간이 소모됩니다.

따라서 저희는 이번 Auctify프로젝트에 CICD기술을 적용 시키기로 했습니다.

어떤 기술들로 구현할 수 있는가?

CICD는 젠킨스, github action, git labs 등으로 구현하는데

아래와 같은 특징들이 있다. Jenkins는 자체 호스팅이 필요하다는 점에서 매력적으로 다가오지 않았고, 현재 프로젝트에서 GitLab을 사용하지 않으므로 이 역시 제외 시켰다. 결국 우리는 GitHub Actions로 구현하기로 정했다.

 
JenkinsGitHub ActionsGitLab CI/CD
설치 방식 자체 호스팅 필요 GitHub 내장 GitLab 내장
설정 파일 Jenkinsfile (DSL 기반) YAML (.github/workflows/) YAML (.gitlab-ci.yml)
확장성 플러그인으로 무한 확장 가능 GitHub Marketplace 활용 GitLab 자체 기능 활용
호스팅 옵션 온프레미스, 클라우드 모두 가능 GitHub 제공 Runner GitLab 제공 Runner, 자체 Runner
러닝 커브 높음 (설치 & 설정 복잡) 낮음 (GitHub 내장, YAML 기반) 중간 (GitLab 내장, YAML 기반)
Git과의 통합 GitHub, GitLab, Bitbucket 등 지원 GitHub 전용 GitLab 전용
사용 추천 환경 기업 환경, 복잡한 CI/CD 구축 필요할 때 GitHub 기반 프로젝트 GitLab 사용 환경, 자체 호스팅 필요할 때

어떤 방식으로 구현할 것 인가?

✅ 장점

  • Docker 기반으로 서비스를 운영할 때, 가장 간단하게 구성할 수 있는 인프라 구조이다.

✅ 단점

  • 무중단 배포를 구현하거나 여러 EC2 인스턴스에 배포를 해야 하는 상황이라면, 직접 Github Actions에 스크립트를 작성해서 구현해야 한다. 직접 구현을 해보면 알겠지만 생각보다 꽤 복잡하다.

✅ 이 방법은 언제 주로 쓰는 지

  • 컨테이너 기반으로 인프라를 구성했을 때 이 방법을 많이 활용한다.
  • 서버를 여러 대 운영하고 있지 않을 정도의 소규모 프로젝트 일 때 주로 활용한다.

실제 구현 방법 설명

도커파일 (local에서는 application-local.yml을 사용한다.)

FROM eclipse-temurin:17-jdk-alpine
COPY ./build/libs/*SNAPSHOT.jar project.jar
ENTRYPOINT ["java", "-jar","-Dspring.profiles.active=prod", "project.jar"]


프로젝트/.github/workflows/deploy.yml

name: Deploy To EC2

on:
  push:
    branches:
      - main

jobs:
  Deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Github Repository 파일 불러오기
        uses: actions/checkout@v4

      - name: JDK 17버전 설치
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 17

      - name: application-prod.yml 파일 만들기
        run: echo "${{ secrets.APPLICATION_PROPERTIES}}" > ./src/main/resources/application-prod.yml

      - name: 테스트 및 빌드하기
        run: ./gradlew clean build

      - name: AWS Resources에 접근할 수 있게 AWS credentials 설정
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-2
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: ECR에 로그인하기
        id : login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Docker 이미지를 생성
        run: docker build -t auctify-server .

      - name: Docker 이미지에 Tag 붙이기
        run: docker tag auctify-server ${{ steps.login-ecr.outputs.registry }}/auctify_server:latest

      - name: ECR에 Docker 이미지 Push
        run: docker push ${{ steps.login-ecr.outputs.registry }}/auctify_server:latest

      - name: SSH로 EC2에  접속하기
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.EC2_HOST}}
          username: ${{ secrets.EC2_USERNAME}}
          key: ${{ secrets.EC2_PRIVATE_KEY }}
          script_stop: true
          script: |
            docker stop auctify_server || true
            docker rm auctify_server || true
            docker pull ${{ steps.login-ecr.outputs.registry }}/auctify_server:latest
            docker run -d --name auctify_server -p 8080:8080 ${{ steps.login-ecr.outputs.registry }}/auctify_server:latest

AWS에서 설정

ec2만들기 (rds도 만들자)

IAM에 권한 추가

  • AmazonEC2ContainerRegistryFullAccess 권한 추가하기
  •  

Ubuntu에서 Docker, Docker Compose 설치하기

sudo apt-get update && \
	sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && \
	curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \
	sudo apt-key fingerprint 0EBFCD88 && \
	sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
	sudo apt-get update && \
	sudo apt-get install -y docker-ce && \
	sudo usermod -aG docker ubuntu && \
	sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
	sudo chmod +x /usr/local/bin/docker-compose && \
	sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
	
# 잘 설치됐는 지 확인
$ docker -v # Docker 버전 확인
$ docker compose version # Docker Compose 버전 확인

ECR(Elastic Container Registry) 만들기

Ubuntu일 경우

$ sudo apt update
$ sudo apt install amazon-ecr-credential-helper

IAM Role을 활용해 EC2가 ECR에 접근할 수 있게 권한 부여하기

  • EC2에 연결되어 있는 IAM Role에 AmazonEC2ContainerRegistryFullAccess 정책 추가하기

Github Secrets and Variables

APPLICATION_PROPERTIES : allication-prod.yml 설정파일 그대로

AWS_ACCESS_KEY_ID : iam id

AWS_SECRET_ACCESS_KEY : iam pw

EC2_HOST : ec2주소

EC2_PRIVATE_KEY : pem

EC2_USERNAME : ubuntu 우분투일경우

+ Recent posts