Spring Boot 앱의 정적 HTML 파일 url .html 없애기. (프론트와 백 서버 나누기)


Spring Boot 앱의 정적 HTML 파일(예: login.html)을 URL에서 .html 없이 작동하도록 설정하고 싶었습니다 (예: https://syoo.shop/login 대신 https://syoo.shop/login.html). 이를 위해 서버 사이드 렌더링을 하지 않는 이상, 정적 파일은 프론트엔드와 백엔드가 다른 서버에 있어야 원활하게 가능하다는 것을 알게 되었습니다.


선택한 방법

방법:
  • Nginx를 사용해 /var/www/html/에서 정적 파일을 .html 없이 제공.
  • Spring Boot는 API (/api/)와 WebSocket (/websocket)용으로 유지, Nginx가 해당 요청을 Spring Boot로 전달.
  • Spring Boot의 src/main/resources/static/에 있던 모든 정적 파일(HTML, JS, CSS, 이미지)을 /var/www/html/로 이동.
  • localStorage를 활용한 리다이렉트를 처리하는 index.html 생성.
  • 사용자 경험 개선을 위해 커스텀 에러 페이지 추가.

구현 과정

1. 모든 정적 파일을 /var/www/html/로 이동
  • Spring Boot의 정적 폴더에서 Nginx가 제공할 위치로 파일 이동 시작:
  • 디렉토리 생성 (없을 경우):
    sudo mkdir -p /var/www/html
  • Spring Boot 프로젝트에서 모든 정적 파일(HTML, JS, CSS, 이미지 등) 복사:
    sudo cp -r /path/to/my/spring-boot-project/src/main/resources/static/* /var/www/html/
  • Nginx가 파일을 읽을 수 있도록 권한 설정:
    sudo chown -R www-data:www-data /var/www/htmlsudo chmod -R 755 /var/www/html
2. Nginx 설정으로 정적 파일 제공 및 Spring Boot로 프록시
  • Nginx 설정 파일을 편집해 프론트엔드-백엔드 분리 설정:
  • 파일 열기:
    sudo vim /etc/nginx/sites-available/default
  • Nginx 설정 업데이트:
    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 / {
                      try_files $uri $uri/ =404;
                      }
                  }
    
    server {
                      
                      server_name syoo.shop www.syoo.shop;
                      
                      root /var/www/html;
                      index index.html;
                      
                      location =/ {
                      try_files /index.html =404;
                      }
                      
                      location / {
                      try_files $uri $uri.html =404;
                      }
                      # Proxy API requests to Spring Boot
                      location /api/ {
                      proxy_pass http://127.0.0.1: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;
                      proxy_intercept_errors on; # 백엔드 에러 가로채기
                      }
                      
                      location /websocket {
                      proxy_pass http://127.0.0.1:8080; # WebSocket 서버 위치
                      proxy_http_version 1.1;
                      proxy_set_header Upgrade $http_upgrade;
                      proxy_set_header Connection 'upgrade';
                      proxy_set_header Host $host;
                      proxy_cache_bypass $http_upgrade;
                      }
                      error_page 400 /400.html;
                      error_page 401 /401.html;
                      error_page 403 /403.html;
                      error_page 404 /404.html;
                      error_page 405 /405.html;
                      error_page 500 /500.html;
                      error_page 503 /503.html;
                      
                      listen 443 ssl; # Certbot 관리
                      listen [::]:443 ssl ipv6only=on; # Certbot 관리
                      ssl_certificate /etc/letsencrypt/live/syoo.shop/fullchain.pem; # Certbot 관리
                      ssl_certificate_key /etc/letsencrypt/live/syoo.shop/privkey.pem; # Certbot 관리
                      include /etc/letsencrypt/options-ssl-nginx.conf; # Certbot 관리
                      ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Certbot 관리
                      }
                      
    server {
                      if ($host = www.syoo.shop) {
                      return 301 https://$host$request_uri;
                      } # Certbot 관리
                      
                      if ($host = syoo.shop) {
                      return 301 https://$host$request_uri;
                      } # Certbot 관리
                      
                      listen 80;
                      listen [::]:80;
                      
                      server_name syoo.shop www.syoo.shop;
                      return 404; # Certbot 관리
                      }
                    
  • /var/www/html 디렉토리의 HTML로 에러 렌더링을 위해 다음 줄을 listen 443 ssl; 전에 추가:
    
                      error_page 400 /400.html;
                      error_page 401 /401.html;
                      error_page 403 /403.html;
                      error_page 404 /404.html;
                      error_page 405 /405.html;
                      error_page 500 /500.html;
                      error_page 503 /503.html;
                    
  • location /api/ 안에 추가:proxy_intercept_errors on;
  • Nginx 테스트 및 재로드:
    sudo nginx -tsudo nginx -s reload
3. 루트 리다이렉트를 위한 index.html 설정
  • index.html 파일 내용:
    
                      <!DOCTYPE html>
                      <html lang="en">
                      <head>
                      <meta charset="UTF-8">
                      <title>Welcome to Let's Chat!</title>
                      </head>
                      <body>
                      <script>
                      // localStorage에서 userId 확인
                      const userId = localStorage.getItem('userId');
                      
                      if (userId === null || userId === '') {
                      // userId 없음, 로그인으로 리다이렉트
                      window.location.href = 'https://syoo.shop/login';
                      } else {
                      // userId 있음, 채팅 목록으로 리다이렉트
                      window.location.href = 'https://syoo.shop/chat-list';
                      }
                      </script>
                      </body>
                      </html>
                    

결과 :

  • https://syoo.shop/login 같은 URL이 .html 없이 작동.
  • 모든 정적 파일이 /var/www/html/에서 로드됨.
  • https://syoo.shop/localStorage를 사용해 리다이렉트.
  • API와 WebSocket이 Spring Boot와 연동.
  • 에러가 커스텀 페이지로 표시됨.

Posted on 2025.03.07