TIL - 20260604

juni·2026년 6월 4일

TIL

목록 보기
369/468

0604 풀스택 실무 기초 (7/N): 환경변수와 설정 관리


✅ 1. 환경변수란 무엇인가?

  • 환경변수(Environment Variable)는 애플리케이션이 실행될 때 필요한 설정값을 코드 밖에서 주입하는 값입니다.
  • DB 주소, API Key, JWT Secret, AWS 접근 정보, 외부 API URL처럼 환경마다 달라지거나 보안상 코드에 직접 넣으면 안 되는 값을 관리할 때 사용합니다.
  • 풀스택 개발에서는 프론트엔드, 백엔드, 배포 서버, CI/CD 환경 모두에서 환경변수 관리가 중요합니다.

➕ 1-1. 환경변수가 필요한 이유

  • 보안

    • DB 비밀번호, JWT Secret, AWS Secret Key 같은 민감정보를 코드에 직접 작성하지 않기 위해 사용합니다.
  • 환경 분리

    • 로컬, 개발, 스테이징, 운영 환경마다 다른 설정을 적용할 수 있습니다.
  • 배포 유연성

    • 같은 코드라도 환경변수만 바꿔서 다른 서버나 다른 도메인에서 실행할 수 있습니다.
  • 협업과 유지보수

    • 설정값이 코드 곳곳에 흩어져 있으면 관리가 어렵습니다.
    • 환경변수로 분리하면 어떤 설정이 필요한지 명확하게 관리할 수 있습니다.

✅ 2. 환경별 설정 분리

  • 실무에서는 보통 로컬, 개발, 스테이징, 운영 환경을 구분합니다.
환경설명예시
Local개발자 개인 PC 환경localhost
Development개발 서버 환경dev.example.com
Staging운영 배포 전 검증 환경staging.example.com
Production실제 사용자 서비스 환경www.example.com

➕ 2-1. 환경별로 달라지는 값

  • API 서버 주소
  • 데이터베이스 주소
  • Redis 주소
  • JWT Secret
  • 외부 API Key
  • AWS S3 버킷 이름
  • OAuth Redirect URI
  • 결제/문자/본인인증 API 설정
  • 로그 레벨
  • CORS 허용 도메인
로컬 환경 API 주소:
http://localhost:3000

운영 환경 API 주소:
https://api.example.com

✅ 3. .env 파일

  • .env 파일은 환경변수를 파일 형태로 관리하는 방식입니다.
  • Node.js, NestJS, React, Next.js, Docker 등 다양한 환경에서 사용됩니다.

➕ 3-1. .env 예시

NODE_ENV=development
PORT=3000

DATABASE_URL=postgresql://user:password@localhost:5432/app_db

JWT_SECRET=my-local-secret
JWT_ACCESS_EXPIRES_IN=30m
JWT_REFRESH_EXPIRES_IN=14d

AWS_REGION=ap-northeast-2
AWS_S3_BUCKET=my-dev-bucket

CORS_ORIGIN=http://localhost:5173
  • .env는 편리하지만 민감정보가 들어갈 수 있으므로 Git에 올리면 안 됩니다.
.env
.env.local
.env.development
.env.production

✅ 4. .env.example

  • .env.example은 실제 비밀값 없이 필요한 환경변수 목록만 공유하는 파일입니다.
  • 협업자나 배포 담당자가 어떤 설정값이 필요한지 알 수 있게 해줍니다.

➕ 4-1. .env.example 예시

NODE_ENV=
PORT=

DATABASE_URL=

JWT_SECRET=
JWT_ACCESS_EXPIRES_IN=
JWT_REFRESH_EXPIRES_IN=

AWS_REGION=
AWS_S3_BUCKET=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

CORS_ORIGIN=
  • 실제 값은 비워두고, 변수 이름만 작성합니다.
  • 필요한 경우 주석으로 설명을 추가할 수 있습니다.
# 서버 실행 포트
PORT=3000

# PostgreSQL 연결 문자열
DATABASE_URL=

# 프론트엔드 허용 Origin
CORS_ORIGIN=

✅ 5. 프론트엔드 환경변수

  • React, Vite, Next.js 같은 프론트엔드 프로젝트에서도 환경변수를 사용합니다.
  • 단, 프론트엔드 환경변수는 빌드 결과물에 포함될 수 있으므로 민감정보를 넣으면 안 됩니다.

➕ 5-1. Vite 환경변수

  • Vite에서는 브라우저에서 접근 가능한 환경변수 이름이 VITE_로 시작해야 합니다.
VITE_API_BASE_URL=https://api.example.com
VITE_GA_MEASUREMENT_ID=G-XXXXXXXXXX
VITE_CHANNEL_TALK_PLUGIN_KEY=xxxxxxxx
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
  • 주의할 점

    • VITE_가 붙은 값은 브라우저에서 확인될 수 있습니다.
    • DB 비밀번호, JWT Secret, AWS Secret Key를 절대 넣으면 안 됩니다.

➕ 5-2. Next.js 환경변수

  • Next.js에서는 브라우저에 노출되어도 되는 값에 NEXT_PUBLIC_ prefix를 붙입니다.
NEXT_PUBLIC_API_BASE_URL=https://api.example.com
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
  • NEXT_PUBLIC_이 붙은 값은 클라이언트 번들에 포함될 수 있습니다.
  • 민감정보는 서버 전용 환경변수로만 사용해야 합니다.

✅ 6. 백엔드 환경변수

  • 백엔드에서는 DB 연결 정보, JWT Secret, 외부 API Key 등 민감정보를 환경변수로 관리합니다.
  • NestJS에서는 보통 @nestjs/config 패키지를 사용합니다.

➕ 6-1. NestJS ConfigModule 예시

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
  ],
})
export class AppModule {}

➕ 6-2. ConfigService 사용 예시

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AuthService {
  constructor(private readonly configService: ConfigService) {}

  createToken() {
    const jwtSecret = this.configService.get<string>('JWT_SECRET');

    return jwtSecret;
  }
}
  • process.env.JWT_SECRET를 직접 여러 곳에서 사용하는 것보다 ConfigService를 통해 관리하면 구조가 깔끔해집니다.

✅ 7. 환경변수 검증

  • 환경변수는 누락되거나 잘못 들어가면 런타임 오류나 장애로 이어질 수 있습니다.
  • 특히 운영 배포에서는 환경변수 하나가 빠져서 서버가 실행되지 않거나, 외부 API 호출이 실패할 수 있습니다.

➕ 7-1. 자주 발생하는 문제

  • DATABASE_URL 누락
  • JWT_SECRET 누락
  • 운영 환경에서 로컬 DB 주소 사용
  • CORS Origin 오타
  • S3 버킷 이름 오류
  • 외부 API Key 만료
  • OAuth Redirect URI 불일치
Error: Environment variable not found: DATABASE_URL

➕ 7-2. 검증이 필요한 이유

  • 서버 시작 시점에 잘못된 설정을 빠르게 발견할 수 있습니다.
  • 장애가 발생한 뒤에야 설정 오류를 찾는 상황을 줄일 수 있습니다.
  • 팀원이 새로 프로젝트를 세팅할 때 누락된 값을 바로 알 수 있습니다.

✅ 8. NestJS 환경변수 검증 예시

  • NestJS에서는 joi 같은 라이브러리를 사용해 환경변수를 검증할 수 있습니다.
import * as Joi from 'joi';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        NODE_ENV: Joi.string()
          .valid('development', 'production', 'test')
          .required(),
        PORT: Joi.number().default(3000),
        DATABASE_URL: Joi.string().required(),
        JWT_SECRET: Joi.string().required(),
        CORS_ORIGIN: Joi.string().required(),
      }),
    }),
  ],
})
export class AppModule {}
  • 이렇게 설정하면 필수 환경변수가 없을 때 애플리케이션이 시작 단계에서 바로 실패합니다.
  • 운영에서는 조용히 잘못 실행되는 것보다, 시작 전에 명확히 실패하는 편이 더 안전합니다.

✅ 9. Prisma와 DATABASE_URL

  • Prisma는 DB 연결을 위해 보통 DATABASE_URL 환경변수를 사용합니다.
DATABASE_URL="postgresql://user:password@localhost:5432/app_db?schema=public"
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

➕ 9-1. DATABASE_URL에서 확인할 것

항목예시
DB 종류postgresql, mysql
사용자명user
비밀번호password
호스트localhost, db.example.com
포트5432, 3306
DB 이름app_db
옵션schema=public

➕ 9-2. 자주 발생하는 실수

  • Docker DB는 실행 중인데 포트가 다름
  • 로컬에서는 localhost, Docker 내부에서는 서비스명 사용 필요
  • 운영 DB 주소를 로컬 .env에 잘못 넣음
  • 특수문자가 포함된 비밀번호를 URL 인코딩하지 않음
  • .env 수정 후 서버를 재시작하지 않음

✅ 10. Docker 환경변수

  • Docker를 사용할 때도 환경변수를 주입해야 합니다.
  • docker-compose.yml에서 env_file 또는 environment를 사용할 수 있습니다.

➕ 10-1. env_file 방식

services:
  api:
    build: .
    env_file:
      - .env
    ports:
      - "3000:3000"
  • .env 파일의 값을 컨테이너에 주입합니다.

➕ 10-2. environment 방식

services:
  api:
    build: .
    environment:
      NODE_ENV: production
      PORT: 3000
      DATABASE_URL: postgresql://user:password@db:5432/app_db
  • 직접 값을 지정하는 방식입니다.
  • 민감정보가 docker-compose.yml에 그대로 들어가지 않도록 주의해야 합니다.

✅ 11. GitHub Actions 환경변수와 Secrets

  • CI/CD에서는 GitHub Actions가 빌드와 배포를 수행할 때 필요한 환경변수를 관리해야 합니다.
  • 민감정보는 GitHub Repository의 Secrets에 저장합니다.

➕ 11-1. GitHub Secrets에 넣는 값 예시

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • DATABASE_URL
  • JWT_SECRET
  • SSH_HOST
  • SSH_USER
  • SSH_PRIVATE_KEY
  • S3_BUCKET_NAME

➕ 11-2. GitHub Actions에서 사용하는 예시

name: Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Use secret
        run: echo "Deploying..."
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  • Secrets 값은 로그에 직접 출력하지 않아야 합니다.
  • echo $JWT_SECRET 같은 명령어는 절대 사용하지 않는 것이 좋습니다.

✅ 12. 운영 서버에서 환경변수 관리

  • 운영 서버에서는 .env 파일을 직접 서버에 두거나, 클라우드 Secret Manager를 사용할 수 있습니다.
  • 중요한 것은 민감정보 접근 권한을 최소화하고 변경 이력을 관리하는 것입니다.

➕ 12-1. 운영 서버 .env 관리 기준

  1. .env 파일 권한을 제한한다.
  2. 운영 서버의 .env를 Git에 올리지 않는다.
  3. 운영 DB 정보와 개발 DB 정보를 혼동하지 않는다.
  4. 변경 시 백업 또는 변경 기록을 남긴다.
  5. 배포 후 서버 재시작이 필요한지 확인한다.
  6. 외부 API Key 변경 시 관련 기능을 테스트한다.
# .env 파일 권한 예시
chmod 600 .env

✅ 13. 민감정보 관리 도구

  • 프로젝트가 커지면 단순 .env 파일만으로는 관리가 어려워질 수 있습니다.
  • 이때는 Secret Manager 계열 서비스를 사용할 수 있습니다.

➕ 13-1. 대표적인 도구

도구설명
AWS Secrets ManagerAWS에서 제공하는 비밀정보 관리 서비스
AWS Systems Manager Parameter Store설정값과 비밀정보를 저장할 수 있는 AWS 서비스
Doppler환경변수와 Secret 관리 SaaS
VaultHashiCorp에서 제공하는 Secret 관리 도구
GitHub Actions SecretsGitHub Actions용 비밀정보 저장소
  • 1인 개발 또는 작은 팀에서는 .env + GitHub Secrets만으로도 충분한 경우가 많습니다.
  • 운영 환경이 복잡해지면 AWS Secrets Manager나 Parameter Store를 고려할 수 있습니다.

✅ 14. 환경변수와 보안 사고

  • 환경변수 관리 실수는 실제 보안 사고로 이어질 수 있습니다.

➕ 14-1. 위험한 실수

  • .env를 GitHub에 올림
  • 프론트엔드 환경변수에 Secret Key를 넣음
  • 로그에 환경변수를 출력함
  • 운영 DB URL을 개발자 개인 PC에 무분별하게 저장함
  • 퇴사자나 외부 작업자의 접근 권한을 회수하지 않음
  • AWS Access Key를 장기간 교체하지 않음

➕ 14-2. 사고 예방 방법

  1. .gitignore에 .env 포함
  2. GitHub Secret Scanning 활성화
  3. AWS IAM 권한 최소화
  4. Access Key 주기적 교체
  5. 운영 Secret 접근자 제한
  6. 프론트엔드 번들에 민감정보가 포함되지 않았는지 확인
  7. 유출 의심 시 즉시 Key 폐기 및 재발급

✅ 15. 프론트엔드 환경변수 보안 주의점

  • 프론트엔드에 들어간 환경변수는 사용자가 개발자 도구나 번들 파일을 통해 확인할 수 있습니다.
  • 그래서 “프론트엔드 환경변수 = 공개될 수 있는 값”이라고 생각해야 합니다.

➕ 15-1. 넣어도 되는 값

  • API Base URL
  • Google Analytics Measurement ID
  • 공개용 지도 API Key
  • 채널톡 Plugin Key
  • 공개 가능한 OAuth Client ID

➕ 15-2. 넣으면 안 되는 값

  • DB 접속 정보
  • JWT Secret
  • AWS Secret Access Key
  • 관리자 API Key
  • 결제 Secret Key
  • 문자 발송 Secret Key
  • 본인인증 Secret Key
프론트엔드에 들어가도 되는 값:
“이 값이 사용자에게 보여도 서비스가 망가지지 않는 값”

프론트엔드에 들어가면 안 되는 값:
“이 값이 노출되면 서버 권한이나 외부 서비스 권한을 탈취당하는 값”

✅ 16. 환경변수 변경 후 확인할 것

  • 환경변수는 수정만 한다고 바로 반영되지 않는 경우가 많습니다.
  • 서버 프로세스나 빌드 결과에 따라 재시작 또는 재빌드가 필요합니다.

➕ 16-1. 백엔드

  • .env 수정 후 서버 재시작 필요
  • PM2 사용 시 pm2 restart 또는 pm2 reload 필요
  • Docker 사용 시 컨테이너 재생성 필요
  • ConfigModule 캐싱 여부 확인 필요
pm2 restart api

➕ 16-2. 프론트엔드

  • Vite, React, Next.js의 공개 환경변수는 빌드 시점에 포함됩니다.
  • 운영 배포에서는 .env 수정 후 재빌드가 필요할 수 있습니다.
npm run build
  • 이미 빌드된 정적 파일에는 이전 환경변수가 들어있을 수 있으므로, 빌드와 배포를 다시 해야 합니다.

✅ 17. 실무 체크리스트

➕ 17-1. 새 프로젝트 세팅 체크리스트

  1. .env.example을 만들었는가?
  2. .env가 .gitignore에 포함되어 있는가?
  3. 프론트엔드 공개 환경변수 prefix를 지켰는가?
  4. 민감정보를 프론트엔드 환경변수에 넣지 않았는가?
  5. 백엔드 필수 환경변수 검증을 추가했는가?
  6. 로컬/운영 DB 주소를 명확히 구분했는가?
  7. CORS Origin을 환경변수로 관리하는가?
  8. JWT Secret이 환경별로 다르게 설정되어 있는가?

➕ 17-2. 배포 전 체크리스트

  1. 운영 서버에 필요한 환경변수가 모두 있는가?
  2. 운영 DB 주소가 정확한가?
  3. 운영 CORS Origin이 정확한가?
  4. 외부 API Key가 운영용인지 확인했는가?
  5. 프론트엔드 재빌드가 필요한 환경변수인지 확인했는가?
  6. GitHub Actions Secrets가 올바르게 등록되어 있는가?
  7. 로그에 Secret 값이 출력되지 않는가?
  8. 배포 후 로그인, API 호출, 외부 API 연동을 확인했는가?

➕ 17-3. 장애 발생 시 체크리스트

  1. 최근 환경변수 변경이 있었는가?
  2. .env 수정 후 서버를 재시작했는가?
  3. 운영 서버와 로컬 서버의 환경변수가 섞이지 않았는가?
  4. DB URL, 포트, 계정 정보가 맞는가?
  5. CORS Origin 오타가 없는가?
  6. JWT Secret 변경으로 기존 토큰이 모두 무효화된 것은 아닌가?
  7. 외부 API Key가 만료되었거나 권한이 바뀌지 않았는가?

✅ 18. AI를 활용해 환경변수 문제를 해결할 때 질문법

  • 환경변수 문제는 현재 실행 환경과 설정값의 구조를 같이 설명해야 해결이 빠릅니다.
  • 단, 실제 Secret 값은 AI에게 그대로 보내면 안 됩니다.

➕ 18-1. 좋은 질문 예시

NestJS + Prisma 프로젝트에서 DB 연결 오류가 발생해.

상황:
- 로컬 개발 환경
- PostgreSQL은 Docker로 실행 중
- 백엔드 서버는 로컬에서 npm run start:dev로 실행 중
- Prisma 사용
- 오류 메시지: Can't reach database server at localhost:5432

.env 구조:
DATABASE_URL="postgresql://USER:PASSWORD@localhost:5432/DB_NAME?schema=public"

docker-compose.yml에서 PostgreSQL 포트:
5432:5432

실제 비밀번호와 DB명은 가렸어.
확인해야 할 순서를 알려줘.

➕ 18-2. AI 답변 검증 기준

  1. 실제 Secret 값을 요구하지 않는가?
  2. 로컬 실행인지 Docker 내부 실행인지 구분하는가?
  3. .env 수정 후 서버 재시작을 안내하는가?
  4. 포트, DB 실행 여부, 계정 정보 확인을 포함하는가?
  5. 프론트엔드 환경변수와 백엔드 환경변수를 구분하는가?
  6. 민감정보를 Git에 올리지 말라고 안내하는가?

📌 요약

  • 환경변수는 DB 주소, API Key, JWT Secret, 외부 API URL처럼 실행 환경마다 달라지거나 코드에 직접 넣으면 안 되는 설정값을 관리하는 방식입니다.
  • 로컬, 개발, 스테이징, 운영 환경은 서로 다른 설정을 가질 수 있으므로 환경변수를 통해 분리해야 합니다.
  • .env에는 실제 값이 들어가고, .env.example에는 필요한 변수 목록만 정리합니다.
  • 프론트엔드 환경변수는 브라우저에 노출될 수 있으므로 민감정보를 넣으면 안 됩니다.
  • 백엔드에서는 @nestjs/config 같은 도구로 환경변수를 관리하고, 필수값 검증을 적용하는 것이 좋습니다.
  • Prisma는 DATABASE_URL 환경변수를 통해 DB에 연결하며, DB 주소, 포트, 계정, Docker 실행 위치를 정확히 확인해야 합니다.
  • GitHub Actions에서는 민감정보를 Secrets로 관리하고, 로그에 출력하지 않아야 합니다.
  • 환경변수 변경 후에는 서버 재시작이나 프론트엔드 재빌드가 필요한 경우가 많습니다.
  • AI에게 환경변수 문제를 물어볼 때는 실제 Secret 값은 가리고, 실행 환경과 오류 메시지, 설정 구조만 전달해야 합니다.

0개의 댓글