next.js
와 express.js
의 운영배포설정 및 과정을 정리해보자.
package.json
에 빌드 스크립트를 작성하고 빌드를 해보자.
"prestart": "NODE_ENV=production next build",
"start": "NODE_ENV=production next start"
빌드를 하면 .next
폴더가 생성되는데 이쪽에 생성된 파일들을 next start
시에 읽는다.
.next
폴더는 .gitignore
에 포함시킨다.
만약 redux를 사용시에는 운영환경일때 redux상태가 보이지 않도록 하는 부분을 추가해준다.
아래 예는 saga를 같이 사용한 경우의 예이다.
import { createStore, applyMiddleware, compose } from 'redux'
import { createWrapper } from 'next-redux-wrapper'
import { composeWithDevTools } from 'redux-devtools-extension'
import createSagaMiddleware from 'redux-saga'
import rootReducer from '../reducers/rootReducer'
import rootSaga from '../sagas'
const makeStore = () => {
const sagaMiddleWare = createSagaMiddleware()
const middlewares = [sagaMiddleWare]
const enhancer =
process.env.NODE_ENV === 'production'
? compose(applyMiddleware(...middlewares))
: composeWithDevTools(applyMiddleware(...middlewares))
const store = createStore(rootReducer, enhancer)
store.sagaTask = sagaMiddleWare.run(rootSaga)
return store
}
const wrapper = createWrapper(makeStore, {
debug: process.env.NODE_ENV !== 'production'
})
export default wrapper
next.config.js는 내부적으로 webpack설정이 디폴트로 되어있는데 커스텀도 가능하다.
운영모드일때는 webpack devtool 모드를 hidden-source-map을 해줘야지 소스를 숨길수 있다.
module.exports = {
compress: true,
...
webpack(config, { webpack }) {
const prod = process.env.NODE_ENV === 'production'
return {
...config,
mode: prod ? 'production' : 'development',
devtool: prod ? 'hidden-source-map' : 'eval',
plugins: [...config.plugins]
}
}
}
logger middleware for node.js 다른 logger
모듈을 사용해도 무방하다.
const morgan = require('morgan')
app.use(morgan(<format>, <option>))
confined
: production
환경에 적합한 format
dev
: development
환경에 적합한 format
express-session
사용시 설정을 환경에 따라 달리하자
const session = require('express-session')
app.use(session(<sessionOption>))
const sessionProdOpt = {
resave: false,
saveUninitialized: false,
secret: process.env.SECRET,
cookie: {
httpOnly: true,
secure: true
}
proxy: true,
}
const sessionDevOpt = {
resave: false,
saveUninitialized: false,
secret: process.env.SECRET,
cookie: {
httpOnly: true,
secure: false
}
}
sequelize
를 기준으로 DB
설정 값을 변경한다고 하자
config.js
의 username
, password
, database
, host
를 환경별로 .env
에 설정해준다.
require('dotenv').config()
module.exports = {
development: {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
dialect: 'mysql'
},
test: {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
dialect: 'mysql'
},
production: {
username: process.env.DB_PROD_USER,
password: process.env.DB_PROD_PASSWORD,
database: process.env.DB_PROD,
host: process.env.DB_PROD_HOST,
port: process.env.DB_PORT,
dialect: 'mysql',
logging: false // sql문이 로깅되지 않는다.
}
}
app.listen(process.env.PORT, () => {
logger.info(`server on ${process.env.PORT}`)
})
heroku
로 테스팅한다고 할 때 참고링크앞서 morgan
이라는 logger를 사용했는데 winston
을 사용하는 이유는 두 모듈에 사용목적이 다르기 때문이다. morgan
은 http
요청과 응답을 format
화 하여 http
관련 로깅을 확인하는데 좋다. 하지만 이런 로깅을 파일이나 db에 남겨 놓지 않는다면 문제발생시 에러추적을 하기 어렵다. 이럴때 winston
을 사용하여 logging을 저장해 둘 수 있다.
AWS, GCP 같은 클라우드를 사용시에는 보통 console.log
를 사용해도 로깅이 파일이나 디비에 저장되지만, 클라우드를 사용하지 않는 경우에는 console.log
가 파일이나 디비에 남겨지지 않을 수 있다. 따라서 winston
을 사용해서 파일이나 db에 logging
을 남길 수 있다.
winston
사용예 링크
세션store를 사용해야지 서버가 재시작 되더라도 세션이 유지된다. 따라서 운영시에는 메모리스토어를 사용하지 않는데 Redis
를 한번 사용해보자.
app.js
의 store
에 client
로 연결해준다.//redisClient.js
const redis = require('redis')
const Logger = require('./logger')
require('dotenv').config()
const redisClient = redis.createClient({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD
})
redisClient.unref()
redisClient.on('ready', () => {
Logger.debug('✅ redis is ready')
})
redisClient.on('connect', () => {
Logger.debug('✅ redis is connected')
})
redisClient.on('reconnecting', () => {
Logger.debug('✅ redis is reconnecting')
})
redisClient.on('end', () => {
Logger.debug('✅ redis is end')
})
redisClient.on('error', (error) => {
Logger.error(error)
})
module.exports = redisClient
//app.js
const redisClient = require('./redisClient')
store: new RedisStore({ client: redisClient })
기타사항으로 조치해줄 것들
npm audit
//if any
npm audit fix
The audit
command submits a description of the dependencies configured in your project to your default registry and asks for a report of known vulnerabilities.
Helmet helps you secure your Express apps by setting various HTTP headers. It's not a silver bullet, but it can help!
위에 설명은 helmat
패키지를 소개해주는 말이다. 웹은 보안에 취약하기 때문에 보안에 도움이 될만한 패키지는 운영배포시에 꼭 설치해주자.
Express middleware to protect against HTTP Parameter Pollution attacks
위에 설명은 hpp
패키지를 소개해주는 말이다. 웹은 보안에 취약하기 때문에 보안에 도움이 될만한 패키지는 운영배포시에 꼭 설치해주자.