환경 

Ubuntu 18.04
Nodejs
Express


1. certbot 을 설치해주자

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

2. 실행

sudo certbot certonly --manual

3. 이메일 입력

처음 실행시키면 이메일 입력하라는 커맨드가 나올 것이다. 입력해주면 된다!
도메인 입력하라고 뜨기 전까지 Y.

4. 인증서를 발급할 도메인 주소 입력

http & https 빼고 그냥 도메인만 입력하자.

5. Y 입력하고 엔터!

 

6. 중요! 여기서 일단 멈춘다.

사진에서 a-string과 a-challenge내용은 다른 문자열이 적혀있을 것이다.
그냥 a-string과 a-challenge이라 부르겠다.

http://도메인/.well-known/acme-challenge/a-string 라는 내용이 보일 것이다.
저 주소로 요청을 보내어 인증서를 발급 할지 말지 인증을 하는 과정을 거치는 것 같았다. 
그래서 우리는 접속 경로를 만들어 줘야한다.

7. 경로 폴더 & 파일 생성

프로젝트파일 root
ㄴ public
  ㄴ .well-known
    ㄴ acme-challenge
      ㄴ 위 이미지 속 a-string 부분 복사해서 파일 이름으로 생성

8. 새로 생성한 a-string파일 내용으로 위 이미지의 a-challenge 라고 적힌 부분의 내용을 입력해주고 저장하자. 

9. 그리고 기다리고 있었던 콘솔창 엔터!

그럼 위 사진과 같이 인증서가 발급 된 것을 알 수 있다.

sudo cd /etc/letsencrypt/live/도메인

위 경로로 들어가면 pem 파일이 있을 것이다.

10. app.js 파일에 붙여 넣어서 제대로 https로 접근이 가능한지 확인해보자!

/* app.js */

// Dependencies
const fs = require('fs');
const http = require('http');
const https = require('https');
const express = require('express');

const app = express();

// Certificate 인증서 경로
const privateKey = fs.readFileSync('/etc/letsencrypt/live/도메인 입력/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/도메인 입력/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/도메인 입력/chain.pem', 'utf8');

const credentials = {
	key: privateKey,
	cert: certificate,
	ca: ca
};

app.use((req, res) => {
	res.send('Hello there !');
});

// Starting both http & https servers
const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);

httpServer.listen(80, () => {
	console.log('HTTP Server running on port 80');
});

httpsServer.listen(443, () => {
	console.log('HTTPS Server running on port 443');
});
sudo node app.js

 

아래 이미지와 같이 인증서가 유효하게 뜨는 것을 볼 수 있다.

 

출처
https://itnext.io/node-express-letsencrypt-generate-a-free-ssl-certificate-and-run-an-https-server-in-5-minutes-a730fbe528ca

'Develop > Node.js' 카테고리의 다른 글

PM2 80, 443포트 사용  (0) 2020.06.20
[Nodejs] Multer - Formdata 전송  (0) 2020.05.25
[Nodejs] Sequelize - 설치 & 마이그레이션  (0) 2020.05.18

[ 주의 ] 삽질하면서 코딩한 경험을 바탕으로 작성한 것임으로 틀린것도 많으니 더 좋은 정보가 있으면 알려주세요!

[ 잡담 ]

요즘들어 새로 시작한 프로젝트가 있어서 12시에 기상해서 새벽 4~6시까지 코딩만 죽어라 하고 있다.

실제로 유저들에게 상용시킬 서비스를 제작하는 것이란 대학교 때 졸업작품을 개발하는 것과는 비교도 안될 정도로 많은 변수를 생각해야하기 때문에 시간이 많이 든다.

덕분에 정말 많은 삽질을 하고 있다. 하지만 이 삽질 끝에 문제를 해결하고 잘 작동하는 모습을 보면 너무 너무 재밌다.

그럼 본론으로 들어가 Multer에 대해서 알아보겠다.

+ 지금까지 Multer를 사용하면서 겪은 3가지 삽질

[ Multer ]

정의: Multersms Multypart / form-data 형식의 Request을 다루기 위한 Node.js 미들웨어이다.

설치

> npm install --save multer

1. Formdata 받기

나는 처음에 Multer의 존재를 몰랐다. 프론트에서 Formdata를 axios로 넘겨줬지만 req.body, res.file, res.files 전부 console.log로 찍어봤지만 빈값만 들어가 있었다. 이게 새벽 2~4시까지 골머리를 썩혔다.

찾다 찾다보니 Multer라는 친구를 발견했고 아래와 같이 작성해주면 formdata 값을 받을 수 있다고 해서 적용해 봤다.

1) single

  • 파일 한 개만 받을 경우에 사용한다.
  • req.file에 이미지 데이터가 담겨있다.
  • avatar는 formdata.append("avatar": value); 에서 value의 key값을 의미한다.
app.post('/profile', upload.single('avatar'), function (req, res, next) {})

2) array

  • 여러개의 이미지 파일을 하나의 key값으로 받아올 수 있다.
  • 구분없이 여러개의 이미지를 받을 때 좋은듯?
  • req.files에 데이터가 담겨있다.
  • 12 숫자는 넘겨 받는 이미지 갯 수를 나타낸다. 한계를 정해두고싶지 않다면 그냥 key값만 적으면 된다.
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {})

3) fields

  • 전체적으로 array와 큰 차이를 모르겠다. 확장 버전인듯?
  • key값을 구분하여 데이터를 분류해서 받고 싶다면 사용하자.
  • req.file에 데이터가 담겨있다.
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {})

4) none

  • 안써봐서 몰라.
  • text만 담긴 formdata 받으라고 한다.

5) any

  • 마찬가지로 안써봄.
  • 유선으로 오는 모든 파일 다 받을 수 있다고 적혀잇다.

2. 그래도 값이 넘어오지 않는 경우

자! 열심히 알아봤다. 이제 받아져야지? 라고 생각한 나의 실수였다. 계속해서 데이터가 넘어오지 않았다. 여기서 삽질 또 시작.

문제는 프론트의 axios에 있었다. axios를 사용하면 받아지지 않았지만 아래의 코드를 사용하니 값이 넘어왔다.

var req = new XMLHttpRequest()
var file = new Blob(['This is a test'], { type: 'text/plain' })
var data = new FormData()

data.append('photo', file, 'test.txt')

req.open('POST', '/upload')
req.send(data)

3. 저장 폴더를 유동적으로 바꾸기

난 aws s3에 이미지 파일을 저장해야했기 때문에 multer-s3도 사용했다.

multer의 구조는 좀 이상했다. 프론트로 받은 데이터를 기반으로 이미지가 저장될 폴더를 만들고 싶었지만 

app.post('/image', s3.upload.single('avatar'), function (req, res, next) {})

이렇게 req로 받기도 전에 파일에 저장을 때리는데 어떻게 하란 말인가...

그래서 아래와 같은 방법으로 파일명을 고쳐보기로 했다.

/* router file */

const express = require('express');
const router = express.Router();
const ctrl = require('../api/c_board');
const multer = require("multer");
const {new_s3_storage} = require("../utils/u_s3_storage");


// s3를 빈 값으로 선언했더니 아래 라우터에서 빈 값에 
// array() 함수가 없다고 에러가 떠서 저장 폴더가 고정된 s3객체를 넘겨줬다
let s3 = require("../utils/u_s3");

// 해당 middleware부터 먼저 실행되고 아래 /image가 실행된다
router.use('/image', (req, res, next) => {

    // 프론트로부터 받은 데이터
    var bo_id = req.headers.bo_id;
    
    // 데이터를 매개변수로 넘겨 새로운 s3 storage 객체 생성
    var s3_storage = new_s3_storage(bo_id);
    
    // 기존 s3에 새로만들어진 s3 storage로 덮어준다
    s3 = multer({ storage : s3_storage });
    
    next();
})

router.post('/image', s3.array('img'), ctrl.image);

module.exports = router;

middleware를 사용해서 /image로 들어가기 전에 header 값으로 프론트로부터 받은 데이터(req.headers.bo_id)로 새로운 storage 객체를 만들어 s3에 덮어씌울 계획이었다.

 결과는 실패!

let s3 = require("../utils/u_s3"); 값이 middleware에서 아무리 덮어씌어도 안바뀌더라.

그렇게 구글을 이리저리 떠돌면서 해답을 찾던 도중 정답을 발견했다.

▼ 완성 코드

/* router file */

// lib
const express = require('express');
const router = express.Router();
const ctrl = require('../api/c_board');

// modules
let s3 = require("../utils/u_s3");

router.post('/image', s3.upload.array('img'), ctrl.image);

module.exports = router;

/* ../utils/u_s3.js */

// lib
const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const path = require('path');

// config
const aws_crediential = require("../config/aws");

const s3 = new AWS.S3(aws_crediential);

let params = {
  Bucket: 'deac-project',
  ACL: 'public-read-write'
};

let s3Storage = multerS3({
  s3: s3,
  bucket: params.Bucket,
  key: function(req, file, cb) {
    // 요거 하나로 해결
    var bo_id = req.headers.bo_id;
    let extension = path.extname(file.originalname);
    let basename = path.basename(file.originalname, extension);
    // 아래 코드에서 header로 받은 bo_id를 활용하여 저장되는 파일이 유동적으로 바뀜
    cb(null, `images/${bo_id}/${basename}-${Date.now()}${extension}`);
  },
  acl: 'public-read-write',
  contentDisposition: 'attachment',
  serverSideEncryption: 'AES256'
});

exports.upload = multer({ storage: s3Storage });

그냥 multerS3에 있는 key 함수에서 req.headers.bo_id를 사용하니 불러와졌다.

multerS3안의 key함수의 req에도 프론트에서 보낸 데이터가 똑같이 포함되어 있을 줄은 몰랐다.

file데이터만 있을줄 알았는데...

 

이렇게 삽질이 끝났다.

 

출처

https://velog.io/@josworks27/2020-01-18-0001-%EC%9E%91%EC%84%B1%EB%90%A8-qrk5iamlmv

+ Recent posts