15.1 서비스 운영을 위한 패키지
1. 실 서비스 배포 준비하기
⇒ 서비스 개발 후 외부환경인 AWS에 배포준비 과정을 정리
- 서버 실행 관리, 에러 내역관리, 보안 위협 대처
2. morgan
⇒ 개발용으로 설정된 익스프레스 미들웨어를 배포용으로 전환한다.
- process.env.NODE_ENV를 통해 배포환경인지 배포환경인지를 판단
- 배포 환경일 때는 combined를 사용한다(dev보다 더 많은 사용자 정보를 남김)
if (process.env.NODE_ENV === 'production') {
app.use(morgan('combined'));
} else {
app.use(morgan('dev'));
}
3. express-session
⇒ 기존 설정들을 배포용과 개발용으로 분기 처리
- session 옵션 중 proxy속성은 배포용일때는 true로 설정한다. (기본값 : false)
- proxy 속성여부 : 보안쿠키를 설정 할 때 역방향 프록시를 신뢰한다.( "X-Forwarded-Proto" 헤더를 통해)
const sessionOption = {
resave : false,
saveUninitialized : false,
secret : process.env.COOKIE_SECRET,
cookie : {
httpOnly : true,
secure : false,
},
};
if (process.env.NODE_ENV === 'production') {
sessionOption.proxy = true;
app.enable('trust proxy'); // proxy서버를 사용하면 넣어두면 좋다
}
app.use(session(sessionOption));
4. sequelize config
⇒ 시퀄라이즈 설정도 json이 아닌 js로 변경 후 process.env.NODE_ENV를 활용한다.
// config/config.js
require('dotenv').config();
module.exports = {
development: {
username: "root",
password: process.env.SEQUELIZE_PASSWORD,
database: "nodebird",
host: "127.0.0.1",
dialect: "mysql"
},
production: {
username: "root",
password: process.env.SEQUELIZE_PASSWORD,
database: "nodebird",
host: "127.0.0.1",
dialect: "mysql",
logging : false,
}
}
// .env
COOKIE_SECRET=nodebirdsecret
SEQUELIZE_PASSWORD=DB비밀번호
5. cross-env를 package.json에 파라미터 설정
⇒ 동적으로 process.env 변경 가능
- 운영체제 상관없이 일괄 적용을 위한 cross-env를 설치
- cross-env를 설치하지 않으면 맥/리눅스에서만 정상적으로 설정된다. (윈도우X)
$ npm i cross-env
// package.json
{
"name": "nodebird",
"version": "0.0.1",
"description": "익스프레스로 만드는 SNS 서비스",
"main": "server.js",
"scripts": {
"start": "cross-env NODE_ENV=production PORT=80 pm2 start server.js -i 0",
"dev": "nodemon server",
"coverage": "jest --coverage"
},
....
}
7. sanitize-html
⇒ XSS(Cross Site Scripting) 공격을 방어한다.
- 허용하지 않은 html 입력을 막아준다.
$ npm i sanitize-html
const sanitizeHtml = require('sanitize-html');
const html = "<script>localhost.href = 'https://gilbut.co.kr'</script>"
console.log(sanitizeHtml(html)); // '' (빈 문자열로 치환처리)
8. scurf
⇒ CSRF(Cross Site Request Forgery) 공격방어
- csrfToken을 생성해 프론트로 보내주고(쿠키로) Form 등록 시 csrfToken을 같이 받아 일치하는지 비교한다.
$ npm i csurf
// routes/index.js
const csrf = require('csurf');
const csrfProtection = csrf({ cookie : true });
app.get('/form', csrProtoction, (req, res) => {
res.render('csrf', { csrfToken : rq.csrfToken()});
});
app.post('/form', csrfProtoction, (req, res) => {
res.send('ok');
});
view/csrf.html
...
<form id="twit-form" action="/post" method="post" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="{{csrfToken}}" />
...
</form>
...
9. pm2 소개
⇒ node.js를 통해 만든 프로그램을 관리해주는 프로그램이며 원활한 서버 운영에 도움을 준다.
- 서버가 에러가 발생해 꺼졌을 때 다시 서버를 실행한다. (무중단 서비스)
- 멀티 프로세싱 지원 (노드 프로세스 수를 1개 이상으로 늘린다)
- 요청을 프로세스들에게 고르게 분배해 준다.
- 단점 : 프로세스 간 서버의 메모리 같은 자원은 공유할 수 없다. (memcached나 redis같은 메모리 DB를 사용해서 해소)
10. pm2 사용하기
⇒ pm2 전역 설치 후, 명렁어 사용
$ npm i pm2 -g
// package.json
"scripts": {
"start": "cross-env NODE_ENV=production PORT=80 pm2 start server.js"
11. 프로세스 목록 확인하기
⇒ pm2 list로 현재 실행시킨 프로세스 목록을 확인할 수 있다.
$ npx pm2 list
12. pm2로 멀티 프로세싱하기
⇒ pm2 start [파일명] -i [프로세스 수] 명령어로 멀티 프로세싱이 가능하다.
- 프로세스 수를 0으로 입력 시 CPU 코어 개수만큼 생성, -1이면 CPU 코어 개수보다 1개 적게 생성한다.
- -1은 하나의 프로세스를 노트 외에 작업 수행을 위해 풀어주는 편이다.
// package.json
"scripts": {
"start": "cross-env NODE_ENV=production PORT=80 pm2 start server.js -i 0"
13. 서버 종료 후 멀티 프로세싱 하기
⇒ npx pm2 kill명령어를 통해 pm2로 실행시킨 전체 프로세스 종료처리
14. 프로세스 모니터링 확인
⇒ pm2 monit으로 프로세스를 모니터링 할 수 있다.
$ npx pm2 monit
15. winston
⇒ console.log와 console.error를 대체하기 위한 모듈
- 위 두메서드는 휘발성이므로 로그를 기록할 수 있는 윈스턴을 설치해 관리한다.
$ npm i winston
16. winston 메서드
⇒ createLogger로 로거 인스턴스를 생성 후 필요속성들을 설정한다.
- level은 로그의 심각도(error, warn, verbose, debug, silly 순, 중요도 순)
- info를 고른 경우 info보다 심각한 단계 로그도 같이 기록한다.
- format은 로그의 형식(json, label, timestamp, printf, combine, simple 등 지원)
- 기본적으로 json으로 기록하지만 로그 시간을 표시하려면 timestamp를 쓰는 게 좋다.
- transports는 로그 저장 방식
- new transports.File은 파일로 저장한다는 뜻, new transports.Console.은 콘솔에 출력한다는 뜻.
- 인자로 finename(파일명), level(심각도) 제공
// logger.js
const { createLogger, format, transports } = require('winston');
const logger = createLogger({
level : 'info', // 심각도
format : format.json(), // 로그의형식
transports : [ // 로그 저장 방식
new transports.File({ filename : 'combined.log'}),
new transports.File({filename : 'error.log', level : 'error'}),
],
});
if(process.env.NODE_ENV !== 'production') {
logger.add(new transports.Console({ format : format.simple()}));
}
module.exports = logger;
// app.js
...
const logger = require('./logger');
...
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
logger.info('hello');
logger.error(error.message);
next(error);
});
...
19. helmet, hpp로 보안 관리하기
⇒ 모든 취약점을 방어해주진 않지만 실무에서 필수인 패키지
- 배포 환경일 때만 사용하면 되며 필요없는 옵션들은 해제해서 반영한다.
$ npm i helmet hpp
// app.js
...
const helmet = require('helmet');
const hpp = require('hpp');
...
if (process.env.NODE_ENV === 'production') {
...
app.use(helmet({
contentSecurityPolicy : false,
crossOriginEmbedderPolicy : false,
crossOriginResourcePolicy : false,
}));
app.use(hpp());
...
} else {
...
}
20. connect-redis
⇒ 멀티 프로세스 간 메모리 공유를 위해 redis를 사용한다.
- connect-redis가 익스프레스와 레디스를 연결해준다.
$ npx i redis connect-redis
⇒ 레디스 호스팅 생성 완료 후 Endpoint와 Redis password를 복사해 .env에 값 삽입
// .env
...
REDIS_PASSWORD=x5qAUOzdJ1mEoC7lGmts7dh1xvO1VcWS
REDIS_HOST=redis-11793.c323.us-east-1-2.ec2.cloud.redislabs.com
REDIS_PORT=11793
28. connect-redis 연결하기
⇒ app.js express.session 미들웨어 부분에 store 속성을 추가한다.
- RedisStore 생성자의 인스턴스를 store 속성에 등록한다.
...
const redis = require('redis');
const RedisStore = require('connect-redis').default;
...
const redisClient = redis.createClient({
url : `redis://${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
password : process.env.REDIS_PASSWORD,
legacyMode : false, (버전에 따라 상태값이 다를 수 있으므로 유의)
});
redisClient.connect().catch(console.error);
...
const sessionOption = {
resave : false,
saveUninitialized : false,
secret : process.env.COOKIE_SECRET,
cookie: {
httpOnly : true,
secure : false, // https여부
},
// store의 기본값은 메모리이므로 레디스에 저장하는 것으로 변경 처리
store : new RedisStore({ client : redisClient}),
};
29. nvm, n
⇒ 노드 버전을 업데이트하기 위한 패키지이다.
- 윈도우에서는 nvm-installer, 리눅스/맥에서는 n 패키지
30. nvm-installer
⇒ https://github.com/coreybutler/nvm-windows/releases
- nvm-setup.zip을 내려받아 압축 해재 후 실행한다.
- nvm list로 노드 버전을 확인, nvm instal로 버전을 설치한다(nvm install lastest로 최신버전을 설치한다)
$ nvm list
* 21.6.0 (Currently using 64-bit executable)
$ nvm install 21.6.0
Version 21.6.0 is already installed. // 현재 최신버전이므로 기존버전 유지
31. nvm-installer로 노드 버전 바뀍
⇒ nvm use [버전명] 명령어로 버전 변경 가능
$ nvm use 18.7.0
Now using node v18.7.0 (64-bit)
$ node -v
v18.7.0
32. 맥, 리눅스에서 n으로 노드 업데이트
⇒ n을 전역설치
- n 명령어로 현재 노드 버전을 확인 및 n 버전으로 새 버전 설치
$ sudo npm i -g n
$ n 18.7.0
installed v18.7.0
$ node-v
v18.7.0
15.2 Git과 GitHub 사용하기
1. Git으로 소스코드 관리하기
⇒ 배포 후 소스 코드가 수정될때마다 직접 업로드하는 것이 불편하므로 소스의 형상관리가 필요하다.
- 협업 시에도 서로 소스가 다를 경우 소스 충돌이 발생한다.
- Git이라는 분산형 버전 관리 시스템을 사용하여 위 사항들을 해소하여 여러 사람의 코드를 공동관리할 수 있다.
- GitHub는 GIt으로부터 업로드한 소스코드를 서버에 저장할 수 있는 원격 저장소이다.
- https://git-scm.com/downloads : git 설치경로
4. git 명령어 사용하기
⇒ 콘솔에서 git --version 입력하여 버전을 확인할 수 있다.
$ git --version
git version 2.43.0.windows.1
⇒ .gitgnore에 git으로 소스 관리하지 않을 파일과 디렉터리를 등록한다.
// .gitignore
node_modules
uploads
*.log
coverage
.env
5. GibHub 사용하기
⇒ github.com 에 접속하여 회원가입, 플랜은 무료 Plan 선택(Choose Free)
⇒ GitHub 리포지터리를 생성한다.
- 좌측 Create repository 버튼을 클릭
- 리포지터리 이름은 node-deploy로 하고 Create repository 버튼을 클릭한다.
⇒ 생성 완료 화면 확인 후 콘솔로 이동
10. 프로젝트에 git 설정하기
⇒ nodebird 프로젝트로 이동 후 git init 명령어 입력
$ git init
Initialized empty Git repository in C:/nodejs/nodebird/.git/
11. 모든 파일을 git에 추가하기
$ git add .
warning : LF will be replaced by CRLF in models/index.js.
The file will have its original line endings in your working directory.
...
12. 소스 코드 커밋하기
⇒ 사용자 정보를 설정한 후 소스 코드 커밋(상태 저장)
$ git config --global user.email "ykji1003@hotmail.co.kr"
$ git config --global user.name "jaeikKim"
$ git commit -m "Initial commit"
[master (root-commit) cf7ad51] Initial commit
24 files changed, 5322 insertions(+)
create mode 100644 .env
create mode 100644 .gitignore
create mode 100644 app.js
...
13. 개인 접근 토큰 발급하기
⇒ https://github.com/settings/tokens 에서 Generate new token 클릭
14. GitHub 주소 등록하기
⇒ 아이디와 비밀번호 부분을 자신의 토큰으로 교체한다.
- remote할 때 별명, 주소를 잘못 입력했을 경우 : git remote rm [별명] 명령어를 사용 해 지운 후 다시 git remote add한다.
$ git remote add origin https://아이디:토큰@github.com/아이디/node-deploy
15. gibHub에 코드 올리기
⇒ git push origin master 입력해 소스 코드가 깃허브에 올라간 것을 확인할 수 있다.
$ git push origin master
15.3 AWS 시작하기
1. AWS 이용하기
⇒ aws.amazon.com/ko 에 접속해서 회원가입 수행
⇒ 간단하게 노드 서비스를 배포할 수 있는 Lightsail을 선택한다.
⇒ 인스턴스 생성
⇒ 인스턴스의 시작지점은 한국과 가까울수록 이점이 많다. Linux와 Node.js를 선택한다.
⇒ 인스턴스 계획을 선택( 첫 세달은 무료)
⇒ 생성된 인스턴스를 확인한다.
⇒ 인스턴스 삭제 방법( 첫 세달만 무료이므로 반드시 삭제필요)
15.4 AWS에 배포하기
1. SSH 연결하기
⇒ SSH를 사용하여 연결 버튼을 클릭한다.
2. LightSail 콘솔을 열어 Mysql을 설치한다.
$ sudo apt-get update
$ sudo apt-get install -y gnupg
$ sudo wget https://dev.mysql.com/get/mysql-apt-config_0.8.23-1_all.deb
$ sudo dpkg -i mysql-apt-config_0.8.23-1_all.deb
⇒ sudo apt update 오류 참고링크 : https://weich.tistory.com/28
$ sudo apt update (여기서 오류발생함)
$ sudo apt-get install -y mysql-server
⇒ 비밀번호 설정 후 Use Lengacy Authentication Method 선택
⇒ Mysql 프롬프트 접근 후 비밀번호 수정 명령어를 입력한다.
bitnami@ip-172-26-1-117:~$ sudo mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 95
Server version: 8.0.36 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '0000';
Query OK, 0 rows affected (0.08 sec)
mysql> exit;
3. Github에서 소스 내려받기
⇒ git clone 명령어로 소스 내려받기
- github에서 공개 리포지터리는 비밀번호가 필요하지 않다.
- 비밀번호가 필요한 경우는 깃헙 비밀번호를 발급받는 게 아니라 pat를 발급받아야 한다
$ git clone https://github.com/아이디/node-deploy
4. 퍼블릭 IP 확인 후 브라우저에 입력해 접속
6. 추가로 알아둘 점
⇒ Https를 사용하고자 하면 도메인을 발급 받아야 한다. ( 도메인 구입 후 AWS의 Route 53번 서비스에서 연결)
⇒ 수정된 소스코드 반영하기
- 추후 소스 코드를 수정해서 업데이트 된 내용으로 배포하고 싶을 때는 git clone이 아니라 git pull 명령어 사용
$ git pull
$ sudo pm2 reload all
// 서버가 재시작되면서 변경 내용들이 반영된다.
'BackEnd > Node' 카테고리의 다른 글
[노드교과서] 섹션 15. 16장 AWS 서버리스(S3+Lambda) 사용하기 (0) | 2024.02.05 |
---|---|
[노드교과서] 섹션 13. 14장 CLI 프로그램 만들기 (2) | 2024.01.31 |
[노드교과서] 섹션 12. 13장 실시간 경매 시스템 만들기(서버센트이벤트, 스케줄링) (2) | 2024.01.31 |
[노드교과서] 섹션 11. 12장 실시간 GIF 채팅방 만들기(웹소켓, Socket.IO) (0) | 2024.01.28 |
[노드교과서] 섹션 10. 11장 테스트 해보기(단위, 통합, 부하) (0) | 2024.01.25 |