[배포] 설정 및 pm2

박재현·2022년 3월 25일
0

- express-session 옵션 설정

const sessionOption = {
    // 요청이 왔을 때 세션에 수정사항이 생기지 않더라도 다시 저장할지 여부
    resave: false,
    // 세션에 저장할 내역이 없더라도 세션을 저장할지
    saveUninitialized: false,
    // signed 되어 있기 때문에 읽을 수 없는 문자열로 되어 있음
    secret: process.env.COOKIE_SECRET,
    cookie: {
        httpOnly: true,
        secure: false,
    }
    // name: 'connect.sid', //default 이름
}
// 배포 모드일 시 프록시 추가
if (process.env.NODE_ENV === 'production') {
    // Nginx 쓸 때 필요 ( 설정해서 문제가 되는 경우는 없음, 설정을 안해서 문제가 되는 경우가 많음)
    // 실무에서는 대부분 proxy서버(Nginx) 를 사용 
    sessionOption.proxy =  true;
    // https 적용시에는 해당 secure true로 바꿔줘야 함
    // sessionOption.cookie.secure = true;
}
app.use(session(sessionOption))

- 그 외 추가사항

if ( process.env.NODE_ENV === 'production') {
    app.enable('trust proxy')   // 프록시 서버를 사용할 때 추가
  // 웬만한 실제 서비스 배포시 helmet, hpp 적용하기 (보안)
    // contentSecurityPolicy default: true -> 컨텐츠 로딩 시 외부 css, script 에서 에러나는 경우가 많으므로 디폴트를 false로 변경
    app.use(helmet( {contentSecurityPolicy: false} ));
    app.use(hpp());
    app.use(morgan('combined'));   // ip 를 비롯해 세부적인 사항 로그에 찍히게 하기 위해
}
else {
    app.use(morgan('dev'));
}

sequelize 사용 시 config.json 을 config.js로 바꿔서 .env 사용할 수 있게 해주기

config.js

const dotenv = require('dotenv')
dotenv.config();

module.exports = {
    "development": {
      "username": process.env.username,
      "password": process.env.password,
      "database": process.env.database,
      "host": "127.0.0.1",
      "dialect": "mysql"
    },
    "test": {
      "username": "root",
      "password": null,
      "database": "database_test",
      "host": "127.0.0.1",
      "dialect": "mysql"
    },
    "production": {
      "username": "root",
      "password": null,
      "database": "database_production",
      "host": "127.0.0.1",
      "dialect": "mysql"
    }
  }

models/index.js

	const config = require('../config/config.js')[env];

package.json

  • 환경변수를 통해 배포모드(production)로 app.js 시작할 수 있도록 설정

맥 환경

"scripts": {
    "start": "NODE_ENV=production PORT=80 pm2 start server.js -i 0",
    "dev": "nodemon server",
    "kill": "pm2 kill"
  },

윈도우 환경

npm i cross-env

"scripts": {
    "start": "cross-env NODE_ENV=production PORT=80 node server",

XSS(sanitize-html) 공격 방어

  • 허용하지 않은 html 입력을 막음
  • 아래 처럼 빈 문장열로 치환
const sanitizeHtml = require('sanitize-html');

const html = "<script>location.href = 'https://gilbut.co.kr'</script>";
console.log(sanitizeHtml(html)); // ''

CSRF(Cross Site Request Forgery) 공격 방어

  • npm i csurf
  • csrfToken을 생성해 프론트로 보내주고(쿠키로)
  • Form 등록 시 csrfToken을 같이 받아 일치하는지 비교
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true});

app.get('/form', csrfProtection, (req, res) => {
  res.render('csrf', { csrfToken: req.csrfToken() });
});

app.post('/form', csrfProtection, (req, res) => {
  res.send('Ok');
});

pm2 사용하기

  • 서버가 에러로 인해 꺼졌을 때 서버를 다시 켜 줌
  • 멀티 프로세싱 지원 (노드 프로세스 수를 1개 이상으로 늘릴 수 있음)하기 때문에 메모리 자원을 공유가 불가
  • 이를 극복하기 위해 memocached, redis 와 같은 DB 사용 ( 공유 메모리를 별도 DB에 저장)

설치 및 시작

  1. npm i pm2

  2. package.json 스크립트

"scripts": {
    "start": "NODE_ENV=production PORT=80 pm2 start server.js -i 0",
      // 뒤에 -i 0 붙이면 CPU 코어 개수만큼 프로세스 생성
      // -i -1 이면 CPU 갯수보다 1개 작은 수만 큼 생성 (fs, crypto와 같은 내장 모듈 실행할 수 있도록 풀어줌)
      // 어떤 것이 성능이 좋을지에 대해서는 테스트를 통해 확인해보기
  1. npm start

개발 환경의 경우 local 에서 80번 포트를 쓰고 있기 때문에 에러날 확률 높음
aws 서버에서는 80번 포트 열기

💡 로컬에서 pm2 사용 시 전역 명령어인 npx 붙여주기
ex) npx pm2 start server.js

명령어

npx pm2 list

  • pm2 가 돌아가고 있는 상황 확인 (이름, 재시작 횟수, 상태 등)

재시작 횟수가 많다면 에러가 있을 수 있다고 생각해 봐야함
리눅스나 맥의 경우 앞에 sudo를 붙여줘야할 수 있음

npx pm2 kill

  • pm2 서버 종료시키기

npx pm2 reload all

  • 현재 모든 서버들 재시작하기

npx pm2 monit

  • 서버 별 실시간 로그 파악하기

pm2 logs --err

  • 과거 에러 로그들 파악

0개의 댓글