@extends('layouts.app') @section('title', '.env 관리 정책') @push('styles') @endpush @section('content')
{{-- ============================================================ --}} {{-- 히어로 배너 --}} {{-- ============================================================ --}}
아카데미 .env 관리 정책

.env 관리 정책

SAM 프로젝트의 환경 변수 관리 — 열쇠 고리처럼 서비스를 여는 비밀 설정 파일

.env 열쇠 고리 비유
{{-- ============================================================ --}} {{-- 좌측 고정 목차 (TOC) --}} {{-- ============================================================ --}} {{-- ============================================================ --}} {{-- 우측 콘텐츠 --}} {{-- ============================================================ --}}
{{-- 모바일 목차 --}} {{-- ============================================================ --}} {{-- 1. .env란 무엇인가? --}} {{-- ============================================================ --}}

1 .env란 무엇인가?

열쇠 고리 비유

.env 파일열쇠 고리와 같다. 데이터베이스, 메일, AI, 푸시 알림 등 여러 서비스를 여는 열쇠(비밀번호, API 키)를 한 곳에 모아둔 파일이다.

왜 설정을 코드에서 분리하는가?

보안

API 키, 비밀번호를 코드에 직접 적으면 Git에 올라가서 유출된다. .env는 Git에 올리지 않는다.

환경별 차이

로컬에서는 DB가 Docker 컨테이너, 서버에서는 localhost. 코드는 같은데 설정만 다르다.

.env.example vs .env

비유: 양식과 실제 서류

.env.example빈 양식지다. 어떤 항목을 채워야 하는지 알려주지만 실제 값은 비어 있다.
.env작성 완료된 서류다. 실제 비밀번호와 API 키가 들어 있다.

.env.example (양식)

GEMINI_API_KEY=
DB_PASSWORD=sampass
INTERNAL_EXCHANGE_SECRET=

Git에 포함 (공유용)

.env (실제)

GEMINI_API_KEY=AIzaSy...
DB_PASSWORD=Pr0d_S3cur3!
INTERNAL_EXCHANGE_SECRET=abc123...

Git에 절대 포함 금지!

.env 역할 개념도
{{-- ============================================================ --}} {{-- 2. SAM 프로젝트의 .env 구조 --}} {{-- ============================================================ --}}

2 SAM 프로젝트의 .env 구조

SAM은 MNG, API, React 3개 프로젝트로 구성되며, 각 프로젝트가 독립된 .env 파일을 보유한다. 공유 DB를 사용하지만 환경 변수는 각자 관리한다.

프로젝트별 .env 구조

MNG .env 카테고리

APP

이름, 환경, URL

Database

DB 접속 정보

Session

세션 드라이버, 수명

Mail

SMTP 서버 설정

SAM API 연동

API_BASE_URL, 내부통신키

Google AI

Gemini, Vertex, GCS

Claude AI

CLAUDE_API_KEY

FCM

Firebase 푸시 알림

Notion

MNG 전용

기상청 API

MNG 전용

보라 = 양쪽 공유 · 파랑 = MNG 전용

API .env 추가 카테고리

Slack 로깅

API 전용

Swagger

API 문서 설정

Sanctum

토큰 만료 설정

Legacy DB

5130 DB 접속

바로빌

세금계산서 SOAP

주황 = API 전용

{{-- ============================================================ --}} {{-- 3. Docker가 .env를 덮어쓴다 --}} {{-- ============================================================ --}}

3 Docker가 .env를 덮어쓴다

비유: 현장 상관의 즉각 명령

군대에서 기본 명령서(.env)가 있지만, 현장 상관(docker-compose)이 "이건 이렇게 해!"라고 하면 그게 우선이다. Docker 환경에서는 docker-compose.ymlenvironment 설정이 .env보다 강하다.

우선순위 (높은 순)

Override 우선순위
1

docker-compose.yml environment:

최우선. 컨테이너 시작 시 직접 주입된다.

2

.env 파일

프로젝트 루트의 환경 변수 파일.

3

.env.example

기본값 참고용. 실제 적용되지 않는다.

실제 Override 예시

API 프로젝트의 DB_HOST

api/.env: DB_HOST=127.0.0.1 무시됨
docker-compose: DB_HOST=sam-mysql-1 적용됨

Docker에서 Override하는 5개 변수: DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD

React 프로젝트

NEXT_PUBLIC_API_URL=https://api.sam.kr

NEXT_PUBLIC_API_KEY=42Jfwc6E...

NODE_ENV=development

React는 .env 파일 없이 docker-compose에서만 설정한다.

{{-- ============================================================ --}} {{-- 4. 양쪽이 같아야 하는 변수 --}} {{-- ============================================================ --}}

4 양쪽이 같아야 하는 변수

비유: 한 쌍의 자물쇠

MNG와 API는 서로 HTTP로 통신한다. INTERNAL_EXCHANGE_SECRET이 양쪽에서 다르면 HMAC 인증이 실패하여 통신이 불가능하다. 자물쇠와 열쇠가 맞지 않는 것과 같다.

동기화 필수 변수 맵

공유 API 키 (양쪽 동일 값 필수)

환경 변수 MNG API 설명
INTERNAL_EXCHANGE_SECRET 필수 필수 서버 간 HMAC 검증 키
GEMINI_API_KEY Gemini AI API 키
GEMINI_MODEL gemini-2.5-flash
VERTEX_AI_PROJECT_ID Vertex AI 프로젝트
VERTEX_AI_LOCATION us-central1
GOOGLE_STORAGE_BUCKET GCS 버킷 이름
DB_HOST / DB_DATABASE / DB_PASSWORD 공유 DB 접속 정보

경로가 다른 변수 (같은 파일, 다른 경로)

경로가 다른 변수
환경 변수 MNG 경로 API 경로
GOOGLE_APPLICATION_CREDENTIALS /var/www/sales/apikey/google_sa.json /var/www/mng/apikey/google_sa.json
FCM_SA_PATH secrets/firebase-service-account.json secrets/codebridge-x-firebase-sa.json

동일한 Google 서비스 계정 파일이지만 컨테이너마다 마운트 경로가 다르다. 값을 복사하면 안 되고 각 프로젝트의 실제 경로를 사용해야 한다.

{{-- ============================================================ --}} {{-- 5. 로컬 vs 서버 환경 --}} {{-- ============================================================ --}}

5 로컬 vs 서버 환경

로컬 vs 서버 비교
환경 변수 로컬 (Docker) 서버 (운영)
APP_ENV local production
APP_DEBUG true false
DB_HOST sam-mysql-1 (컨테이너명) 127.0.0.1 (localhost)
DB_PASSWORD sampass (개발용) ●●●●●●● (강력한 비밀번호)

APP_DEBUG=true의 운영 환경 위험성

운영 서버에서 APP_DEBUG=true이면?

DB 비밀번호 노출

에러 발생 시 .env 값이
브라우저에 표시된다

API 키 유출

스택 트레이스에 환경 변수
전체가 포함될 수 있다

서버 경로 노출

파일 구조, 프레임워크 버전 등
공격에 필요한 정보가 드러난다

{{-- ============================================================ --}} {{-- 6. .env 변경 후 해야 할 일 --}} {{-- ============================================================ --}}

6 .env 변경 후 해야 할 일

왜 config:clear가 필요한가

Laravel은 성능을 위해 .env 값을 캐시에 저장해둔다. .env를 수정해도 php artisan config:clear를 실행하지 않으면 이전 값이 계속 사용된다.

.env 변경 → 캐시 클리어 흐름

로컬 (Docker) 환경

docker exec sam-mng-1 php artisan config:clear
docker exec sam-api-1 php artisan config:clear

서버 환경

cd /home/webservice/mng && php artisan config:clear
cd /home/webservice/api && php artisan config:clear

신규 개발자 온보딩 체크리스트

온보딩 체크리스트
1

.env.example을 .env로 복사

cp .env.example .env
2

APP_KEY 생성

docker exec sam-mng-1 php artisan key:generate
3

DB 접속 정보 확인

Docker가 Override하므로 .env 기본값으로 충분하다

4

공유 API 키 동기화

GEMINI_API_KEY, INTERNAL_EXCHANGE_SECRET 등을 팀장에게 받아 설정

5

캐시 초기화

docker exec sam-mng-1 php artisan config:clear
{{-- ============================================================ --}} {{-- 7. 주의사항 & 자주 하는 실수 --}} {{-- ============================================================ --}}

7 주의사항 & 자주 하는 실수

절대 하지 마라 (6가지)

.env를 Git에 커밋

비밀번호, API 키가 저장소에 영구 저장된다. .gitignore에 .env가 포함되어 있는지 확인한다.

운영 서버에서 APP_DEBUG=true

에러 발생 시 모든 환경 변수가 브라우저에 노출된다.

EXCHANGE_SECRET 불일치

MNG와 API의 INTERNAL_EXCHANGE_SECRET이 다르면 서버 간 통신이 전부 실패한다.

운영 서버에서 APP_KEY 재생성

기존 세션, 암호화된 데이터가 모두 복호화 불가능해진다.

config:clear 안 하고 "안 되요"

.env 수정 후 캐시를 안 지우면 이전 설정이 계속 적용된다.

운영 키를 로컬에 복사

로컬에서 운영 DB에 접속하면 실수로 데이터를 변경할 수 있다.

증상별 해결책

증상

MNG → API 연동 실패 (401/403)

해결 양쪽 INTERNAL_EXCHANGE_SECRET 값 일치 확인 → config:clear

증상

AI 기능 (Gemini/Claude) 동작 안 함

해결 해당 프로젝트 .env의 GEMINI_API_KEY 또는 CLAUDE_API_KEY 값 확인 → config:clear

증상

DB 접속 오류 (Connection refused)

해결 Docker: DB_HOST=sam-mysql-1 / 서버: DB_HOST=127.0.0.1 확인. Docker에서는 compose가 override하므로 .env 값은 무관.

증상

Google 서비스 계정 파일 오류

해결 GOOGLE_APPLICATION_CREDENTIALS 경로가 해당 컨테이너의 마운트 경로와 일치하는지 확인. MNG와 API의 경로가 다르다.

증상

.env 수정했는데 설정이 안 바뀜

해결 php artisan config:clear 실행. Docker의 override 변수인지도 확인 (compose가 .env보다 우선).

신규 환경 변수 추가 시 절차

  1. .env.example에 키=기본값 추가 (다른 개발자를 위한 문서 역할)
  2. 자신의 .env에 실제 값 설정
  3. config/services.php 등에서 env('NEW_KEY')로 참조
  4. 팀원에게 새 변수 추가 사실 공유
  5. 양쪽(MNG/API) 필요 시 동기화 필수 항목인지 확인
{{-- ============================================================ --}} {{-- 용어 사전 --}} {{-- ============================================================ --}} @include('components.academy-glossary', ['domain' => 'env-management'])
@endsection