프로젝트 개발 중 백엔드 Swagger를 먼저 배포하여 프론트엔드 로컬 환경에서 API를 테스트하려고 했다. AWS만 사용해봤던 나는 당연히 다른 플랫폼들(Railway, Koyeb, Render 등)도 백엔드와 프론트엔드를 모두 잘 지원할 거라 생각했다.
하지만 무료 배포 플랫폼을 찾아보는 과정에서 백엔드와 프론트엔드를 지원하는 플랫폼이 각각 다르다는 사실을 알게 되었다. 그리고 배포 후에는 HTTP/HTTPS, SSL 인증서, CORS 등 다양한 보안 이슈를 마주하게 되었다.
이번 포스팅에서는 플랫폼 선택부터 배포 환경에서 필수적인 보안 설정까지, 실제로 겪으며 배운 내용들을 정리해본다.
1. 백엔드와 프론트엔드, 왜 지원하는 플랫폼이 다를까?
백엔드와 프론트엔드의 근본적인 차이
백엔드와 프론트엔드는 동작 방식과 요구사항이 완전히 다르다.
프론트엔드의 특성
- 정적 파일 제공 (HTML, CSS, JavaScript)
- 빌드 결과물: build/ 폴더 내 정적 파일들
- CDN을 통한 빠른 전송이 핵심
- 사용자와의 물리적 거리를 최소화해야 함
- 트래픽이 많아도 캐싱으로 대응 가능
백엔드의 특성
- 동적 처리가 필요 (DB 조회, 비즈니스 로직 실행)
- 빌드 결과물: 실행 파일 (Java → JAR, Node.js → 번들)
- 24시간 서버가 실행되어야 함
- 메모리, CPU 등 컴퓨팅 리소스 필요
- 요청마다 새로운 연산 수행
플랫폼별 특화 방향
이러한 특성 차이 때문에 각 플랫폼은 특정 영역에 최적화되어 있다.
| 프론트엔드 특화 | 백엔드 특화 | 풀스택 특화 | |
| 대표 플랫폼 | Vercel, Netlify Cloudflare Pages |
Railway, Render Koyeb, Fly.io |
AWS, GCP, Azure |
| 핵심 기능 | - CDN 자동 배포 - 엣지 캐싱 - 빠른 정적 파일 서빙 |
- 컨테이너 실행 - 24시간 서버 운영 - DB 연결 지원 |
- 모든 서비스 제공 - 인프라 직접 구성 |
| 무료 제약 | 빌드 횟수 제한 대역폭 제한 |
실행 시간 제한 메모리 제한 슬립 모드 |
프리티어 존재 (사용량 기반 과금) |
내가 선택한 방향
- 백엔드: Koyeb (무료 플랜, 자동 HTTPS, 컨테이너 지원)
- 프론트엔드 (향후): Vercel 또는 Netlify (빠른 배포, CDN)
무료 플랫폼 선택 시 가장 중요한 건 각 플랫폼이 어떤 워크로드에 최적화되어 있는지 이해하는 것이다.
2. HTTP vs HTTPS, 왜 이게 문제가 될까?
배포 후 마주한 상황
백엔드를 Koyeb에 배포하니 자동으로 HTTPS가 적용되었다.
- 백엔드: https://api.myproject.com
- 프론트엔드: http://localhost:3000 (로컬 개발 환경)
단순히 API를 호출하면 되겠지라고 생각했지만, 브라우저는 이 두 환경의 차이를 민감하게 구분했다. CORS 에러부터 쿠키가 저장되지 않는 문제까지, 다양한 이슈들이 터져 나왔다.
HTTP와 HTTPS의 차이
HTTP (HyperText Transfer Protocol)
클라이언트 → [평문 데이터] → 서버
↑
중간에서 가로채기 가능
데이터 위변조 가능
- 데이터가 암호화되지 않음
- 80번 포트 사용
- 민감한 정보 전송 시 위험
HTTPS (HTTP Secure)
클라이언트 → [암호화된 데이터] → 서버
↑
SSL/TLS로 보호됨
제3자가 해독 불가
- SSL/TLS 프로토콜로 암호화
- 443번 포트 사용
- 데이터 무결성 보장
- 서버 신원 확인
SSL 인증서, 왜 필수일까?
SSL/TLS 인증서의 역할
- 암호화: 클라이언트와 서버 간 데이터를 제3자가 해독할 수 없게 암호화
- 인증: 서버가 신뢰할 수 있는 주체임을 증명 (인증 기관 CA가 보증)
- 무결성: 전송 중 데이터 변조를 감지하고 방지
왜 배포 시 필수인가?
- 브라우저 보안 정책: 최신 브라우저는 HTTPS가 아닌 사이트에 "주의 요함" 경고 표시
- 데이터 보호: 로그인 정보, API 토큰 등 민감한 데이터 전송 시 암호화 필수
- 최신 웹 API 요구사항: Service Worker, Geolocation 등 많은 웹 API가 HTTPS 환경에서만 동작
- SEO: 구글 등 검색 엔진이 HTTPS 사이트를 우선 순위로 평가
무료 배포 플랫폼의 SSL 지원
다행히 Koyeb, Railway, Render 같은 무료 배포 플랫폼은 Let's Encrypt를 사용해 SSL 인증서를 자동으로 발급하고 갱신해준다. 별도 설정 없이 배포만 하면 HTTPS가 활성화되는 것이 일반적이다.
3. Swagger는 잘 되는데 프론트엔드는 왜 안 될까?
배포 후 겪은 혼란
백엔드를 배포하고 Swagger를 열어보니 모든 API가 정상 작동했다.
Swagger에서 테스트: 완벽하게 동작
https://my-backend.koyeb.app/swagger-ui → API 호출 성공
"오! 잘 되네?"라고 생각하며 프론트엔드 로컬 환경에서 같은 API를 호출했더니...
로컬 프론트에서 호출: 빨간색 에러 폭격
Access to fetch at 'https://my-backend.koyeb.app/api/users'
from origin 'http://localhost:3000' has been blocked by CORS policy
"Swagger는 되는데 왜 프론트는 안 돼?" 이게 내가 며칠간 삽질한 핵심 질문이었다.
원인: Same-Origin vs Cross-Origin
문제는 Origin(출처) 개념에 있었다.
Origin = 프로토콜 + 도메인 + 포트
Swagger의 경우 (Same-Origin)
Swagger UI: https://my-backend.koyeb.app/swagger-ui
백엔드 API: https://my-backend.koyeb.app/api/users
Origin: https://my-backend.koyeb.app (동일!)
→ 같은 집 안에서 통신 → 제약 없음
로컬 프론트의 경우 (Cross-Origin)
프론트엔드: http://localhost:3000
백엔드 API: https://my-backend.koyeb.app/api/users
프론트 Origin: http://localhost:3000
백엔드 Origin: https://my-backend.koyeb.app
→ 서로 다른 집 → 보안 검문소(브라우저)를 거침!
브라우저의 Same-Origin Policy (동일 출처 정책)
브라우저는 보안을 위해 기본적으로 다른 출처 간의 리소스 공유를 차단한다.
악의적인 사이트가 사용자 모르게 다른 사이트에 요청을 보내는 것을 막기 위해서다.
Mixed Content와 쿠키 문제까지
Origin이 다른 것만으로도 문제인데, 여기에 추가로:
문제 1: Mixed Content
- HTTPS 페이지에서 HTTP 리소스 요청은 차단
- 다행히 내 경우는 HTTP(로컬) → HTTPS(배포)라서 허용됨
문제 2: 쿠키 정책
- 서로 다른 도메인 간 쿠키 전송은 SameSite=None 필요
- SameSite=None은 반드시 Secure=true (HTTPS) 와 함께 사용
- 로컬은 HTTP인데 Secure 쿠키를 받을 수 있을까?
4. 해결의 실마리: Spring Security 설정의 필요성
이 모든 문제는 Spring Security에서 명시적으로 허용해줘야 해결된다.
필요한 설정들
1. CORS 설정
// "이 출처들은 내 API 호출해도 돼!"
configuration.setAllowedOrigins(List.of(
"http://localhost:3000",
"https://my-front.vercel.app"
));
2. 쿠키 설정(프론트와 쿠키로 TOKEN 이용하기로 했기 때문에 쿠키를 설정)
// SameSite=None, Secure=true 설정
ResponseCookie cookie = ResponseCookie.from("token", value)
.sameSite("None")
.secure(true)
.build();
3. SecurityFilterChain 구성
// CORS 활성화, CSRF 비활성화 등
http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(csrf -> csrf.disable());
이 모든 설정은 다음 포스팅에서 실전 코드와 함께 자세히 다룰 예정이다.
마치며
백엔드 배포는 생각보다 고려할 게 많았다.
첫째, 백엔드와 프론트엔드는 근본적으로 다른 특성을 가지고 있고, 그에 따라 최적화된 플랫폼도 다르다는 것을 알게 되었다.
둘째, 대부분의 무료 배포 플랫폼이 자동으로 HTTPS를 제공하는 것은 큰 장점이지만, 이로 인해 로컬 개발 환경(HTTP)과의 연동에서 새로운 고려사항이 생긴다.
셋째, Swagger는 잘 되는데 프론트는 안 되는 이유가 바로 Origin 차이 때문이라는 것을 배웠다. Same-Origin과 Cross-Origin의 차이를 이해하는 것이 핵심이었다.
하지만 이론만으로는 부족했다. 실제로 로컬 프론트엔드에서 배포된 백엔드로 요청을 보내자마자 브라우저 콘솔은 빨간색 에러로 가득 찼다.
"CORS Policy Error"
"Cookie blocked due to SameSite policy"
다음 포스팅에서는 이 에러들을 하나씩 해결하며 완성한 Spring Security 설정 코드를 실전 중심으로 공유할 예정이다. 특히 CORS 설정, 쿠키의 SameSite와 Secure 속성, 그리고 SecurityFilterChain 구성까지 실제로 동작하는 코드와 함께 다뤄보겠다.
'Cloud & DevOps > Docker & CI CD' 카테고리의 다른 글
| Koyeb과 Docker를 활용한 Spring Boot 무료 배포기 (feat. Swagger 공유) (0) | 2026.01.10 |
|---|