728x90
반응형
SMALL

도메인을 연결하기 위해서는 Certbot을 이용해야하기 때문에 우분투에 설치 먼저해줘야합니다.

  1. Certbot을 설치하고 업데이트하세요.
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

2. Certbot을 사용하여 인증서를 생성하세요.

sudo certbot --nginx

Certbot을 실행할 때 도메인 이름을 입력하라는 메시지가 표시됩니다. 여기에 도메인 이름을 입력하고 인증서 생성 프로세스를 완료하세요.

If you really want to skip this, you can run the client with
--register-unsafely-without-email but you will then be unable to receive notice
about impending expiration or revocation of your certificates or problems with
your Certbot installation that will lead to failure to renew.

Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): 이메일 주소

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
<https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf>. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

ubuntu@ip-172-31-46-142:~$ sudo certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel): 도메인이름
Requesting a certificate for 도메인이름

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/도메인이름/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/도메인이름/privkey.pem
This certificate expires on 2023-07-07.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for 도메인이름 to /etc/nginx/sites-enabled/default
Congratulations! You have successfully enabled HTTPS on 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   <https://letsencrypt.org/donate>
 * Donating to EFF:                    <https://eff.org/donate-le>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

저장된 위치를 메모장에 따로 기록해주세요! 

3. 생성된 인증서와 키의 경로를 확인하고, Nginx 구성 파일의 ssl_certificatessl_certificate_key 지시문에 올바른 경로를 설정하세요.

예를 들면, 다음과 같이 설정할 수 있습니다.

ssl_certificate /etc/letsencrypt/live/hype.r-e.kr/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hype.r-e.kr/privkey.pem;

4. Nginx 구성을 테스트하고, 문제가 없다면 다시 로드하여 변경 사항을 적용하세요.

sudo nginx -t
sudo systemctl reload nginx

 

5. 도메인이름과 도메인이름:8080을 확인해주세요~

확인 후 포트포워딩!!

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

확인하면 도메인 이름으로 스프링 부트가 적용이 된 것을 확인할 수 있습니다!

아직 https 로 리다이렉트를 하지 않아서 http 입니다~ 
그 후에는 로드벨런서 블루/ 그린을 적용할 예정입니다! (무중단 배포 화이팅..!!)

728x90
반응형
LIST

'개발 > sw' 카테고리의 다른 글

리눅스  (0) 2023.05.11
우분투 nginx(4) 리다이렉트  (0) 2023.04.15
우분투 nginx (2) 스프링부트 연결하기  (0) 2023.04.09
우분투 nginx (1) 설치 및 포트 변경  (0) 2023.04.09
http → https 리다이렉트 오류  (0) 2023.04.06
728x90
반응형
SMALL

무중단 배포를 하기 전 먼저 스프링부트를 연결을 연습을 했습니다.

서버 블록 작성

기본적으로 Ubuntu 시스템에서 Nginx 서버 블록 구성 파일은 /etc/nginx/sites-enable/ 디렉토리에 대한 심볼 링크를 통해 사용할 수 있는 /etc/nginx/sites-available/ 디렉토리에 저장됩니다.

원하는 편집기를 열고 다음 서버 블록 파일을 만듭니다.

/etc/nginx/sites-available/도메인이름.conf 의 파일을 만들기 위해서는 
앞에 sudo nano 를 붙여주면 수정이 가능하다!

sudo nano /etc/nginx/sites-available/도메인이름.conf

server {
        listen 80 default_server;
        listen [::]:80 default_server;
				root /var/www/html;
				index index.html index.htm index.nginx-debian.html;

        server_name 도메인 이름;

        location / {
^X Exition     M# First attempt to serve request as file, then  ^J Justify      ^
                # as directory, then fall back to displaying a 404.
                proxy_pass <http://인스턴스> IP 주소 ex) 127.0.0.0;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                try_files $uri $uri/ =404;
        }

작성 후
ctrl + ^ + x
ctrl + y
저장!

proxy_pass http://인스턴스 IP 주소 ex) 127.0.0.0;
여기에 사용할 인스턴스 주소를 넣고 저는 스프링 부트를 사용하기 때문에 127.0.0.0:8080을 넣어주면
엔진엑스와 스프링 부트 연결이 됩니다!

재시작은 필수!!

sudo systemctl reload nginx

상태확인!

sudo systemctl status nginx.service


127.0.0.0에 접속 했을 때 엔진엑스 화면이 나오고 

127.0.0.0:8080에 접속했을 때 흔히 보이는 화면이 나옵니다.

저는 시큐리티를 사용하고 따로 필터에서 제외를 해주지 않았기 때문에 127.0.0.0:8080/login 화면으로 확인했습니다!

이 두개를 하나로 합치기 위해 포트포워딩이 필요합니다! -> 도메인 연결하고 나서 하는 걸 추천 합니다! 헷깔려요...!!

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

 

728x90
반응형
LIST
728x90
반응형
SMALL
  1. WebSocket 설정

WebSocket을 활성화 하기 위해 @EnableWebSocket 어노테이션을 사용합니다.

javaCopy code
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatHandler(), "/chat/{roomId}")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Bean
    public WebSocketHandler chatHandler() {
        return new ChatHandler();
    }
}

2. WebSocket Handler 구현

WebSocket 메시지를 처리하는 핸들러를 구현합니다. 아래는 간단한 예시입니다.

javaCopy code
public class ChatHandler extends TextWebSocketHandler {

    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String roomId = getRoomId(session);
        sessions.put(roomId, session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String roomId = getRoomId(session);
        TextMessage msg = new TextMessage("[" + roomId + "] " + message.getPayload());
        broadcast(roomId, msg);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String roomId = getRoomId(session);
        sessions.remove(roomId);
    }

    private String getRoomId(WebSocketSession session) {
        return session.getUri().getPath().split("/")[2];
    }

    private void broadcast(String roomId, TextMessage message) throws IOException {
        for (WebSocketSession session : sessions.values()) {
            if (session.isOpen() && roomId.equals(getRoomId(session))) {
                session.sendMessage(message);
            }
        }
    }
}

3. 인증 및 권한 부여

스프링 시큐리티를 사용하여 인증과 권한 부여를 구현할 수 있습니다. 아래는 간단한 예시입니다.

javaCopy code
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .apply(new JwtConfigurer(jwtTokenProvider));
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

4. 토큰 기반 인증

로그인 후에 클라이언트는 서버로부터 JWT 토큰을 받아서 이를 이용하여 채팅방에 접근할 수 있습니다. 아래는 간단한 예시입니다.

@PostMapping("/login")
public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {

    Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(
                    loginRequest.getUsername(),
                    loginRequest.getPassword()
            )
    );

    SecurityContextHolder.getContext().setAuthentication(authentication);

    String jwt = jwtTokenProvider.generateToken(authentication);
    return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
}

로그인 성공시 JWT 토큰을 반환하는 응답 클래스를 정의합니다.

javaCopy code
public class JwtAuthenticationResponse {

    private String accessToken;

    public JwtAuthenticationResponse(String accessToken) {
        this.accessToken = accessToken;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }
}

JWT 토큰을 생성하는 유틸리티 클래스를 구현합니다.

javaCopy code
@Component
public class JwtTokenProvider {

    @Value("${app.jwtSecret}")
    private String jwtSecret;

    @Value("${app.jwtExpirationInMs}")
    private int jwtExpirationInMs;

    public String generateToken(Authentication authentication) {

        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();

        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);

        return Jwts.builder()
                .setSubject(Long.toString(userPrincipal.getId()))
                .setIssuedAt(new Date())
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public Long getUserIdFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody();

        return Long.parseLong(claims.getSubject());
    }

    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException ex) {
            logger.error("Invalid JWT signature");
        } catch (MalformedJwtException ex) {
            logger.error("Invalid JWT token");
        } catch (ExpiredJwtException ex) {
            logger.error("Expired JWT token");
        } catch (UnsupportedJwtException ex) {
            logger.error("Unsupported JWT token");
        } catch (IllegalArgumentException ex) {
            logger.error("JWT claims string is empty.");
        }
        return false;
    }
}

5. 채팅방 구현

WebSocket 세션 ID를 이용하여 각 채팅방을 구분합니다. 채팅방은 각 사용자별로 생성되며, 클라이언트는 채팅방의 ID를 이용하여 특정 채팅방에 접속합니다.

javaCopy code
@RestController
@RequestMapping("/api/chat")
public class ChatController {

    @MessageMapping("/{roomId}")
    @SendTo("/topic/{roomId}")
    public ChatMessage sendMessage(@DestinationVariable String roomId, ChatMessage message) {
        return message;
    }
}

6. 데이터베이스 저장

채팅방에서 주고받은 메시지를 데이터베이스에 저장할 수 있습니다. 메시지 모델과 메시지 레파지

토리를 구현합니다.

javaCopy code
@Repository
public interface MessageRepository extends JpaRepository<Message, Long> {

    List<Message> findAllByRoomIdOrderByCreatedAtAsc(Long roomId);
}

7. UI 구현

웹 브라우저에서 채팅방을 사용할 수 있는 UI를 구현합니다. 아래는 간단한 예시입니다.

htmlCopy code
<!DOCTYPE html>
<html>
<head>
    <title>Chat Room</title>
    <script src="/webjars/sockjs-client/1.0.2/sockjs.min.js"></script>
    <script src="/webjars/stomp-websocket/2.3.3/stomp.min.js"></script>
    <script>
        var stompClient = null;

        function connect() {
            var socket = new SockJS('/chat');
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function (frame) {
                console.log('Connected: ' + frame);
                stompClient.subscribe('/topic/' + roomId, function (message) {
                    showMessage(JSON.parse(message.body));
                });
            });
        }

        function sendMessage() {
            var message = document.getElementById("message").value;
            stompClient.send("/app/chat/" + roomId, {}, JSON.stringify({content: message}));
            document.getElementById("message").value = "";
        }

        function showMessage(message) {
            var messageArea = document.getElementById("messageArea");
            messageArea.innerHTML += message.content + "\\n";
        }

        window.onload = function () {
            connect();
        };
    </script>
</head>
<body>
<div>
    <h1>Chat Room</h1>
    <p>Room ID: <span id="roomId"></span></p>
    <textarea id="messageArea" rows="10" cols="50"></textarea>
    <br>
    <input type="text" id="message" name="message">
    <button onclick="sendMessage()">Send</button>
</div>
<script>
    var urlParams = new URLSearchParams(window.location.search);
    var roomId = urlParams.get('roomId');
    document.getElementById("roomId").innerHTML = roomId;
</script>
</body>
</html>

 

728x90
반응형
LIST

'개발 > Spring' 카테고리의 다른 글

웹소캣 - 채팅 기본 구현 (테스트 코드 연습)  (0) 2023.04.09
웹소켓 알림 메세지 - session  (0) 2023.04.09
yml 파일이란 ?  (0) 2023.03.12
WebSock 구현  (0) 2023.03.07
JWT 장점과 단점  (0) 2023.02.15

+ Recent posts