티스토리 뷰

vercel에 넥스트 프로젝트를 배포하면서 환경 변수를 따로 넣어주지 않아 배포실패로 골머리를 썪다가 제대로 정리해야겠다는 생각이 들었습니다. 

우선 우리가 통상적으로 react로 프로젝트를 만들 때에도 .env에 환경변수를 넣어서 관리했던 것을 기억할 것이다. 

 

환경 변수란?

environment variable

일반적으로 우리는 코드 베이스는 하나만 관리하고, 개발, 테스트 운영등 여러 환경에 어플리케이션을 배포한다. 

어느 환경에 배포하느냐에 따라서 다르게 설정되어야 하는 값들은 보통 운영 체제 수준에서 환경 변수를 통해 관리하게 된다.

대표적으로 DB 설정을 들 수 있는데, 운영 환경에서는 데이터 센터나 클라우드 인프라 상의 상용DB를 사용하고, 개발 환경에서는 개발자의 PC상 로컬 DB를 사용하는 경우가 많다.

뿐만 아니라, DB의 비밀번호나 서드파티서비스의 API 키와 같이 민감한 인증 정보는 Github과 같은 코드 저장소(repo)에 올리면 상당히 위험할 수 있기 때문에 환경 변수로 저장해두고 사용한다.

 

환경 변수 접근

node.js에서는 보통 process.env 를 통해서 환경 변수에 접근하게 된다. process 는 Node.js에 기본적으로 내장된 전역 객체여서 별도로 불러올(import) 필요없이 프로그램 어디서든 사용할 수 있다.

일부 환경 변수들은 우리가 직접 설정해주지 않더라도 운영 체제 수준에서 이미 설정이 되어 있다. 예를 들어, terminal 을 열고 node.js 인터프리터를 실행하면 어떤 환경 변수들이 이미 설정되어 있는지 간단히 확인할 수 있다.

$ node
Welcome to Node.js v16.14.2.
Type ".help" for more information.
> process.env.USER
'dale'
> process.env.HOME
'/Users/dale'

 

환경 변수 설정 

환경 변수는 운영 체제에 따라서 상이한 방법으로 설정할 수 있다.

가장 간단한 방법은 프로그램을 실행할 때 node 명령어 앞에 환경 변수를 키=값 형태로 붙여주면 된다.

$ API_KEY=abc DB_PASSWORD=1234 node
Welcome to Node.js v16.14.2.
Type ".help" for more information.
> process.env.API_KEY
'abc'
⚠ 이렇게 프로그램 실행 시 설정해준 환경 변수는 해당 프로그램이 실행되는 동안에만 유효하며 프로그램이 종료하면 사라진다. 

운영 체제에서 제공하는 명령어를 통해서 환경 변수를 설정해 줄 수도 있다. 

  • Unix 계열(MacOS): export 
  • windows 계열: SET

🤸‍♀️운영 체제의 명령어를 이용하여 환경 변수를 설정하면 터미널 창을 닫을 때까지 유지가 된다. 

$ export API_KEY=abc
$ export DB_PASSWORD=1234
$ node
Welcome to Node.js v16.14.2.
Type ".help" for more information.
> process.env.API_KEY
'abc'
> process.env.DB_PASSWORD
'1234'
  • 사실 process.env는 가변 객체이기 때문에 반드시 이렇게 프로그램 실행 시점이나 실행 전에 설정해줘야할 필요는 없다. 프로그램 내에서 얼마든지 새로운 환경 변수를 설정하거나 기존에 설정된 환경 변수의 값을 자유롭게 갱신, 제거할 수 있기 때문이다.
  • 운영 체제의 명령어를 이용하여 환경 변수를 설정하거나 process.env를 활용하여 환경 변수를 설정할 경우 => 프로그램 실행 시점에 설정된 환경 변수의 값이 운영 체제의 명령어로 설정된 환경 변수의 값보다 우선시 된다. (특정 환경 변수를 일회성으로 설정하고자 할 때 매우 유용하게 overwrite 특징을 살려 활용할 수 있다.)

사실 이렇게 일일이 모든 환경 변수를 설정하는 것은 오타의 위험도 크고 지루한 작업이 될 수 있다. 

관리해야할 환경 변수의 수가 많아지거나 애플리케이션을 배포해야할 환경이 늘어나면 유지 보수가 매우 괴로워지기 때문에 Node.js 프로젝트에서 환경 변수를 좀 더 효과적으로 관리하기 위해 dotenv 라는 라이브러리를 이용한다.


dotenv 

:환경 변수를 파일에 저장해놓고 접근할 수 있게 도와주는 node.js 라이브러리 

yarn add dotenv
  • 아무런 설정을 하지 않으면 현재 디렉터리의 최상단에 위치한 .env 파일을 읽어온다.
  • dotenv를 활용하면 process.env에 환경변수를 설정할 수 있다.
  • 사용 방법은 본인의 프로젝트가 CommonJS 기반인지, ESModule 기반인지에 따라 다르다.

1. CommonJS에서 환경 변수 불러오기(require)

Node.js 에서 전통적으로 제공해왔던 모듈 시스템인 CommonJS에서 dotenv 라이브러리를 사용하는 법

 프로그램을 구동할 때 제일 먼저 실행되는 자바스크립트 파일(e.g. index.js, main.js)의 최상위에 dotenv라이브러리를 임포트한 후 config() 함수를 호출해주면 된다.

 

//index.js
require("dotenv").config(); //dotenv 라는 패키지를 불러온다음에 .config()함수를 통해 연결해준다.

console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
하지만, 같은 파일 내에서 dotenv 라이브러리의 config() 함수를 호출하기 전에 process.env를 읽으면 안되니 주의해야 한다. 
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);

require("dotenv").config();
  • 위와 같이 dotenv 파일의 환경변수를 읽어오기 전에 process.env.의 환경변수를 읽으려하면 undefined 가 뜰 것이다. 

1-1.  ES 모듈에서 환경 변수 불러오기 (import)

ES 모듈을 사용하고 있는 Node.js 환경에서는 require 대신 import 키워드를 사용하여 dotenv 패키지를 불러오면 된다. 

📌확장자를 .js가 아니라 .mjs를 사용하게 되면 node.js가 ES 모듈을 사용하게 된다. 
import dotenv from "dotenv";

dotenv.config();

console.log("DB_HOST", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);

 

2. .env 파일(default)이 아닌 다른 파일에 환경변수를 저장하고 싶다면?

-> config() 함수를 호출할 때, path 옵션(이 담긴 객체)을 넘기면 된다.

아래의 예시는 .env.local 파일(default로 환경 변수를 읽어오는 .env가 아닌 파일)에 담긴 환경변수를 읽어오는 CommonJS 문법이다. ES 모듈에서도 사용 방법은 동일하다. 

require('dotenv').config({path: '.env.local'});

 

3. 프로그램을 실행하면서 환경 변수를 불러오기 

해당 파일에서 dotenv를 임포트하여 config() 함수를 코드에서 호출하지 않고도 프로그램을 구동할 때, 커멘드라인을 통해서 dotenv/config 를 넘기는 방법도 있다.

node 커맨드의 -r 또는 --require 옵션으로 dotenv/config를 넘겨준다. 이 방법을 활용하면 dotenv라이브러리를 직접 임포트하지 않아도 .env 파일에 저장된 환경 변수가 process.env에 설정된다.

//index.mjs (ES 모듈 시스템으로 동작하는 js파일)
console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);
  • 위의 코드를 보면 dotenv패키지를 불러오지도 않고 config함수를 호출하지도 않는다. 
  • 이때, 아래와 같이 커맨드라인에 옵션을 사용하면 정상적으로 환경변수에 접근할 수 있다.
$ node -r dotenv/config index.mjs
DB_HOST: localhost
DB_USER: root
DB_PASS: 1234
만약 .env가 아닌 다른 경로에 있는 파일에 환경 변수를 저장해놨다면 DOTENV_CONFIG_PATH 환경 변수를 활용하면 된다. 
$ DOTENV_CONFIG_PATH=.env.local node -r dotenv/config index.mjs //=뒤에 오는 값이 환경변수가 들어있는 파일이다. (.env.local)

📌해당 방법은 어떤 프로젝트가 CommonJS 기반인지 ES 모듈 기반인지 미리 알 수 없을 때 유용하다.

해당 Node.js 런타임(runtime)이 어떤 모듈 시스템을 사용하든지 상관없이 통하는 방법이기 때문!

 

4. 이미 설정되어 있는 환경 변수(디버깅, 오버라이드 방법)

📌 dotenv라이브러리는 운영체제 수준에서 설정된 환경 변수값을 기본적으로 override하지 않는다.

이미 운영체제에서 환경 변수가 설정되어 있다면 process.env의 값이 그 값으로 고정되어 실행할 때에도 dotenv로 설정한 값이 오버라이드 되지 않는 것이다.

 

이럴 때 path 처럼 옵션값을 넘겨서 이미 설정된 환경 변수 값을 확인해볼 수 있다. 

debug: true 값을 넘기면 어떤 값이 설정되어 있는 지와 오버라이드가 되지않는다는 안내 메세지를 받을 수 있다. 

환경 변수의 오버라이드(덮어쓰기)를 원한다면 override: true 값을 주면 된다.

import dotenv from "dotenv";

dotenv.config({debug: true, override: true})

5. ES 모듈에서 발생하기 쉬운 실수

ES 모듈을 사용할 때는 CoommonJS를 사용할 때보다 주의가 더 필요하다.

아래의 코드를 보면, dotenv 라이브러리를 제일먼저 임포트하기 때문에 db.js 파일이 process.env에 접근할 때 환경 변수가 설정되어 있을 거 같다. 

// db.mjs
export const db_host = process.env.DB_HOST;
export const db_user = process.env.DB_USER;
export const db_pass = process.env.DB_PASS;
//index2.mjs

import dotenv from "dotenv";
import { db_host, db_user, db_pass } from "./db.js";

dotenv.config();

console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);

console.log({ db_host, db_user, db_pass });

 

하지만 실제 실행을 해보면 db.js 파일이 process.env 에 접근했을 시점에는 환경변수가 설정되어 있지 않다. 

원인은 dotenv.config() 함수가 db.js 파일이 임포트 된 이후에 호출되었기 때문이다. 

이 문제는 dotenv 라이브러리를 임포트하는 코드를 별도의 파일로 빼고, 그 안에서 dotenv.config() 함수를 호출하면 피할 수 있다.

//env.mjs
import dotenv from "dotenv";

dotenv.config();
//index2.mjs

import "./env.js";
import { db_host, db_user, db_pass } from "./db.js";

console.log("DB_HOST:", process.env.DB_HOST);
console.log("DB_USER:", process.env.DB_USER);
console.log("DB_PASS:", process.env.DB_PASS);

console.log({ db_host, db_user, db_pass });

-> 결론적으로 프로그램이 시작된 후 가급적 dotenv.config() 함수를 빨리 호출하는 것이 안전하다. 

6. 보안상 주의 사항

.env.production .env.straging, .env.qa 등 이런 식으로 각 배포(deploy) 환경 별로 환경 변수를 다른 파일에 저장해두고 사용하는 것도 볼 수 있다. 이렇게 하면 보안 문제에 취약할 뿐만 아니라, 일반적인 코드와 설정을 한 곳에서 관리하는 소프트웨어 개발 관행으로 여겨진다. 

 

다라서 .env 파일은 개발자가 로컬 환경에서 환경 변수를 설정해야할 때만 제한적으로 사용하는 것이 좋으며, 그 밖에 환경에서는 운영 체제 수준에서 제대로 환경 변수를 설정해줘야 한다.

 

all ref: https://www.daleseo.com/js-node-process-env/

 

Node.js에서 환경 변수 다루기 (process.env)

Engineering Blog by Dale Seo

www.daleseo.com

https://www.daleseo.com/js-dotenv/

 

dotenv로 환경 변수를 .env 파일로 관리하기

Engineering Blog by Dale Seo

www.daleseo.com

 

댓글