새로운 강의는 이제 https://memi.dev 에서 진행합니다.
memi가 Vue & Firebase로 직접 만든 새로운 사이트를 소개합니다.
모던웹(NEMV) 혼자 제작 하기 3기 - 79 보안연결(ssl) 적용하기
보안연결을 구성하여 https로 접속 해보겠습니다.
실제 인증서를 사용해서 구현 할 것이기 때문에 무료 인증서는 “lets encrypt”를 검색해서 사용하세요~
이미 사 놓은게 있어서 무료 방법은 만료되면 다시 포스팅하겠습니다.
개요
최근 브라우저들은 보안연결(https)이 아닌 사이트는 위험사이트로 간주합니다.
폼(form)이 없는 단순 광고 페이지도 피해갈 수가 없습니다.
https로 신뢰할 수 있는 사이트를 제작하는 것은 이제 기본입니다.
고대디(godaddy)로 ssl을 구현해보겠습니다.
연간 8만원정도가 들어가니 지금은 참고하고 나중에 구현하셔도 됩니다.
도메인 연결하기
고대디 메뉴중 DNS 관리로 갑니다.
실제 서버의 아이피로 지정해 줍니다.
저의 경우엔 로드밸런서를 지정했습니다.
해당 인스턴스 한대에도 호스트명을 넣어서 설정 했습니다.
- fkkmemi.com: 로드밸런서
- nemv.fkkmemi.com: 인스턴스 중 하나
접속 순서는
fkkmemi.com -> 로드밸런서(133.186.246.151) -> 내부 인스턴스중 널널한 서버 교차 접속
위와 같이 방향 지시가 되는 것이죠.
구성에 필요한 파일들
3가지 파일만 있으면 준비물은 끝입니다.(꼭 ssl제공 업체가 고대디가 아니어도 됩니다.)
- key: 인증서를 만들 키 파일입니다.
- cert: 인증서입니다.
- ca: 인증된 기업 정보.
사이트 키 만들기
고대디에서 안내한 방법대로 만들어봅니다.
$ mkdir config/keys && cd config/keys
$ openssl req -new -newkey rsa:2048 -nodes -keyout site.key
Generating a 2048 bit RSA private key
.............................+++
...............................................................................+++
writing new private key to 'site.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:KO
State or Province Name (full name) []:Seoul
Locality Name (eg, city) []:Yongsan
Organization Name (eg, company) []:memi
Organizational Unit Name (eg, section) []:memiTeam
Common Name (eg, fully qualified host name) []:fkkmemi.com
Email Address []:fkkmemi@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
-----BEGIN CERTIFICATE REQUEST-----
MIICzzCCAbcCAQAwgYkxCzAJBgNVBAYTAktPMQ4wDAYDVQQIDAVTZW91bDEQMA4G
A1UEBwwHWW9uZ3NhbjENMAsGA1UECgwEbWVtaTERMA8GA1UECwwIbWVtaVRlYW0x
FDASBgNVBAMMC2Zra21lbWkuY29tMSAwHgYJKoZIhvcNAQkBFhFma2ttZW1pQGdt
YWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL7Oj6KS0dpB
U3IrhOLghbL0tGfki8gMx1zYAYYsS4eK6PFnyO2gXJ5eM5sscByEySrL8PCrBs49
HZgjCePxHmQWJX+EGQnZOS0RdkCM82Wewk96Y5wy4AMwEm568Q1rLMlwCCkhLzUO
akgL7B9s5477KKCQZ/NFPnVmgDSu9eiHiiwd8qPmTOf/KR+nkY6lqEracnmhv0Ev
Ht3zbN1d7eJj9e23w6ib1mx6QAGOkQ/cLLCHWfavKJZYvm0sowD/UeXQujo+Sl+7
9h6hzq+pSy45NCRPoXqig1Pbn6zMhT4oB0lGdSJi3YHC2A+t3WNxY2rj4LEr8RTX
tXY63puNWQ0CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCsakDswNNTGleH/gYh
cjYkWMr1+DWgQpWflhnm+AmO+dLdKlTeD6101n55GLlcx6oZIP/kCD1UwAD5Qi35
eRvjgwE7LVNhKHdl7H1R79IPUWurZ0ha1Wj5owA+PzU2z+bL09C1MGgtTrYPDjQ2
IiQWp0CZeUUlzfnlXplvnhLRmTbGZBEGxTzTus8WIW3xQ29valNNadFPdIEoyiOB
NgO+T9W2IHjR5bMxdsIEyx7jGnY1YW14y/ieKXTtOp72xCslyOaXg5TjOSy724nC
aW53taqFsZ810y29YNJ02q6z4lfVfM3GyUqCKK1wVztP70EQVPUvjwbK86rq/C0y
L9ZI
-----END CERTIFICATE REQUEST-----
—–BEGIN CERTIFICATE REQUEST—– 부터 —–END CERTIFICATE REQUEST—– 까지 긁어서 복사해 놓습니다.
인증서 받기
위에 복사해둔 내용을 고대디 인증서 등록 페이지(csr 내용 넣으라고 하는 곳)에 붙히고 기다립니다.
고대디에서 확인이 후(한 5분정도?) 다운로드 페이지로 연결되는 이메일을 보냅니다.
다운로드를 받으면 2가지 파일이 있습니다.
- c10ebb114e52c69b.crt(헥사파일명)
- gd_bundle-g2-g1.crt
각 파일 명을 변경해줍니다.
- c10ebb114e52c69b.crt -> cert.crt
- gd_bundle-g2-g1.crt -> ca.crt
변경후 config/keys 에 복사합니다.
- config/keys
- site.key
- cert.crt
- ca.crt
https 서버 구동 코드 만들기
기존 be/bin/www 파일 아래에 추가 합니다.
// ssl
const fs = require('fs')
if (fs.existsSync('./config/keys/site.key') && fs.existsSync('./config/keys/cert.crt') && fs.existsSync('./config/keys/ca.crt')) {
const https = require('https')
const httpsPort = process.env.PORT ? 443 : 3001
const o = {
key: fs.readFileSync('./config/keys/site.key'),
cert: fs.readFileSync('./config/keys/cert.crt'),
ca: [fs.readFileSync('./config/keys/ca.crt')]
}
const serverSSL = https.createServer(o, app).listen(httpsPort)
serverSSL.on('error', (error) => {
if (error.syscall !== 'listen') {
throw error
}
const bind = `port ${httpsPort}`
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
break
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
break
default:
throw error
}
})
serverSSL.on('listening', () => {
{
const addr = serverSSL.address()
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port
debug('HTTPS Listening on ' + bind)
}
})
}
인증에 필요한 파일들이 전부 있을 때만 https 서버를 구동시키는 것입니다.
포트(process.env.PORT) 가 설정되어 있지 않으면 3001로 지정합니다.
설정 되어 있다면(process.env.PORT = 80) 기본 https 포트인 443으로 여는 것입니다.
http 서버와 크게 다를 것은 없고, 옵션에 3파일만 들어가는 형태입니다.(위에 http코드를 그대로 복제해서 만듬..)
로컬호스트 구동
이대로 로컬에서 구동시키면 도메인과 일치하지 않기 때문에 경고 메세지가 뜹니다.
경고메세지대로 다른서버니 가장 했을 가능성이 있는 것이죠.
실제서버 구동
방화벽 열어주기
토스트 보안규칙에서 443포트를 열어줍니다.
로드밸런서를 위한 api 만들기
로드밸런서는 매 주기마다(기본 30초) 건강한지 파악합니다(health check).
그런데 기본 url은 /입니다.
무지막지한 데이터를 쓸데 없이 가져가는 것이죠.(fe/dist 폴더 죄다.. 물론 캐쉬되어서 2번째부터는 좀 작을 수도 있지만..)
api/lb를 만들어서 간단하게 건강하다고 알려줍니다.
be/routes/api/lb/index.js
const router = require('express').Router()
router.get('/', (req, res, next) => {
res.send({ success: true })
})
module.exports = router
be/routes/api/index.js
router.use('/lb', require('./lb'))
router.use('/sign', require('./sign'))
// ..
인증파일들 복사
해당 인스턴스 서버에 접속해서 인증 관련 파일들을 넣어줍니다.
서버에서 구동 한방에 해결하기
서버에 접속해서 최신 소스로 변경하는 방법을 파일로 만들면 편합니다.
build.sh
#!/bin/bash
cd /var/www/nemv/source
git pull
yarn
cd be
yarn
cd ..
cd fe
yarn
yarn build
cd ..
pm2 start
루트 디렉토리에가서
$ sh build.sh
명령어 한방이면 최신 소스로 업데이트하 모든 종속요소 설치 후 pm2가 재시작 됩니다.
추후 강좌에서는 이파일로 멀티 업데이트를 할 것입니다.
서버 로그 확인하기
$ pm2 log
이제 서버 로그를 켜놓고 요청을 파악할 준비가 되었습니다.
로드밸런서 https 리스너 등록
이제 443포트로 각 인스턴스서버에 /api/lb로 건강 체크를 할 것 입니다.
인스턴트 포트를 3001 로 해두고 외부에서 443으로 들어오면 내부 3001로 연결 시킬 수도 있습니다.
로드밸런서 상태 체크 확인하기
해당 인스턴스에서 주기마다 로드밸런서가 요청하는 모습입니다.
원래 /로 요청하다가 /api/lb로 요청이 변경되었습니다.
인증서 확인하기
브라우저에서 실제 사이트에 들어가서 인증서를 확인해봅니다.
고대디(godaddy)님이 저를 신뢰하고 인정해 주셨습니다.(돈만 내면 인정해주네요)
사용해보기
실제 사이트 적용 확인
ssl 작동: https://fkkmemi.com
ssl 미작동: https://nemv.fkkmemi.com
해당 인스턴스로 직접 들어가는 https://nemv.fkkmemi.com은 경고 표시가 나는 것을 볼 수 있습니다.
앞의 호스트명을 전부 커버하는 것을 와일드카드라고 하는데 전부 보호하려면 돈을 많이 내야됩니다.(약 연간 30만원이상)
http에 대해
그러면 http 포트(80)는 왜 열어두었을까요?
도메인만 입력해도 최신브라우저들은 앞에 http(s)://등을 붙혀주긴 하지만. 마지막 저장된 주소를 주로 사용합니다.
주소창에 fkkmemi.com으로 치면 브라우저별로 앞에 뭐가 붙을 지 모른다는 것입니다.
http 포트가 안열려있으면 브라우저에서는 그런 사이트가 없다고 나와버립니다.
결국 이유는 http로 들어오면 https로 이동시켜주거나 안내페이지 처리를 해야하기 때문입니다.
마치며
활용하기 편의 목적은 실제 서비스 구현입니다.
이제부터는 실제로 돌아가게 만들고 하나씩 기능을 추가하는 것입니다.
원래는 test.xxx.com 으로 테스트하고 xxx.com으로 배포하는 것이 좋습니다.
지금은 도메인이 없거나 ssl 구입이 안된 상태라 이 강좌를 패스하더라도 결국엔 꼭 봐야할 내용입니다.
웹사이트의 목적은 결국 서비스 이기 때문입니다.
댓글남기기