๐ŸŒ™ ๋ณ„ ํ—ค๋Š” ๋ฐค: ERR_TOO_MANY_REDIRECTS์—์„œ JWT ์•”ํ˜ธํ™” ๋ฌธ์ œ๊นŒ์ง€

๊น€์ •๊ทœยท2025๋…„ 9์›” 17์ผ

๐Ÿ“… 2025๋…„ 9์›” 18์ผ ์˜ค์ „ 7์‹œ, ์šด์˜ ์„œ๋ฒ„ ์žฅ์•  ๋ฐœ์ƒ

ํ‰์†Œ์™€ ๊ฐ™์ด ์ปคํ”ผ ํ•œ ์ž”๊ณผ ํ•จ๊ป˜ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ™•์ธํ•˜๋˜ ์ค‘, ๋ณ„ ํ—ค๋Š” ๋ฐค ์„œ๋น„์Šค์— ์ ‘์†์ด ์•ˆ ๋˜๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—๋Š” ๋ฌด์ •ํ•˜๊ฒŒ๋„ ERR_TOO_MANY_REDIRECTS ์˜ค๋ฅ˜๋งŒ ๋ฐ˜๋ณต๋˜๊ณ  ์žˆ์—ˆ๋‹ค.

"์–ด์ œ๊นŒ์ง€ ์ž˜ ๋˜๋˜ ์‚ฌ์ดํŠธ๊ฐ€ ๊ฐ‘์ž๊ธฐ ์™œ...?"

๐Ÿ” ์ฒซ ๋ฒˆ์งธ ์šฉ์˜์ž: Nginx ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ค‘๋ณต

์ฒ˜์Œ์—๋Š” ๋‹น์—ฐํžˆ Nginx ์„ค์ • ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ์ตœ๊ทผ ๋ฐฐํฌ ๊ณผ์ •์—์„œ ๋ฉ”์ธ ์„œ๋ฒ„์™€ ํ”„๋ก ํŠธ์—”๋“œ์— ์žˆ๋Š” nginx.conf ํŒŒ์ผ ๋‘˜ ๋‹ค ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ฝ”๋“œ๊ฐ€ ์ค‘๋ณต๋˜์–ด ์žˆ์—ˆ๊ณ , API ํ‚ค๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ์šฐ๋ฆฌ ์›น์„œ๋น„์Šค ํŠน์„ฑ์ƒ ์ด๊ฒŒ ๊ทผ๋ณธ ์›์ธ์ผ ๊ฑฐ๋ผ ํ™•์‹ ํ–ˆ๋‹ค.

# ๊ธ‰ํ•˜๊ฒŒ Nginx ์„ค์ • ์ˆ˜์ •
vim /etc/nginx/nginx.conf
# ์ค‘๋ณต๋œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ทœ์น™ ์ œ๊ฑฐ
sudo systemctl reload nginx

๋‹คํ–‰ํžˆ ์ˆ˜์ • ํ›„ ์„œ๋น„์Šค๊ฐ€ ์ •์ƒํ™”๋˜์—ˆ๋‹ค. "์—ญ์‹œ Nginx ๋ฌธ์ œ์˜€๊ตฌ๋‚˜" ํ•˜๋ฉฐ ์•ˆ๋„์˜ ํ•œ์ˆจ์„ ์‰ฌ์—ˆ๋‹ค.

๐Ÿ˜ฑ ๋ฐ์ž๋ทฐ: ๋˜ ๋‹ค์‹œ ๋ฐœ์ƒํ•œ ๋™์ผ ์ฆ์ƒ

๋ฉฐ์น  ํ›„, ์„œ๋น„์Šค๊ฐ€ ์ž˜ ๊ตด๋Ÿฌ๊ฐ€๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋ฐฐํฌํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ...

๋˜ ๊ฐ™์€ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค!

์ด๋ฒˆ์—๋Š” ๋ธŒ๋ผ์šฐ์ € ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ๋กœ๊ทธ์—์„œ ๋” ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค:

2025-09-18T07:01:29.821+09:00 ERROR 1 --- [byeolnight] [main] 
Caused by: java.lang.IllegalArgumentException: 
Could not resolve placeholder 'app.security.jwt.secret' in value "${app.security.jwt.secret}"

"Nginx ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค... ์ง„์งœ ์›์ธ์€ ๋”ฐ๋กœ ์žˆ์—ˆ๊ตฌ๋‚˜."

๐Ÿ•ต๏ธ ์ง„์งœ ๋ฒ”์ธ์„ ์ฐพ์•„์„œ

"Config Server๋Š” ์‚ด์•„์žˆ๋Š”๋ฐ JWT๋งŒ ์ฃฝ์—ˆ๋‹ค?"

๋กœ๊ทธ๋ฅผ ์ž์„ธํžˆ ๋ณด๋‹ˆ ์ด์ƒํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค:

โœ… Located environment: name=byeolnight, profiles=[prod]
โœ… MySQL ๋น„๋ฐ€๋ฒˆํ˜ธ: ์ •์ƒ ๋ณตํ˜ธํ™”
โœ… Redis ๋น„๋ฐ€๋ฒˆํ˜ธ: ์ •์ƒ ๋ณตํ˜ธํ™”  
โœ… AWS API ํ‚ค๋“ค: ์ •์ƒ ๋ณตํ˜ธํ™”
โŒ JWT ์‹œํฌ๋ฆฟ: Could not resolve placeholder

"๋‹ค๋ฅธ ์•”ํ˜ธํ™”๋œ ์„ค์ •๋“ค์€ ๋ฉ€์ฉกํ•œ๋ฐ JWT ์‹œํฌ๋ฆฟ๋งŒ ์™œ...?"

๋ฏธ์Šคํ„ฐ๋ฆฌํ•œ ์•”ํ˜ธํ™” ๋ฐ์ดํ„ฐ

byeolnight-prod.yml ํŒŒ์ผ์„ ์—ด์–ด๋ณด๋‹ˆ JWT ์‹œํฌ๋ฆฟ์ด ์ด์ƒํ–ˆ๋‹ค:

# ์ •์ƒ์ ์ธ ๋‹ค๋ฅธ ์„ค์ •๋“ค
password: '{cipher}4f645acb62e6302d47f02b2d3b88c8cda3c90e64f91d042dc9ff2613955ba***'

# ๋ฌธ์ œ์˜ JWT ์‹œํฌ๋ฆฟ
jwt:
  secret: '{cipher}eaebecbd17000326cf1b0281b5e9b9c905f10300270c747f95207cea0c029d34***'

์ถ”๋ฆฌ ๊ฒฐ๊ณผ:

  • ํŒŒ์ผ ๋ณต์‚ฌ ๊ณผ์ •์—์„œ ์•”ํ˜ธํ™” ๋ฐ์ดํ„ฐ ์ผ๋ถ€ ์†์‹ค?
  • Git ์ปค๋ฐ‹ ์‹œ ์ธ์ฝ”๋”ฉ ๋ฌธ์ œ?
  • ๋‹ค๋ฅธ ์•”ํ˜ธํ™” ํ‚ค๋กœ ์•”ํ˜ธํ™”๋œ ์ด๋ ฅ?

"๋ฒ”์ธ์€... ์†์ƒ๋œ ์•”ํ˜ธํ™” ๋ฐ์ดํ„ฐ์˜€๋‹ค!"

๐Ÿš‘ ์‘๊ธ‰์ฒ˜์น˜: ์ผ๋‹จ ์‚ด๋ ค๋†“๊ณ  ๋ณด์ž

"ํ‰๋ฌธ์œผ๋กœ๋ผ๋„ ์ผ๋‹จ ์„œ๋น„์Šค๋ถ€ํ„ฐ ์‚ด๋ฆฌ์ž!"

์šด์˜ ์„œ๋น„์Šค๊ฐ€ ๋‹ค์šด๋œ ์ƒํ™ฉ์—์„œ ์›์ธ ๋ถ„์„๋ณด๋‹ค๋Š” ๋น ๋ฅธ ๋ณต๊ตฌ๊ฐ€ ์šฐ์„ ์ด์—ˆ๋‹ค.

# ์‘๊ธ‰์ฒ˜์น˜: JWT ์‹œํฌ๋ฆฟ์„ ํ‰๋ฌธ์œผ๋กœ ๋ณ€๊ฒฝ
jwt:
  secret: 'byeolnight-jwt-secret-key-2025-very-long-and-secure-key-for-production-use-only'
# ์„œ๋ฒ„ ์žฌ์‹œ์ž‘
docker-compose restart app

"ํœด... ์ผ๋‹จ ์„œ๋น„์Šค๋Š” ์‚ด์•„๋‚ฌ๋‹ค. ์ด์ œ ์ง„์งœ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•„๋ณด์ž."

๐Ÿ”ง ๊ทผ๋ณธ ํ•ด๊ฒฐ: Config Server๋กœ ์žฌ์•”ํ˜ธํ™”

"encrypt-simple.bat, ๋„ˆ๊ฐ€ ๋‚ด ๊ตฌ์›์ž๋‹ค!"

ํ‰๋ฌธ์œผ๋กœ ์ž„์‹œ ํ•ด๊ฒฐํ•œ ํ›„, ๋ณด์•ˆ์„ ์œ„ํ•ด ์ œ๋Œ€๋กœ ๋œ ์•”ํ˜ธํ™”๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

# 1๋‹จ๊ณ„: Config Server ์‹œ์ž‘
cd config-server
gradlew.bat bootRun

# 2๋‹จ๊ณ„: JWT ์‹œํฌ๋ฆฟ ์žฌ์•”ํ˜ธํ™”
encrypt-simple.bat "byeolnight-jwt-secret-key-2025-very-long-and-secure-key-for-production-use-only"

ํ„ฐ๋ฏธ๋„ ์ถœ๋ ฅ:

Encrypting: "byeolnight-jwt-secret-key-2025-very-long-and-secure-key-for-production-use-only"

8bab426a814eb620e297d3a336d22ebf6ede3b285003154b24898d87ba743416***[์ƒˆ๋กœ์šด ์•”ํ˜ธํ™” ํ‚ค ์ƒ์„ฑ๋จ]

"์ƒˆ๋กœ์šด ์•”ํ˜ธํ™” ํ‚ค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค! ์ด์ œ ์ด๊ฑธ๋กœ ๊ต์ฒดํ•˜์ž."

์ตœ์ข… ํ•ด๊ฒฐ: ์ƒˆ ์•”ํ˜ธํ™” ํ‚ค ์ ์šฉ

# byeolnight-prod.yml ์ตœ์ข… ์ˆ˜์ •
jwt:
  secret: '{cipher}8bab426a814eb620e297d3a336d22ebf6ede3b285003154b24898d87ba743416***'

๐ŸŽ‰ ํ•ดํ”ผ์—”๋”ฉ: ๋ณ„ ํ—ค๋Š” ๋ฐค์ด ๋‹ค์‹œ ๋น›๋‚ฌ๋‹ค

"๋“œ๋””์–ด ์ •์ƒ ๋กœ๊ทธ๊ฐ€ ๋–ด๋‹ค!"

# ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ํ›„ ๋กœ๊ทธ ํ™•์ธ
docker logs -f byeolnight-app-1

๊ธฐ๋‹ค๋ฆฌ๋˜ ์„ฑ๊ณต ๋กœ๊ทธ:

โœ… JwtAuthenticationFilter: Filter 'jwtAuthenticationFilter' configured for use
โœ… TomcatWebServer: Tomcat started on port 8080 (http)  
โœ… ByeolnightApplication: Started ByeolnightApplication in 28.808 seconds
โœ… ๋ณ„ ํ—ค๋Š” ๋ฐค์ด ๋‹ค์‹œ ์‚ด์•„๋‚ฌ์Šต๋‹ˆ๋‹ค! ๐ŸŒŸ

๊ฒ€์ฆ: ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์ •์ƒ ์ž‘๋™

  • โœ… JWT ํ† ํฐ ์ƒ์„ฑ/๊ฒ€์ฆ ์™„๋ฒฝ
  • โœ… ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ ์ •์ƒ
  • โœ… API ํ˜ธ์ถœ ์ธ์ฆ ์„ฑ๊ณต
  • โœ… ์†Œ์…œ ๋กœ๊ทธ์ธ (Google, Kakao, Naver) ์ •์ƒ
  • โœ… ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… WebSocket ์—ฐ๊ฒฐ ์„ฑ๊ณต

"์ด์ œ์•ผ ๋งˆ์Œ ๋†“๊ณ  ์ปคํ”ผ๋ฅผ ๋งˆ์‹ค ์ˆ˜ ์žˆ๊ฒ ๋‹ค... โ˜•"

๐Ÿ”ง ์‚ฌ์šฉ๋œ ๋„๊ตฌ ๋ฐ ๊ธฐ์ˆ 

Config Server ์•”ํ˜ธํ™” ๊ตฌ์กฐ

# Config Server (application.yml)
encrypt:
  key: byeolnight-config-encryption-key-2025!@#$%^&*()
  fail-on-error: false

์•”ํ˜ธํ™” ์Šคํฌ๋ฆฝํŠธ (encrypt-simple.bat)

@echo off
echo Encrypting: "%1"
curl -u config-admin:config-secret-2024 ^
  "http://localhost:8888/encrypt" ^
  -d "%1" ^
  -H "Content-Type: text/plain"

JWT ์„ค์ • ๊ตฌ์กฐ

@Component
public class JwtTokenProvider {
    public JwtTokenProvider(@Value("${app.security.jwt.secret}") String secret, 
                           StringRedisTemplate redisTemplate) {
        this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
        this.redisTemplate = redisTemplate;
    }
}

๐Ÿ“š ํ•™์Šต ํฌ์ธํŠธ

Spring Cloud Config ์•”ํ˜ธํ™” ํŠน์„ฑ

  • ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™” (AES) ์‚ฌ์šฉ
  • ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋งŒ๋ฃŒ ์—†์Œ (JWT์™€ ๋‹ค๋ฆ„)
  • ์•”ํ˜ธํ™” ํ‚ค ์ผ์น˜ ์‹œ ์–ธ์ œ๋“  ๋ณตํ˜ธํ™” ๊ฐ€๋Šฅ
  • ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์ค‘์š”

๋ฌธ์ œ ํ•ด๊ฒฐ ์ ‘๊ทผ๋ฒ•

  1. ์ฆ์ƒ vs ์›์ธ ๊ตฌ๋ถ„
  2. ๋‹ค๋ฅธ ์„ค์ •๊ณผ ๋น„๊ต ๋ถ„์„
  3. ๋‹จ๊ณ„๋ณ„ ๊ฒ€์ฆ (์ž„์‹œ โ†’ ์˜๊ตฌ ํ•ด๊ฒฐ)
  4. ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ํ•ด๊ฒฐ์ฑ… ์ ์šฉ

์šด์˜ ํ™˜๊ฒฝ ๊ณ ๋ ค์‚ฌํ•ญ

  • Config Server ๊ณ ๊ฐ€์šฉ์„ฑ ํ•„์š”
  • ์•”ํ˜ธํ™” ํ‚ค ๋ฐฑ์—… ๋ฐ ๊ด€๋ฆฌ
  • ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์•Œ๋ฆผ ์ฒด๊ณ„
  • ๋กค๋ฐฑ ๊ณ„ํš ์ˆ˜๋ฆฝ

๐Ÿš€ ํ–ฅํ›„ ๊ฐœ์„  ๋ฐฉ์•ˆ

1. ๋ชจ๋‹ˆํ„ฐ๋ง ๊ฐ•ํ™”

# Config Server Health Check
management:
  endpoints:
    web:
      exposure:
        include: health,info,decrypt

2. ์•”ํ˜ธํ™” ๊ฒ€์ฆ ์ž๋™ํ™”

# ๋ฐฐํฌ ์ „ ์•”ํ˜ธํ™” ๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ
validate-config.sh byeolnight prod

3. ๋ฐฑ์—… ์ „๋žต

  • Config ํŒŒ์ผ Git ์ด๋ ฅ ๊ด€๋ฆฌ
  • ์•”ํ˜ธํ™” ํ‚ค ์•ˆ์ „ํ•œ ์ €์žฅ์†Œ ๋ณด๊ด€
  • ๋ณต๊ตฌ ์ ˆ์ฐจ ๋ฌธ์„œํ™”

๐ŸŽ“ ์ด ์‚ฌ๊ฑด์—์„œ ๋ฐฐ์šด ๊ตํ›ˆ๋“ค

1. "์ฆ์ƒ๊ณผ ์›์ธ์€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค"

  • ์ฒ˜์Œ ERR_TOO_MANY_REDIRECTS๋Š” Nginx ๋ฌธ์ œ๋กœ ๋ณด์˜€์ง€๋งŒ
  • ์ง„์งœ ์›์ธ์€ JWT ์•”ํ˜ธํ™” ๋ฐ์ดํ„ฐ ์†์ƒ์ด์—ˆ๋‹ค
  • ๊ทผ๋ณธ ์›์ธ์„ ์ฐพ์ง€ ์•Š์œผ๋ฉด ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐ˜๋ณต๋œ๋‹ค

2. "Config Server ์•”ํ˜ธํ™”๋Š” ์ƒ๊ฐ๋ณด๋‹ค ์ทจ์•ฝํ•˜๋‹ค"

  • ํŒŒ์ผ ๋ณต์‚ฌ, Git ์ปค๋ฐ‹ ๊ณผ์ •์—์„œ ๋ฐ์ดํ„ฐ ์†์ƒ ๊ฐ€๋Šฅ
  • ์ •๊ธฐ์ ์ธ ์•”ํ˜ธํ™” ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์ด ํ•„์š”ํ•˜๋‹ค
  • ๋ฐฑ์—…๋œ ์•”ํ˜ธํ™” ํ‚ค ๊ด€๋ฆฌ์˜ ์ค‘์š”์„ฑ

3. "์‘๊ธ‰์ฒ˜์น˜ โ†’ ๊ทผ๋ณธํ•ด๊ฒฐ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค"

  • ์šด์˜ ์„œ๋น„์Šค ๋‹ค์šด ์‹œ: ๋น ๋ฅธ ๋ณต๊ตฌ ์šฐ์„ 
  • ์•ˆ์ •ํ™” ํ›„: ๋ณด์•ˆ์„ ๊ณ ๋ คํ•œ ๊ทผ๋ณธ ํ•ด๊ฒฐ
  • ํ‰๋ฌธ โ†’ ์žฌ์•”ํ˜ธํ™” ๋‹จ๊ณ„์  ์ ‘๊ทผ์ด ํšจ๊ณผ์ 

์—ํ•„๋กœ๊ทธ: ๊ทธ๋‚  ๋ฐค, ๋ณ„ ํ—ค๋Š” ๋ฐค ์„œ๋น„์Šค๋Š” ๋‹ค์‹œ ํ‰ํ™”๋กญ๊ฒŒ ์‚ฌ์šฉ์ž๋“ค์˜ ์šฐ์ฃผ ์ด์•ผ๊ธฐ๋ฅผ ๋‹ด์•„๋‚ด๊ณ  ์žˆ์—ˆ๋‹ค. ๋•Œ๋กœ๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ณณ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ, ์ฐจ๊ทผ์ฐจ๊ทผ ์›์ธ์„ ์ฐพ์•„ ํ•ด๊ฒฐํ•˜๋Š” ๊ณผ์ •์ด์•ผ๋ง๋กœ ๊ฐœ๋ฐœ์ž์˜ ์ง„์งœ ์‹ค๋ ฅ์ด ์•„๋‹๊นŒ? ๐ŸŒ™โœจ

profile
๊ธฐํš๊ณผ ์„ค๊ณ„ ๊ทธ๋ฆฌ๊ณ  ๊ตฌํ˜„๊นŒ์ง€ ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€