🔐 환경변수 관리
📖 정의
**환경변수(Environment Variables)**는 애플리케이션의 동작을 제어하는 설정값으로, 코드 외부에서 관리됩니다. API 키, 데이터베이스 비밀번호, 서버 포트 등 민감한 정보를 코드에 직접 작성하지 않고, .env 파일이나 배포 플랫폼의 설정으로 관리합니다. 개발(dev), 스테이징(staging), 프로덕션(production) 환경마다 다른 값을 사용할 수 있습니다.
🎯 비유로 이해하기
옷장의 보석 금고
환경변수를 금고에 비유하면:
코드 = 공개된 옷장
├─ 누구나 볼 수 있음
└─ GitHub에 업로드됨
환경변수 = 비밀 금고
├─ 본인만 비밀번호 알고 있음
├─ 코드와 분리
└─ 절대 공개하지 않음
API 키 = 보석
├─ 코드에 직접 놓으면: 도난 위험!
└─ 금고에 보관하면: 안전!
.env 파일 = 금고 열쇠
├─ 로컬에만 보관
├─ .gitignore로 보호
└─ 절대 GitHub에 올리지 않음
레스토랑 레시피
공개 레시피 = 코드
├─ 요리 순서
├─ 재료 목록
└─ 조리 방법
비밀 소스 = 환경변수
├─ 정확한 비율
├─ 특별한 재료
└─ 경쟁사가 모르는 정보
환경별 차이:
- 개발 주방: 저렴한 재료로 테스트
- 프로덕션 주방: 최고급 재료 사용
- 각 주방의 비밀 소스는 다름!
⚙️ 작동 원리
1. 환경변수의 필요성
// ❌ 나쁜 예 (하드코딩)
const API_KEY = 'sk_live_abc123xyz789'; // GitHub에 노출!
const DATABASE_URL = 'mongodb://admin:password123@server.com/db';
// 문제점:
// 1. 코드가 GitHub에 공개되면 API 키 노출
// 2. 환경마다 값을 바꾸려면 코드 수정 필요
// 3. 팀원들과 공유 시 보안 위험
// 4. 키 변경 시 코드 재배포 필요
// ✅ 좋은 예 (환경변수)
const API_KEY = process.env.API_KEY;
const DATABASE_URL = process.env.DATABASE_URL;
// 장점:
// 1. 코드에 비밀 정보 없음
// 2. 환경별로 다른 값 사용
// 3. 키 변경 시 코드 수정 불필요
// 4. .env 파일로 로컬 관리
2. 환경변수 로딩 과정
1. 애플리케이션 시작
└─ node server.js
2. dotenv 라이브러리 로드
└─ require('dotenv').config()
3. .env 파일 읽기
└─ API_KEY=abc123
4. process.env에 주입
└─ process.env.API_KEY = 'abc123'
5. 코드에서 접근
└─ const key = process.env.API_KEY
6. 사용
└─ API 호출 시 key 사용
3. 환경별 설정
개발 환경 (Development)
├─ .env.local 또는 .env.development
├─ 로컬 데이터베이스
├─ 테스트용 API 키
├─ 디버그 모드 ON
└─ localhost:3000
스테이징 환경 (Staging)
├─ 배포 플랫폼 환경변수
├─ 테스트 데이터베이스
├─ 샌드박스 API 키
├─ 프로덕션과 유사한 환경
└─ staging.myapp.com
프로덕션 환경 (Production)
├─ 배포 플랫폼 환경변수
├─ 실제 데이터베이스
├─ 실제 API 키
├─ 에러 로깅 ON
└─ myapp.com
💡 실제 예시
Step 1: .env 파일 기본 사용법
# 프로젝트 생성
mkdir env-demo
cd env-demo
npm init -y
# dotenv 패키지 설치
npm install dotenv
# 추가 패키지 (API 호출 예제용)
npm install express axios
# .env 파일 생성 (루트 디렉토리)
cat > .env << 'EOF'
# Server Configuration
PORT=3000
NODE_ENV=development
# Database
DATABASE_URL=mongodb://localhost:27017/myapp
DATABASE_NAME=myapp_dev
# API Keys
OPENAI_API_KEY=sk-abc123xyz789
STRIPE_SECRET_KEY=sk_test_abc123
STRIPE_PUBLIC_KEY=pk_test_xyz789
# External Services
SENDGRID_API_KEY=SG.abc123xyz789
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_REGION=us-east-1
# JWT
JWT_SECRET=my-super-secret-jwt-key-change-in-production
JWT_EXPIRE=7d
# URLs
FRONTEND_URL=http://localhost:3000
BACKEND_URL=http://localhost:5000
# Feature Flags
ENABLE_LOGGING=true
ENABLE_ANALYTICS=false
MAX_FILE_SIZE=5242880
EOF
# ⚠️ 중요: .gitignore에 추가!
cat > .gitignore << 'EOF'
node_modules/
.env
.env.local
.env.*.local
*.log
.DS_Store
EOF
// server.js
require('dotenv').config(); // 맨 위에 추가!
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// 환경변수 사용
app.get('/', (req, res) => {
res.json({
message: 'Environment Variables Demo',
environment: process.env.NODE_ENV,
port: PORT,
databaseName: process.env.DATABASE_NAME,
// ⚠️ 주의: 실제로는 비밀 키를 응답으로 보내지 마세요!
jwtConfigured: !!process.env.JWT_SECRET,
loggingEnabled: process.env.ENABLE_LOGGING === 'true'
});
});
// API 키 사용 예시
app.get('/api/data', async (req, res) => {
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) {
return res.status(500).json({
error: 'API key not configured'
});
}
// API 호출 (실제 예시)
try {
// const response = await callExternalAPI(apiKey);
res.json({
message: 'API key is configured',
keyPrefix: apiKey.substring(0, 7) + '...' // 일부만 표시
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(PORT, () => {
console.log(`✅ Server running on port ${PORT}`);
console.log(`📝 Environment: ${process.env.NODE_ENV}`);
console.log(`🗄️ Database: ${process.env.DATABASE_NAME}`);
});
# 서버 실행
node server.js
# 출력:
# ✅ Server running on port 3000
# 📝 Environment: development
# 🗄️ Database: myapp_dev
# 테스트
curl http://localhost:3000
# {
# "message": "Environment Variables Demo",
# "environment": "development",
# "port": "3000",
# ...
# }