#WebSphere

[WebSphere] 실제 IP(Real IP) 인식 불가 해결: trustedHeaderOrigin 설정 가이드 (CVE-2012-5783 대응)

WebSphere Application Server(WAS)의 trustedHeaderOrigin 설정이 개선되었습니다. 기존에는 정확한 IP만 입력해야 했으나, 최신 픽스팩(9.0.5.7, 8.5.5.20)부터는 192.168.*.*와 같은 IP 세그먼트 와일드카드를 지원합니다. 유동 IP 환경에서의 설정법과 적용 버전을 정리합니다.

1. 업데이트 배경: IP 관리가 너무 힘들다?

기존에는 보안(CVE-2012-5783) 이슈로 인해 trustedHeaderOrigin에 앞단 웹 서버의 정확한 IP(Full IP)를 일일이 등록해야 했습니다.

하지만 클라우드(AWS, Azure)나 컨테이너(Docker/K8s) 환경에서는 L4/Web 서버의 IP가 수시로 변경되거나 대역으로 할당되므로, 모든 IP를 나열하는 것이 불가능했습니다. 이를 해결하기 위해 부분 와일드카드(IP Wildcard Segments) 지원이 추가되었습니다.


2. 와일드카드 지원 버전 (Target Fixpacks)

아래 버전 이상의 픽스팩(Fix Pack)이 적용된 환경에서는 IP 대역 설정이 가능합니다.

제품군 지원 시작 버전 (Minimum Version)
WAS 9.0 9.0.5.7 이상
WAS 8.5 8.5.5.20 이상
Liberty 21.0.0.2 이상
참고: 위 버전보다 낮은 경우 192.168.*.* 같은 입력을 인식하지 못하고 에러가 발생하거나 IP 인식이 실패할 수 있습니다.

3. 설정 가이드 (Configuration)

WAS 관리 콘솔에서 전송 채널의 사용자 정의 속성을 추가합니다.

설정 경로

  1. Servers > [서버명] > Web Container Settings > Web container transport chains
  2. 대상 체인 선택 (예: WCInboundDefault)
  3. HTTP Inbound Channel (HTTP_2) > Custom properties > New

속성 값 입력 예시 (New Feature)

이제 아래와 같이 유연한 설정이 가능합니다.

속성 이름 (Name) 값 (Value) 예시 설명
trustedHeaderOrigin

trustedSensitiveHeaderOrigin
10.10.*.* 10.10.0.0/16 대역의 모든 IP 신뢰 (추천)
192.168.1.*, 10.1.*.* 콤마(,)를 사용하여 여러 대역 동시 지정
*.ibm.com 호스트네임 기반의 와일드카드 지원
Best Practice:
과거에는 편의상 * (전체 허용)를 사용하는 경우가 많았으나, 이는 보안상 취약합니다.
이제는 10.10.*.* 처럼 내부망 IP 대역만 특정하여 허용함으로써 보안과 편의성을 모두 챙길 수 있습니다.

4. 웹 컨테이너 포트 인식 설정 (함께 적용)

IP 대역 설정과 함께, 호스트 헤더의 포트 정보를 올바르게 가져오기 위한 웹 컨테이너 설정도 잊지 마세요.

  • 위치: Web Container > Custom properties
  • 속성: com.ibm.ws.webcontainer.extractHostHeaderPort = true

5. 검증 (Verification)

  1. 설정 저장 후 WAS 재기동
  2. SystemOut.log에 별다른 에러 메시지가 없는지 확인
  3. 애플리케이션에서 request.getRemoteAddr() 호출 시 실제 클라이언트 IP가 출력되는지 확인
Open Stream →
#IBM HTTPServer

[IHS/WAS] 실제 클라이언트 IP(Real IP) 식별 가이드: mod_remoteip 설정 및 버전별 패치 현황 (9.0.5.13)

로드밸런서(L4/L7) 환경에서 실제 클라이언트 IP를 식별하기 위해 IBM HTTP Server(IHS) 9.0의 mod_remoteip를 설정하는 방법을 다룹니다. 특히 보안 감사 로그의 무결성을 위해 IHS 9.0.5.13 (APAR PH47286) 패치가 왜 중요한지, 그리고 버전별 로그 포맷 설정 차이점을 중점적으로 정리합니다.

0. 배경: 왜 IP가 바뀔까?

클라이언트가 로드밸런서(Proxy)를 거쳐 웹 서버에 접속하면, 웹 서버 입장에서는 연결을 요청한 주체가 로드밸런서이므로 Source IP가 로드밸런서 IP(예: 10.0.0.1)로 기록됩니다.

이는 다음과 같은 보안 문제를 야기합니다.

  • 접근 제어 실패: IP 기반의 ACL(Access Control List) 적용 불가
  • 감사 추적 불가: 사고 발생 시 실제 공격자의 IP를 로그에서 찾을 수 없음

1. 버전별 패치 및 로그 포맷 주의사항 (Version History)

IHS 설정에 앞서, 사용 중인 IHS 버전에 따라 로그 포맷 변수를 다르게 써야 하므로 버전 확인이 필수적입니다.

📢 핵심 패치 정보: APAR PH47286

적용 버전: IBM HTTP Server 9.0.5.13 이상

내용: 이전 버전에서는 mod_remoteip가 정상 작동해도, 기본 로그 변수인 %h가 여전히 프록시 IP를 출력하는 문제가 있었습니다. 9.0.5.13부터는 %hmod_remoteip에 의해 변경된 실제 IP를 반영하도록 수정되었습니다.

버전별 권장 로그 포맷

IHS 버전 Access Log 권장 변수 설명
9.0.5.12 이하 %a (Client IP) %h는 프록시 IP를 찍으므로 사용 금지. 반드시 %a 사용.
9.0.5.13 이상 %h 또는 %a 패치 적용됨. %h를 써도 실제 IP가 기록됨 (기존 설정 유지 가능).

2. IHS 설정 가이드 (httpd.conf)

Step 1: 모듈 활성화

# mod_remoteip 모듈 주석 해제
LoadModule remoteip_module modules/mod_remoteip.so

Step 2: 신뢰할 프록시 등록

보안을 위해 "누가 보내준 헤더를 믿을 것인가"를 명시해야 합니다. 아무 헤더나 믿으면 IP 스푸핑 공격에 당할 수 있습니다.

<IfModule mod_remoteip.c>
    # 1. 실제 IP가 담긴 헤더명 지정 (표준: X-Forwarded-For)
    RemoteIPHeader X-Forwarded-For

    # 2. 신뢰할 로드밸런서(L4/L7) IP 등록
    # 사설 IP 대역의 프록시인 경우 (10.x, 192.168.x 등)
    RemoteIPInternalProxy 10.0.0.1 10.0.0.2

    # 공인 IP 대역의 프록시인 경우
    # RemoteIPTrustedProxy 203.0.113.5
</IfModule>

Step 3: 로그 포맷 변경 (Access Log)

버전에 관계없이 가장 안전한 방법은 %a 변수를 사용하는 것입니다.

# [기존] common 포맷 (9.0.5.12 이하에서 문제 발생 가능)
# LogFormat "%h %l %u %t \"%r\" %>s %b" common

# [변경] %h -> %a 로 변경 (권장)
LogFormat "%a %l %u %t \"%r\" %>s %b" common

3. 검증 및 디버깅 (Validation)

설정 적용 후 실제로 헤더가 잘 변환되는지 확인하기 위해 임시로 로그를 상세하게 찍어봅니다.

# 디버깅용 로그 포맷 정의 (작업 후 주석 처리 권장)
# %{c}a : Connection IP (L4 IP)
# %a    : Client IP (변환된 실제 IP)
GlobalLog logs/remoteip_debug.log "L4-IP=%{c}a Real-IP=%a XFF-Header=%{X-Forwarded-For}i"

정상 결과 예시:

L4-IP=10.0.0.1 Real-IP=203.0.113.2 XFF-Header=203.0.113.2
  • L4-IP에는 로드밸런서 IP가 나와야 함
  • Real-IP에는 실제 사용자 PC의 IP가 나와야 함 (성공)

4. WAS(WebSphere) 추가 설정 필요 여부

IHS에서 mod_remoteip가 정상 작동하면, WAS 플러그인(Plugin)으로 넘어갈 때 이미 Source IP가 복원된 상태로 넘어갑니다. 따라서 WAS 쪽에서는 별도의 추가 설정 없이 request.getRemoteAddr() 호출 시 실제 IP를 획득할 수 있습니다.

(단, Plugin 설정의 TrustedProxyEnable 속성은 상황에 따라 검토가 필요할 수 있습니다.)

Open Stream →
#Liberty

[WebSphere Liberty] DB 연결 총정리: Oracle, DB2, MySQL, Tibero 데이터소스 설정 및 연결 테스트

IBM WebSphere Liberty에서 주요 데이터베이스(Oracle, DB2, MySQL, Tibero)와 연결하기 위한 JDBC 데이터소스 설정 방법을 정리합니다. adminCenter를 활용한 관리 환경 구성, 비밀번호 암호화, 그리고 restConnector를 이용한 연결 테스트까지의 전체 과정을 다룹니다.

0. 전제 조건 (Prerequisites)

  • Version: Liberty 25.x 이상 권장
  • Java: Java 8 (OpenJ9) 기준
  • 필수 기능(Feature): server.xml에 아래 피처들이 등록되어 있어야 합니다.
<featureManager>
    <feature>jdbc-4.3</feature>              <!-- JDBC 표준 지원 -->
    <feature>transportSecurity-1.0</feature> <!-- 암호화 비밀번호 사용 시 -->
    <feature>restConnector-2.0</feature>     <!-- 연결 테스트 API용 -->
    <feature>adminCenter-1.0</feature>       <!-- 관리 UI 및 통합 관리 -->
</featureManager>

1. JDBC 드라이버 준비 (Driver Setup)

각 DB 벤더에 맞는 JDBC 드라이버(JAR 파일)를 준비하여 Liberty 공용 리소스 디렉토리에 배치합니다.

DB 파일명 (예시) 다운로드 출처
Oracle ojdbc8.jar Oracle MOS 또는 Maven
DB2 db2jcc4.jar DB 서버의 /sqllib/java
MySQL mysql-connector-j-8.x.jar Maven Central
Tibero tibero6-jdbc.jar TmaxSoft 테크넷

디렉토리 생성 및 복사

관리 편의성을 위해 ${shared.resource.dir}(기본값: usr/shared/resources) 하위에 벤더별 폴더를 만들어 관리하는 것을 추천합니다.

# Oracle 예시
mkdir -p $WLP_HOME/usr/shared/resources/jdbc/oracle
cp ojdbc8.jar $WLP_HOME/usr/shared/resources/jdbc/oracle/

2. 공통 라이브러리 정의 (Library)

server.xml에서 위에서 배치한 JAR 파일을 참조하는 library 태그를 작성합니다.

<!-- Oracle 라이브러리 정의 -->
<library id="OracleLib">
    <fileset dir="${shared.resource.dir}/jdbc/oracle" includes="ojdbc*.jar"/>
</library>

3. 데이터소스 정의 (DataSource Configuration)

DB별로 설정 태그(properties)와 클래스명이 다르므로 주의해야 합니다.

Case A: Oracle Database

<dataSource id="OracleDS" jndiName="jdbc/oracleDS" statementCacheSize="60">
    <jdbcDriver libraryRef="OracleLib"
                javax.sql.ConnectionPoolDataSource="oracle.jdbc.pool.OracleConnectionPoolDataSource"/>
    <!-- URL 방식 연결 -->
    <properties.oracle URL="jdbc:oracle:thin:@//192.168.0.101:1521/ORCL"
                       user="scott" password="{aes}..." />
    <connectionManager maxPoolSize="50" connectionTimeout="6s"
                       reapTime="300" maxIdleTime="1800"/>
</dataSource>

Case B: IBM DB2

<dataSource id="DB2DS" jndiName="jdbc/db2" isolationLevel="TRANSACTION_READ_COMMITTED">
    <jdbcDriver libraryRef="DB2Lib"
                javax.sql.ConnectionPoolDataSource="com.ibm.db2.jcc.DB2ConnectionPoolDataSource"/>
    <properties.db2.jcc databaseName="SAMPLE" serverName="localhost" portNumber="50000"
                        user="db2inst1" password="{aes}..." />
</dataSource>

Case C: Tibero (Tmax)

국산 DB인 Tibero는 properties 태그가 별도로 없으므로 일반적인 속성 주입 방식을 사용하거나, Tibero 전용 프로퍼티를 명시해야 할 수 있습니다.

<dataSource id="TiberoDS" jndiName="jdbc/tibero" statementCacheSize="100">
    <jdbcDriver libraryRef="TiberoLib"
                javax.sql.ConnectionPoolDataSource="com.tmax.tibero.jdbc.ext.TbConnectionPoolDataSource"/>
    <!-- properties.tibero 태그 사용 -->
    <properties.tibero url="jdbc:tibero:thin:@192.168.0.111:8629:tibero"
                       user="admin" password="{aes}..." />
</dataSource>

4. 비밀번호 암호화 (Security)

설정 파일에 비밀번호를 평문으로 저장하는 것은 보안상 위험합니다. securityUtility를 이용해 AES로 암호화합니다.

암호화 실행

# 암호화 키 지정 (예: passw0rd)
$WLP_HOME/bin/securityUtility encode --encoding=aes --key=passw0rd 'DB_REAL_PASSWORD'
# 결과: {aes}AA6wcy4K2Xm...

키 등록 (bootstrap.properties)

서버가 암호를 복호화할 수 있도록 키를 등록해줍니다.

wlp.password.encryption.key=passw0rd

5. 연결 테스트 및 검증 (Validation)

서버를 기동한 후, REST API를 통해 데이터소스 연결 상태를 체크할 수 있습니다.

필수 확인 (Check Point):
해당 API를 호출하거나 웹 관리 콘솔(Admin Center)을 이용하기 위해서는 adminCenter-1.0restConnector-2.0 피처가 반드시 활성화되어 있어야 하며, 접근하는 계정에 관리자(Administrator) 권한이 있어야 합니다.

연결 테스트 명령어 (curl)

# 관리자 계정(admin)으로 인증 후 테스트 API 호출
curl -k -u admin:passw0rd \
  https://localhost:9443/ibm/api/validation/dataSource/OracleDS

성공 시: 200 OK와 함께 JSON 응답 내에 "Valid" 메시지가 포함됩니다.
실패 시: messages.log 파일에서 CWLLG2010E(로드 실패), CWNEN0034E(연결 실패) 등의 에러 코드를 확인합니다.


6. 트러블슈팅 체크리스트

  • ClassNotFoundException: library 경로 오타 또는 JAR 파일 권한(755) 확인
  • Connection Timeout: DB 방화벽(Port) 오픈 여부 확인
  • Authentication Failed: bootstrap.properties에 암호화 키가 올바르게 등록되었는지 확인
Open Stream →
#Liberty

[WebSphere Liberty] 설정 유연화의 핵심: 변수(Variable) 활용법 및 우선순위 완벽 정리

WebSphere Liberty의 설정 파일(server.xml)에서 포트 번호, DB 접속 정보 등을 하드코딩하지 않고 변수(Variable)로 관리하는 방법을 정리합니다. bootstrap.propertiesserver.xml, 환경 변수 간의 우선순위 규칙과 JDBC URL 설정 시 발생하는 슬래시(/) 정규화 문제를 해결하는 팁을 다룹니다.

0. 변수를 왜 사용해야 하나요?

서버 설정을 변수화하면 하나의 server.xml 파일을 여러 서버 인스턴스나 환경(Dev/Test/Prod)에서 공유할 수 있습니다. 변경되는 값(포트, IP 등)만 별도로 분리하여 관리 효율성을 높일 수 있습니다.


1. 변수 정의 위치 및 우선순위 (Precedence)

Liberty에서 변수를 정의할 수 있는 곳은 크게 세 군데입니다. 만약 같은 이름의 변수가 여러 곳에 정의되어 있다면, 아래 순서대로 덮어씌워집니다. (아래쪽이 우선순위 높음)

  1. 프로세스 환경 변수 (OS Environment Variables): 가장 낮은 우선순위
  2. bootstrap.properties: 환경 변수를 덮어씀
  3. server.xml (또는 include 된 xml): 가장 높은 우선순위 (최종 승자)
Best Practice:
서버별로 달라지는 고유 설정(예: HTTP 포트)은 bootstrap.properties에 정의하고, 여러 서버가 공유하는 공통 설정(예: DB 설정)은 included xml 파일에 정의하는 것이 좋습니다.

2. 변수 사용 방법 (Usage Guide)

Case A: bootstrap.properties 활용

서버 인스턴스 생성 시 자동으로 만들어지는 파일로, key=value 형태로 간단하게 정의합니다.

# bootstrap.properties
# 포트 번호 정의
http.port=8080
https.port=9443

Case B: server.xml 활용

<variable> 태그를 사용하여 정의하거나, 정의된 변수를 ${...} 문법으로 사용합니다.

<!-- 변수 정의 (Global) -->
<variable name="http.port" value="8080" />

<!-- 변수 사용 -->
<httpEndpoint id="defaultHttpEndpoint"
              httpPort="${http.port}"
              httpsPort="${https.port}" />

Case C: 환경 변수(Environment Variable) 활용

OS 환경 변수를 가져올 때는 env. 접두사를 사용합니다.

<!-- OS의 LIBRARY_DIR 환경 변수 사용 -->
<fileset dir="${env.LIBRARY_DIR}" includes="*.jar"/>

3. 고급 활용 팁 (Advanced Tips)

1) JDBC URL 슬래시(/) 정규화 문제 해결

Liberty 설정 파서(Parser)는 변수 값에 포함된 연속된 슬래시(//)를 단일 슬래시(/)로 정규화하는 특성이 있습니다. 이 때문에 JDBC URL 등이 깨질 수 있습니다.

해결책: 값을 두 부분으로 나누어 정의하거나, 이중 슬래시로 시작하게 합니다.

# [Bad] 이렇게 하면 jdbc:db2:/host.com 으로 변환되어 에러 발생
# DB_URL="jdbc:db2://host.com"

# [Good] 두 부분으로 나누어 결합
URL_PART_1="jdbc:db2:"
URL_PART_2="//host.com"
<dataSource ...>
    <properties.db2.jcc url="${URL_PART_1}${URL_PART_2}" />
</dataSource>

2) 리스트(List) 변수 처리

콤마(,)로 구분된 값을 단순 문자열이 아닌 리스트로 인식시키려면 ${list(...)} 함수를 사용합니다.

<variable name="ports" value="80,9080"/>

<!-- 문자열 "80, 9080"으로 인식 -->
<myConfig value="${ports}" /> 

<!-- 리스트 ["80", "9080"]으로 인식 -->
<myConfig value="${list(ports)}" />

3) 산술 연산 (Arithmetic)

포트 오프셋 등을 설정할 때 간단한 사칙연산(+, -, *, /)이 가능합니다.

<!-- 기본 포트(8080)에 1을 더해 8081로 설정 -->
<httpEndpoint id="secondaryEndpoint" httpPort="${http.port+1}" />

4. 변수 명명 규칙 (Naming Convention)

변수 이름은 반드시 알파벳(문자)으로 시작해야 하며, 아래 문자들만 포함할 수 있습니다.

  • 알파벳 문자 (Alphabetic characters)
  • 숫자 (Numeric characters)
  • 언더스코어 (_)
  • 점 (.)

Next Step:
이제 server.xml에서 하드코딩된 값을 제거하고 bootstrap.properties로 옮겨보십시오. 이를 통해 Docker 이미지 빌드나 여러 환경 배포 시 설정 관리가 훨씬 수월해질 것입니다.

Open Stream →
#Liberty

[WebSphere] Liberty Performance Tuning: 주요 구성 매개변수 가이드

Summary: WebSphere Liberty(Open Liberty) 환경에서 성능 최적화를 위해 조정 가능한 주요 매개변수를 정리한 문서입니다. JVM 힙 설정부터 Connection Pool, Executor, 그리고 유휴 자원 관리까지 server.xmljvm.options를 통한 튜닝 포인트를 다룹니다.

WebSphere Liberty는 기본적으로 자가 튜닝(Self-tuning) 기능을 갖추고 있으나, 운영 환경의 특성이나 애플리케이션의 워크로드 패턴에 따라 명시적인 설정 변경이 필요할 수 있습니다. 본 문서는 IBM Documentation을 기반으로 성능에 직접적인 영향을 주는 핵심 속성들을 정리했습니다.

1. JVM Tuning

가장 기본적이며 중요한 단계입니다. ${server.config.dir}/jvm.options 파일을 사용하여 설정합니다.

  • 개발 환경: 빠른 서버 시작을 위해 최소 힙(Min Heap)은 작게, 최대 힙(Max Heap)은 필요한 만큼 설정.
  • 운영 환경: 런타임 중 힙 크기 조정(Expansion/Contraction)에 따른 오버헤드를 제거하기 위해 최소 힙과 최대 힙을 동일한 값으로 설정하는 것을 권장합니다.

2. Transport Channel Service Tuning

클라이언트 연결, HTTP I/O 처리, 스레드 풀 및 연결 풀 관리를 담당하는 영역입니다. server.xml에서 설정합니다.

HTTP Options

SSL 핸드셰이크 비용이 높거나 처리량이 중요한 애플리케이션의 경우 지속적 연결(Persistent Connection) 설정을 최적화해야 합니다.

  • maxKeepAliveRequests: 단일 HTTP 연결에서 허용되는 최대 요청 수입니다. -1로 설정 시 무제한을 의미하며, 연결 맺는 비용을 절감할 수 있습니다.
<httpOptions maxKeepAliveRequests="-1" />

Connection Manager

데이터베이스 연결 풀(Connection Pool) 성능을 결정짓는 핵심 속성입니다.

  • maxPoolSize: 최대 실제 연결 수 (Default: 50). 모든 스레드가 DB 연결을 필요로 한다면 coreThreads와 1:1 매핑을 고려하십시오.
  • purgePolicy: Stale Connection 발견 시 처리 정책. 기본값은 EntirePool이나, FailingConnectionOnly로 설정하여 실패한 연결만 제거하는 것이 효율적입니다.
  • numConnectionsPerThreadLocal: 실행 스레드별로 DB 연결을 캐싱하여 락 경합(Contention)을 줄입니다. 멀티 코어 시스템에서 성능 향상에 유리합니다.
<connectionManager id="defaultConnectionManager" 
                   maxPoolSize="40" 
                   purgePolicy="FailingConnectionOnly" 
                   numConnectionsPerThreadLocal="1" />

Note: numConnectionsPerThreadLocal 사용 시, maxPoolSize는 (애플리케이션 스레드 수 × 스레드당 연결 수) 이상으로 설정해야 합니다.

3. Data Source Optimization

DB 쿼리 성능 및 데이터 무결성 수준을 조정합니다.

Statement Cache

PreparedStatement 캐싱을 통해 파싱 비용을 줄입니다. 애플리케이션에서 사용하는 고유한 SQL 문장 수보다 크게 설정해야 합니다.

<dataSource ... statementCacheSize="60" > ... </dataSource>

Isolation Level

데이터 무결성과 동시성(Concurrency)은 트레이드오프 관계입니다. isolationLevel 속성으로 조정합니다.

  • TRANSACTION_READ_UNCOMMITTED: 성능 최상, 무결성 최저 (Dirty Read 발생).
  • TRANSACTION_READ_COMMITTED: Dirty Read 방지.
  • TRANSACTION_REPEATABLE_READ: Dirty/Non-repeatable Read 방지.
  • TRANSACTION_SERIALIZABLE: 성능 최저, 무결성 최상 (완전한 직렬화).

4. Executor (Thread Pool) Tuning

Liberty의 Executor는 워크로드에 따라 스레드를 동적으로 조절하는 자가 튜닝 로직을 가지고 있습니다.

  • 기본 원칙: 특별한 문제가 없다면 설정을 변경하지 않는 것이 권장됩니다.
  • 예외 상황: 교착 상태(Deadlock) 해결 로직이 과도하게 작동하거나, 시스템 자원 한계로 스레드 수를 제한해야 할 경우 coreThreadsmaxThreads를 명시합니다.

5. Reducing Overhead & Startup Time

불필요한 CPU 사이클을 줄이고 기동 시간을 단축하기 위한 설정입니다.

Servlet Response Time

WebContainer가 정적 리소스 처리를 위해 META-INF 디렉토리를 스캔하는 과정을 생략합니다.

<webContainer skipMetaInfResourcesProcessing="true"/>

Idle Server CPU

운영 환경에서는 빈번한 애플리케이션/구성 파일 변경 감지가 불필요하므로, 모니터링 주기를 비활성화하거나 늘립니다.

<!-- 아예 비활성화 (권장) -->
<applicationMonitor dropinsEnabled="false" updateTrigger="disabled"/>
<config updateTrigger="disabled"/>

<!-- 혹은 MBean 트리거로 변경 및 폴링 주기 완화 -->
<applicationMonitor updateTrigger="mbean" pollingRate="60s"/>
<config updateTrigger="mbean" monitorInterval="60s"/>

CDI 1.2 Scanning

CDI 1.2 기능은 기본적으로 모든 아카이브를 스캔합니다. 대규모 애플리케이션에서 기동 속도 저하의 주원인이 되므로, 암시적 스캔(Implicit Bean Archives)을 비활성화합니다.

<cdi12 enableImplicitBeanArchives="false"/>

Next Step: 위 설정들은 워크로드의 특성에 따라 효과가 다릅니다. 운영 환경 적용 전, 부하 테스트를 통해 각 파라미터 변경에 따른 처리량(Throughput)과 응답 시간 변화를 측정하시기 바랍니다.

Open Stream →
#Liberty

[WebSphere] Liberty Cluster: End-to-End 구축 및 구성 가이드

Summary: WebSphere Liberty Profile(WLP)의 Collective 및 Cluster 기능을 활용한 인프라 구축 가이드입니다. Controller 구성부터 Member 조인, 클러스터링 설정 및 트러블슈팅까지의 전체 과정을 다룹니다.

WebSphere Application Server Liberty Profile(WLP)은 경량화된 구조와 확장성 덕분에 채택률이 높아지고 있습니다. 본 포스트는 WLP Collective와 Clustering 기능을 사용하여 확장 가능한 토폴로지를 구축하는 방법을 단계별로 정리한 엔지니어링 노트입니다.

이 시리즈는 다음 순서로 진행됩니다.

  • How to Create and Configure WebSphere Liberty Cluster End-to-End (Current)
  • How to Deploy Application in WebSphere Liberty Cluster
  • How to Setup Front-End Web Server for WebSphere Liberty Cluster

1. Topology Architecture

이 가이드에서는 Collective Controller 1대와 Collective/Cluster Member 2대로 구성된 토폴로지를 구현합니다. 프론트엔드에는 IBM HTTP Server(IHS)가 배치되며 별도의 배포 서버가 존재하는 구조입니다.

2. Prerequisites & WLP Installation

본 가이드는 WLP 17.0.2CentOS Linux 7.3 환경을 기준으로 작성되었습니다. 설치 전 지원되는 Java 버전이 설치되어 있는지 확인이 필요합니다.

Check System Environment

$> cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

$> ./java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build pxa6480sr4fp5-20170421_01(SR4 FP5))
IBM J9 VM (build 2.8, JRE 1.8.0 Linux amd64-64 Compressed References 20170419_344392)

Base Installation (Machine: 02)

먼저 Controller가 될 머신(Machine: 02)에 WLP를 설치하고 필요한 기능을 추가한 뒤, 이를 패키징하여 Member 서버들(Machine: 03, 04)로 배포하는 전략을 사용합니다.

# Create directory
$> sudo mkdir -p /opt/ibm

# Change ownership
$> sudo chown -R wasadmin:wasgrp /opt/ibm

# Install WLP
$> java -jar wlp-17.0.0.2-all.jar --acceptLicense /opt/ibm

# Verify version
$> cd /opt/ibm/wlp/bin
$> ./productInfo version
Product name: WebSphere Application Server
Product version: 17.0.0.2

Install Required Features

Collective, Cluster, SSL, JMX Connector 등의 필수 기능을 설치합니다.

$> ./installUtility install collectiveController-1.0 collectiveMember-1.0 clusterMember-1.0 websocket-1.1 restConnector-2.0 ssl-1.0 localConnector-1.0 adminCenter-1.0

Package and Distribute

설치된 환경을 wlp_install.jar로 패키징하여 다른 노드에 복제합니다.

# Create defaultServer for packaging context
$> ./server create

# Package server including all binaries
$> ./server package defaultServer --archive=/tmp/wlp_install.jar --include=all
Server defaultServer package complete in /tmp/wlp_install.jar.

생성된 wlp_install.jar를 Machine 03, 04로 전송한 후 동일하게 설치를 진행합니다.

# On Machine 03 & 04
$> sudo mkdir -p /opt/ibm
$> chown -R wasadmin:wasgrp /opt/ibm
$> java -jar wlp_install.jar --acceptLicense /opt/ibm

3. Setup Collective Controller (Machine: 02)

Controller 서버(wlpCntlr)를 생성하고 구성을 초기화합니다.

# Create server
$> ./server create wlpCntlr

# Initialize Collective Controller
$> ./collective create wlpCntlr --keystorePassword=<password> --createConfigFile=/opt/ibm/wlp/usr/servers/wlpCntlr/wlpcntlr_include.xml

위 명령어를 수행하면 인증서 생성 및 wlpcntlr_include.xml 설정 파일이 생성됩니다. 이후 server.xml과 include 파일을 다음과 같이 수정합니다.

Configuration: server.xml (Controller)

<server description="CollectiveController">
    <featureManager>
        <feature>adminCenter-1.0</feature>
        <feature>websocket-1.1</feature>
        <feature>restConnector-1.0</feature>
        <feature>localConnector-1.0</feature>
    </featureManager>

    <!-- Include generated config -->
    <include location="${server.config.dir}/wlpcntlr_include.xml" />

    <httpEndpoint id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443" host="*" />
</server>

Configuration: wlpcntlr_include.xml

자동 생성된 파일에서 quickStartSecurity 부분을 본인의 계정 정보로 수정합니다.

<quickStartSecurity userName="wasadmin" userPassword="{xor}EncryptedPassword..." />

Firewall Configuration

CentOS 방화벽에서 9080, 9443 포트를 허용해야 합니다.

$> sudo firewall-cmd --zone=public --permanent --add-port=9443/tcp
$> sudo firewall-cmd --zone=public --permanent --add-port=9080/tcp
$> sudo firewall-cmd --reload

Start Controller

$> ./server start wlpCntlr

로그(messages.log)에서 CWWKX6011I: The collective controller is ready 메시지를 확인합니다. Admin Center(https://hostname:9443/adminCenter/) 접속도 가능해야 합니다.

4. Setup Collective & Cluster Members

Machine 03과 04에서 멤버 서버를 생성하고 Controller에 Join 시킵니다.

Create & Join Member (Machine: 03)

# Create Server
$> ./server create wlpSrv01

# Join Collective
$> ./collective join wlpSrv01 \
  --host=waslibctlr01 \
  --port=9443 \
  --user=wasadmin \
  --password=<password> \
  --keystorePassword=<password> \
  --createConfigFile=/opt/ibm/wlp/usr/servers/wlpSrv01/wlpsrv01_include.xml

SSL Handshake 과정에서 인증서를 신뢰하겠냐는 프롬프트에 y를 입력합니다.

Configuration: server.xml (Member)

Member 서버의 server.xml에 Cluster 기능을 추가하고, Controller가 배포 관리를 할 수 있도록 remoteFileAccess를 설정합니다.

<server description="Cluster Member">
    <featureManager>
        <feature>webProfile-7.0</feature>
        <feature>restConnector-1.0</feature>
        <feature>localConnector-1.0</feature>
        <!-- Added for Clustering -->
        <feature>clusterMember-1.0</feature>
    </featureManager>

    <include location="${server.config.dir}/wlpsrv01_include.xml" />

    <!-- Define Cluster Name -->
    <clusterMember name="wlpCluster"/>

    <httpEndpoint id="defaultHttpEndpoint" httpPort="9081" httpsPort="9444" host="*" />

    <!-- Write Access for Controller -->
    <remoteFileAccess>
        <writeDir>${server.config.dir}</writeDir>
    </remoteFileAccess>
</server>

Machine: 04 (wlpSrv02)에 대해서도 위 과정을 동일하게 반복합니다.

Security Considerations (LTPA)

클러스터 환경에서 세션 공유 및 보안을 위해 모든 멤버는 동일한 LTPA 키를 사용해야 합니다. 한 서버에서 생성된 ltpa.keys 파일을 다른 멤버 서버들의 동일한 경로(${server.ouput.dir}/resources/security/)로 복사합니다.

5. Start Members & Verification

각 노드에서 멤버 서버를 시작합니다.

$> ./server start wlpSrv01  # On Machine 03
$> ./server start wlpSrv02  # On Machine 04

로그 파일에서 다음 메시지들을 확인하여 정상 구동을 검증합니다.

  • CWWKX8112I: Collective Repository에 호스트 정보 게시 성공.
  • CWWKX7400I: ClusterMember MBean 활성화 (클러스터 조인 성공).

6. Troubleshooting Notes

설정 과정에서 자주 발생하는 오류와 해결 방법입니다.

  • CWWKX0229E (401 Unauthorized / 403 Forbidden)
    collective join 시 인증 실패. quickStartSecurity의 계정 정보가 일치하는지 확인하십시오. 403 에러의 경우 해당 사용자가 administrator-role을 가지고 있는지 확인해야 합니다.
  • CWWKS9582E (SSL unresolved)
    IIOP 보안 설정 시 SSL 참조 오류. server.xml에 SSL 구성 및 KeyStore 정의가 명확한지 확인하십시오.
  • CWWKO0221E / CWWKS9580E (Port in use)
    한 호스트에 여러 인스턴스를 띄울 경우 JMS 포트(7276)나 IIOP 포트(2809) 충돌이 발생할 수 있습니다. wasJmsEndpointiiopEndpoint 설정을 통해 포트를 변경해야 합니다.

Next Step: 클러스터 구성이 완료되었습니다. 다음 포스트에서는 이 클러스터에 애플리케이션을 배포하는 방법을 다룹니다.

Open Stream →
#tomcat

[Tomcat] 주요 설정 파일(server.xml, web.xml) 완벽 분석 및 필수 튜닝 포인트

Apache Tomcat의 동작을 제어하는 핵심 설정 파일들은 모두 /conf 디렉토리에 위치합니다. 가장 중요한 server.xml(포트, 커넥터)과 web.xml(세션, MIME)의 역할과 자주 사용하는 설정 변경 가이드를 정리합니다.

1. 설정 파일 개요 (Configuration Overview)

Tomcat 설치 경로 내 conf 디렉토리에는 다음과 같은 주요 XML 파일들이 존재합니다.

파일명 주요 역할 및 설명
server.xml Tomcat의 메인 설정 파일입니다.
- HTTP/AJP 포트 설정
- 가상 호스트(Host) 및 Context 설정
- 쓰레드 풀(Thread Pool) 관리
web.xml 모든 웹 애플리케이션의 기본 속성을 정의합니다.
- 세션 타임아웃(Session Timeout) 설정
- MIME 타입 정의, 기본 서블릿 매핑
context.xml 웹 애플리케이션의 Context 설정을 담당합니다.
- JNDI 리소스(DB Connection Pool) 설정 시 주로 사용
tomcat-users.xml Tomcat Manager/Admin 페이지 접근 계정을 관리합니다.

2. server.xml 주요 설정 가이드

엔지니어가 가장 빈번하게 수정하는 파일입니다. 포트 충돌 해결이나 인코딩 처리를 위해 필수적으로 확인해야 합니다.

1) HTTP 포트 변경 및 인코딩 설정

기본 8080 포트를 80으로 변경하거나, 한글 깨짐 방지를 위해 URIEncoding을 설정합니다.

<!-- 기본 설정 -->
<Connector port="8080" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           redirectPort="8443" />

<!-- 튜닝 설정 예시 -->
<Connector port="80" protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           redirectPort="8443"
           URIEncoding="UTF-8" />
Tip: GET 방식으로 넘어오는 파라미터의 한글이 깨진다면 URIEncoding="UTF-8" 속성이 누락되었을 가능성이 큽니다.

2) AJP 포트 설정 (웹 서버 연동 시)

Apache HTTP Server와 연동할 때 사용하는 AJP 프로토콜 포트입니다. 사용하지 않는다면 주석 처리하여 보안을 강화하는 것이 좋습니다.

<!-- 기본값 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

3. web.xml 주요 설정 가이드

모든 애플리케이션에 적용되는 전역(Global) 설정을 담당합니다.

1) 세션 타임아웃 (Session Timeout)

사용자 세션 만료 시간을 설정합니다. (단위: 분)

<session-config>
    <session-timeout>30</session-timeout>
</session-config>

2) 디렉토리 리스팅 비활성화 (보안)

특정 디렉토리 접근 시 파일 목록이 노출되는 것을 방지하기 위해 listings 값을 false로 설정해야 합니다.

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value> <!-- true면 파일 목록 노출됨 -->
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

4. tomcat-users.xml (Manager App)

http://localhost:8080/manager 페이지에 접속하여 GUI로 애플리케이션을 배포하거나 중지하려면 계정 설정이 필요합니다.

<tomcat-users>
  <!-- 역할 정의 -->
  <role rolename="manager-gui"/>
  <role rolename="admin-gui"/>
  
  <!-- 사용자 정의 -->
  <user username="admin" password="password" roles="manager-gui,admin-gui"/>
</tomcat-users>
주의: Manager App은 강력한 권한을 가지므로, 운영 환경에서는 외부 IP 접근을 차단하거나 해당 기능을 비활성화하는 것을 권장합니다.

Next Step:
설정 파일 수정 후에는 반드시 Tomcat을 재기동해야 적용됩니다. 다음 단계에서는 실제 운영 환경에서 성능을 최적화하기 위한 JVM 메모리 설정(Heap Size)과 GC 튜닝 방법에 대해 알아보겠습니다.

Open Stream →
#Liberty

[IHS/Liberty] 보안 취약점 조치: X-Powered-By 헤더 숨김 및 정보 노출 방지 가이드

IBM HTTP Server(IHS)와 WebSphere Liberty 환경에서 X-Powered-By 헤더(예: Servlet/3.1) 노출을 차단하는 방법을 정리합니다. 보안 강화를 위해 웹 서버(IHS) 단에서의 필터링과 WAS(Liberty) 단에서의 생성 금지 설정을 모두 적용하는 것을 권장합니다.

0. 배경 및 전략 (Context)

보안 취약점 조치 시, 정보 노출 방지는 다계층 방어(Defense in Depth)가 중요합니다.

계층 역할 및 중요성
1. IHS (Web Server) [필수] 최전방 방어선. 백엔드 WAS가 무엇이든 상관없이 클라이언트로 나가는 모든 응답에서 헤더를 강제 삭제합니다.
2. Liberty (WAS) [권장] 소스 차단. 내부망에서 WAS로 직접 접속하는 경우나 웹 서버 설정을 우회하는 경우를 대비해 헤더 생성 자체를 막습니다.

Test Environment

  • Web Server: IBM HTTP Server v9.0 (Apache 2.4 Base)
  • WAS: WebSphere Liberty Core 20.0.x

1. IBM HTTP Server (IHS) 설정

Apache 기반인 IHS에서는 mod_headers 모듈을 사용하여 응답 헤더를 제어합니다.

httpd.conf 수정

설정 파일(httpd.conf)을 열어 아래 내용을 적용합니다.

# 1. 모듈 로드 확인 (주석 해제 필수)
LoadModule headers_module modules/mod_headers.so

# 2. 헤더 제거 설정 (Global 영역 또는 VirtualHost 내부에 작성)
<IfModule mod_headers.c>
    # 보안 조치: 기술 스택 정보 숨김
    Header unset X-Powered-By
    
    # (선택) 추가적인 정보 노출 헤더 차단
    Header unset X-AspNet-Version
    Header unset X-Runtime
</IfModule>

# 3. 서버 버전 정보 최소화 (OS 정보 등 숨김)
ServerTokens Prod
Tip: 설정 후에는 반드시 ./apachectl -t로 문법을 검사하고 재기동(restart 또는 graceful)해야 합니다.

2. WebSphere Liberty 설정

Liberty는 server.xml 파일 하나로 대부분의 설정을 처리합니다. webContainer 요소를 추가하거나 수정하여 헤더 생성을 비활성화합니다.

server.xml 수정

<server description="Liberty Server">

    <!-- Feature Manager (기본 설정) -->
    <featureManager>
        <feature>servlet-3.1</feature>
    </featureManager>

    <!-- [보안 조치] X-Powered-By 헤더 비활성화 속성 추가 -->
    <webContainer disableXPoweredBy="true" />

</server>

Liberty는 동적 설정을 지원하므로 파일 저장 시 즉시 반영되지만, 운영 환경에서는 확실한 적용을 위해 서버 재기동을 권장합니다.


3. 검증 (Verification)

curl 명령어를 사용하여 조치 전후의 응답 헤더를 비교합니다.

조치 전 (Before)

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1
Server: IBM_HTTP_Server/9.0.5...
...

조치 후 (After)

curl -I http://localhost:80/
HTTP/1.1 200 OK
Server: IBM_HTTP_Server   <-- (Prod 설정으로 버전 숨김)
Content-Type: text/html
...                       <-- (X-Powered-By 헤더 삭제됨)

Next Step:
헤더 조치가 완료되었다면, HTTP 메소드 제한(GET, POST 외 차단)SSL/TLS 프로토콜 버전(TLS 1.2 Only) 설정을 통해 웹 서비스 보안을 한 단계 더 강화해 보십시오.

Open Stream →
#apache

[Apache/IHS] 서버 성능 튜닝의 핵심: MaxRequestWorkers 계산법 및 MPM 설정 완벽 가이드

"사용자가 몰리면 서버가 응답이 없어요." 이런 문제의 90%는 동시 접속자 처리 설정인 MPM(Multi-Processing Module) 튜닝으로 해결됩니다. 물리 메모리 한계 내에서 최대 성능을 끌어내는 MaxRequestWorkers 설정법과 ServerLimit의 관계를 단계별로 정리합니다.

0. 튜닝의 핵심 공식 (The Formula)

튜닝은 '감'으로 하는 것이 아닙니다. 메모리 부족으로 인한 스왑(Swap) 발생을 막는 것이 최우선 목표이며, 이는 정확한 계산에서 시작됩니다.

MaxRequestWorkers = (총 RAM - OS/DB 사용 RAM) / (Apache 프로세스 1개의 평균 메모리)

1. 3단계 계산법: 내 서버의 한계값 찾기

Step 1: Apache 프로세스 평균 메모리 측정

먼저, 현재 구동 중인 httpd(또는 apache2) 프로세스 하나가 실제로 사용하는 메모리(RSS)의 평균을 구합니다.

# SSH 접속 후 실행 (결과 단위: MB)
ps -ylC httpd --sort:rss | awk '{sum+=$8; ++n} END {print "Average RSS: " sum/n/1024 " MB"}'

(예시 결과: 45.5 MB)

Step 2: Apache 가용 RAM 산정

서버의 전체 메모리에서 OS와 다른 애플리케이션(DB 등)이 사용하는 메모리를 제외합니다.

# 전체 메모리 확인
free -m

(예시: 16GB 서버에서 OS/DB가 6GB 사용 중 -> Apache용 가용 메모리 10GB (10,240 MB))

Step 3: 최종 설정값 도출

위에서 구한 값을 공식에 대입합니다.

  • 계산: 10,240 MB / 45.5 MB = 225.05
  • 결론: 소수점은 버리고 225MaxRequestWorkers 값으로 선정합니다.

2. 보이지 않는 벽: Limit 지시어의 이해

MaxRequestWorkers 값만 높인다고 끝이 아닙니다. 이 값은 상위 제한(Hard Limit) 설정인 ServerLimitThreadLimit 안에서만 유효합니다.

  • 규칙: MaxRequestWorkers ≤ (ServerLimit × ThreadsPerChild)

만약 계산된 값이 기본 한계(보통 ServerLimit 16)를 초과한다면, 반드시 설정 파일에 ServerLimit을 명시해야 합니다.


3. 튜닝 전략: 안정성 vs 효율성

Event/Worker MPM을 사용할 때, 성능을 높이는 방향은 두 가지입니다.

구분 ServerLimit 증가 (프로세스 ↑) ThreadsPerChild 증가 (스레드 ↑)
안정성 높음 (하나가 죽어도 나머지는 생존) 낮음 (스레드 하나가 죽으면 프로세스 전체 다운)
메모리 효율 낮음 (독립 메모리 필요) 높음 (메모리 공유)
권장 ✅ 적극 권장 ⚠️ 신중한 접근 필요 (보통 25~64 고정)

4. 최종 설정 예시 (httpd.conf)

위의 계산 결과(MaxRequestWorkers 1000 가정)를 바탕으로 한 Event MPM 최종 설정 예시입니다.

<IfModule mpm_event_module>
    # 1. 스레드 수는 안정적인 값으로 고정 (25)
    ThreadsPerChild         25

    # 2. 필요한 프로세스 수 계산 (1000 / 25 = 40)
    # 기본값(16)보다 크므로 반드시 명시해야 함
    ServerLimit             40

    # 3. 목표 동시 처리 수 (40 * 25 = 1000)
    MaxRequestWorkers       1000

    # 4. 기타 프로세스 관리 옵션
    StartServers            4
    MinSpareThreads         75
    MaxSpareThreads         250
    MaxConnectionsPerChild  0
</IfModule>
Check Point: 설정을 마친 후에는 반드시 apachectl -t 또는 httpd -t 명령어로 문법 오류가 없는지 확인하고 재기동해야 합니다.
Open Stream →
#mcp

[Node.js] Windows npm 실행 오류 해결: PowerShell 보안 정책(PSSecurityException) 설정 가이드

Windows 환경에서 npm 명령어를 실행할 때 발생하는 "이 시스템에서 스크립트를 실행할 수 없으므로..."(PSSecurityException) 오류를 해결합니다. PowerShell의 실행 정책(Execution Policy)을 이해하고, 보안을 유지하면서 npm을 사용할 수 있도록 RemoteSigned 정책을 적용하는 방법을 정리합니다.

1. 문제 현상 (Issue)

Node.js 설치 후 터미널(VS Code 또는 PowerShell)에서 npm 명령어를 실행하면 다음과 같은 빨간색 에러 메시지가 출력되며 실행이 차단됩니다.

에러 메시지

npm : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Program Files\nodejs\npm.ps1 파일을 로드할 수 없습니다.
위치 줄:1 문자:1
+ npm install
+ ~~~
    + CategoryInfo          : 보안 오류: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

2. 원인 분석 (Root Cause)

이것은 npm의 문제가 아니라 Windows PowerShell의 보안 정책 때문입니다.

  • Restricted (기본값): Windows 클라이언트 OS의 기본 정책으로, 모든 스크립트 파일(.ps1)의 실행을 차단합니다.
  • npm 명령어는 내부적으로 npm.ps1 스크립트를 실행하려다 이 정책에 막히게 됩니다.

3. 해결 방법 (Solution)

보안 정책을 변경하여 스크립트 실행을 허용해야 합니다. 보안과 편의성의 균형을 위해 RemoteSigned 정책을 현재 사용자(CurrentUser)에게만 적용하는 것을 권장합니다.

Step 1: 현재 정책 확인

PowerShell을 실행하고 아래 명령어를 입력합니다.

Get-ExecutionPolicy

결과가 Restricted로 나온다면 실행이 불가능한 상태입니다.

Step 2: 정책 변경 (권장 설정)

PowerShell을 관리자 권한으로 실행한 뒤, 아래 명령어를 입력합니다.

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
정책 설명:
  • RemoteSigned: 로컬에서 생성한 스크립트는 실행 허용, 인터넷에서 다운로드한 스크립트는 서명된 것만 허용 (가장 권장되는 설정).
  • -Scope CurrentUser: 시스템 전체가 아닌 현재 로그인한 사용자에게만 적용하여 보안 리스크 최소화.

변경 확인 메시지가 나오면 Y (예)를 입력하여 승인합니다.


4. 대안 및 팁 (Alternatives)

방법 A: 일회성 허용 (임시)

정책을 영구적으로 바꾸기 부담스럽다면, 현재 열려있는 창에서만 허용할 수 있습니다.

Set-ExecutionPolicy RemoteSigned -Scope Process

방법 B: Command Prompt (cmd) 사용

PowerShell이 아닌 일반 명령 프롬프트(cmd)Git Bash에서는 해당 보안 정책의 영향을 받지 않으므로, 별도 설정 없이 npm을 사용할 수 있습니다.


5. 검증 (Verification)

설정 후 다시 버전을 확인하거나 명령어를 실행하여 에러가 사라졌는지 확인합니다.

npm --version

Next Step:
이제 npm이 정상 작동하므로, npm install을 통해 필요한 패키지를 설치하거나 npx create-react-app 등의 프로젝트 생성 명령어를 실행해 보십시오.

Open Stream →