๊ธ€

Nginx์™€ CertBot์„ ์ด์šฉํ•˜์—ฌ ๊ตฌ์ถ•ํ•œ SSLํ™˜๊ฒฝ์„ ์‚ญ์ œํ•˜๋Š” ๋ฐฉ๋ฒ•

์ด๋ฏธ์ง€
  ํ•ด๋‹น ๊ธ€์€ " Nginx์™€ CertBot์„ ์ด์šฉํ•œ SSL ํ™˜๊ฒฝ ๊ตฌ์ถ• " ๊ธ€์˜ ํ›„์† ๊ธ€์ž…๋‹ˆ๋‹ค. SSL ์›น ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ–ˆ์ง€๋งŒ ํ•„์š”๊ฐ€ ์—†์–ด์ ธ์„œ ์‚ญ์ œ์‹œ ํ•ด๋‹น ๊ธ€์„ ์ฝ๊ณ  ์ง„ํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. "example.com" ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œ์‹œ. 1. conf.dํŒŒ์ผ์„ ์‚ญ์ œํ•œ๋‹ค. nginx๋กœ ๋„๋ฉ”์ธ๊ณผ ์—ฐ๊ด€๋œ ์„ค์ •ํŒŒ์ผ(.conf)๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.  ๋ณดํ†ต "example_http.conf", "example_https.conf"๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ด๋ฆ„์ด ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค. 2. ์‚ญ์ œํ›„ nginx๋ฅผ ํ…Œ์ŠคํŠธ ํ•ฉ๋‹ˆ๋‹ค. $ sudo nginx -t 3. ์‚ญ์ œํ›„ nginx๋ฅผ ์žฌ์‹œ์ž‘ ํ•ฉ๋‹ˆ๋‹ค. $ sudo nginx -s reload 4. certbot์— ์ธ์ฆ์„œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. $ sudo certbot certificates 5. certbot์˜ ์ธ์ฆ์„œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค. $ sudo certbot delete --cert-name example.com

Go ์„œ๋ฒ„ ๊ฐœ๋ฐœ์‹œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฝ”๋“œ ์ ์šฉํ•˜๊ธฐ(air)

์ด๋ฏธ์ง€
 air Link :  https://github.com/air-verse/air Go ์„œ๋ฒ„๋ฅผ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด "go run main.go"๋ฅผ ๊ณ„์† ํ„ฐ๋ฏธ๋„์— ์น˜๋ฉฐ ์„œ๋ฒ„๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ๋น„ํšจ์œจ์ ์ด๋ฉฐ ๋งค์šฐ ๋ถˆํŽธํ•œ ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. NodeJS์˜ nodemon( Link )๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ• ์ˆ˜์žˆ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์ฐพ๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ฆผ1) Air GitHub ํŽ˜์ด์ง€ Air๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์•Œ๊ฒŒ ๋˜๊ณ  ์ ์šฉ์„ ํ•˜์˜€๋‹ค. 1. Air ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ - ์ตœ์‹ ๋ฒ„์ „ $ go install github.com/air-verse/@latest copy 2. Air ์„ค์ •ํŒŒ์ผ ์ƒ์„ฑ - ์„ ํƒ์‚ฌํ•ญ $ air init copy 3. Air ์‹คํ–‰ - ํŒจํ‚ค์ง€ ํด๋” ๋‚ด์—์„œ $ air copy ์‚ฌ์ง„2) air ์‹คํ–‰ํ›„ ๊ฒฐ๊ณผ 3๋ฒˆ๊นŒ์ง€ ์ง„ํ–‰ํ•œ๋‹ค๋ฉด ์ด์ œ Go ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐ”๋กœ ๋ฐ˜์˜์ด ๋œ๋‹ค.

Go Fiber ํŒจํ‚ค์ง€๋กœ ๊ฐ„๋‹จํ•œ HTTP Get์š”์ฒญ API ๋งŒ๋“ค๊ธฐ

์ด๋ฏธ์ง€
  Fiber ๊ณต์‹ GitHub ๋งํฌ :  https://github.com/gofiber/fiber 1. go mod ์ดˆ๊ธฐํ™” (์œ„ ์˜ˆ์ œ์˜ ํŒจํ‚ค์ง€ ์ด๋ฆ„์€ fiber_http ์ด๋‹ค.) $ go mod init fiber_http copy 2. fiber ํŒจํ‚ค์ง€ ์„ค์น˜ $ go get -u github.com/gofiber/fiber/v3 copy 3. main.go ์ž‘์„ฑ package main import (   " fmt "   " log "   " github.com/gofiber/fiber/v3 " ) func main () {   fmt . Println ( "Go Fiber ํŒจํ‚ค์ง€๋กœ ๊ฐ„๋‹จํ•œ HTTP Get ์š”์ฒญ API ๋งŒ๋“ค๊ธฐ" )   // Initialize a new Fiber app   app := fiber . New ()   // Define a route for the GET method on the root path '/'   app . Get ( "/" , func ( c fiber . Ctx ) error {     // Send a string response to the client     return c . SendString ( "Hello, World ๐Ÿ‘‹!" )   })   // Start the server on port 3000   log . Fatal ( app . Listen ( ":3000" )) } 4. ํŒจํ‚ค์ง€ ์‹คํ–‰ํ•˜๊ธฐ - ๋นŒ๋“œ $ go build copy 5. ํŒจํ‚ค์ง€ ์‹คํ–‰ํ•˜๊ธฐ - go exe ํŒŒ์ผ $ ./[์‹คํ–‰ํŒŒ์ผ]

systemctl๋กœ ์‹คํ–‰๋˜๋Š” ์„œ๋น„์Šค ์‚ญ์ œํ•˜๊ธฐ

์ด๋ฏธ์ง€
  systemctl์˜ ์„œ๋น„์Šค์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฑฐ๋‚˜ ์‚ญ์ œํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์—… ์ฐธ๊ณ  ์ž๋ฃŒ :  Linux์˜ systemd ์„œ๋น„์Šค๋กœ ๋ถ€ํŒ…์‹œ ์ž๋™ ์‹คํ–‰ํ•˜๊ธฐ ์„œ๋น„์Šค ์ค‘์ง€ $ sudo systemctl stop [์„œ๋น„์Šค๋ช…].service copy ์ž๋™์‹คํ–‰ ํ•ด์ œ $ sudo systemctl disable [์„œ๋น„์Šค๋ช…].service copy ์„œ๋น„์Šค ํŒŒ์ผ ์‚ญ์ œ $ sudo rm /etc/systemd/system/[์„œ๋น„์Šค๋ช…].service copy systemctl ๋ฆฌ๋กœ๋“œ $ sudo systemctl daemon-reload copy (์„ ํƒ์‚ฌํ•ญ) ์ƒํƒœ ์บ์‹œ ์ดˆ๊ธฐํ™” $ sudo systemctl reset-failed copy

NestJS Filter - HttpException ํ•„ํ„ฐ

์ด๋ฏธ์ง€
 NestJS ๊ณต์‹ ์„ค๋ช… :  https://docs.nestjs.com/exception-filters ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋‹ค๋ณด๋ฉด ์ผ์ •ํ•œ ๊ทœ๊ฒฉ์˜ ์‘๋‹ต์„ ํ•ด์•ผํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ํ”„๋ŸฐํŠธ์—์„œ ์ผ์ •ํ•œ ์–‘์‹์˜ ์—๋Ÿฌ์ฝ”๋“œ๋ฅผ ์‘๋‹ตํ•ด์•ผ ๋””๋ฒ„๊น… ํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.  HTTP์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ์‹œ ๊ธฐ์กด์€ HttpException์„ ์ด์šฉํ•ด์„œ ์—๋Ÿฌ๋ฅผ ์‘๋‹ตํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•ด์„œ ๋™์ผํ•˜๊ฒŒ ์‘๋‹ตํ•˜๋„๋ก ์ˆ˜์ •ํ• ์ˆ˜ ์žˆ๋‹ค. // src/common/http-expection.filter/http-expection.filter.ts import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common' ; import { Request, Response } from 'express' ; // HttpException์„ ๋ฐ›์•„์„œ ์ˆ˜์ •ํ›„ ์‘๋‹ต @ Catch ( HttpException ) export class HttpExceptionFilter implements ExceptionFilter {   catch ( exception : HttpException , host : ArgumentsHost ) {     const ctx = host . switchToHttp ();     const response = ctx . getResponse < Response >();     const request = ctx . getRequest < Request >();     const status = exception . getStatus ();     response       . status ( status )       . json ({     ...

NestJS Interceptor ๊ฐœ๋ฐœ - Global

์ด๋ฏธ์ง€
 Interceptors์˜ ๊ณต์‹ ์„ค๋ช… :  https://docs.nestjs.com/interceptors ์ธํ„ฐ์…‰ํ„ฐ(Interceptors)๋Š” Client์™€ Server์‚ฌ์ด์— ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๊ฐ€๋กœ์ฑ„์„œ ์กฐ์ž‘์„ ํ•œํ›„ ๊ธฐ์กด ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค. ์‚ฌ์ง„1) ๊ธฐ์กด ํ†ต์‹ ๋ฐฉ๋ฒ• ๊ธฐ์กด์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋กœ ํ†ต์‹ ์„ ๊ทธ๋Œ€๋กœ ํ•œ๋‹ค. ์‚ฌ์ง„2) Interceptors๊ฐ€ ์ถ”๊ฐ€๋œ ํ†ต์‹  ๊ทธ๋Ÿฐ๋ฐ ์š”์ฒญ, ์‘๋‹ต๊ฐ’์— ํ•ญ์ƒ ์ผ์ •ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ทœ๊ฒฉ์„ ๋งŒ๋“ค๋ ค๊ณ  ํ• ๋•Œ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌํ•˜๋‹ค. ์ฝ”๋“œ๋งˆ๋‹ค ์‘๋‹ต๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ Interceptors์—์„œ ์ž‘์„ฑํ•ด์„œ ์ผ๊ด„์ ์œผ๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์‚ฌ์ง„3) ๊ธฐ์กด ์‘๋‹ต NestJS์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฐ€์žฅ ๋จผ์ € ๋‚˜์˜ค๋Š” API๋Š” '/' ๋ฃจํŠธ์˜ GET ์š”์ฒญ์ด๋‹ค. ํ•ด๋‹น ์š”์ฒญ์€ NestJS์—์„œ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์‹œ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด ์ง„๋‹ค. ๊ธฐ์กด์˜ ์‘๋‹ต์€ "Hello World!"์˜ String๋งŒ ์‘๋‹ตํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์‘๋‹ต๋ฐฉ๋ฒ•์„ ๋ณ€๊ฒฝํ• ๋ ค๊ณ  ํ•œ๋‹ค. // src/common/interceptor/response.interceptor.ts import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common' ; import { Observable } from 'rxjs' ; import { map, tap } from 'rxjs/operators' ; export interface Response < T > {   data : T ; } @ Injectable () export class ResponseInterceptor < T > implements NestInterceptor < T , Response < T >> {   intercept ( context : ExecutionCont...

NextJS์— ๊ฐ„๋‹จํ•œ ๋ชจ๋‹ฌ์ฐฝ ๋„์šฐ๊ธฐ(next : 16.2.2 ver, react : 19.2.4 ver)

์ด๋ฏธ์ง€
 NextJS์— ๊ฐ„๋‹จํ•œ ๋ชจ๋‹ฌ์„ ๋„์šฐ๋Š” ๋ฐฉ๋ฒ• ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ด๋ฒˆ๊ธ€์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์˜ dependencies ๋ฐ devDependencies์ž…๋‹ˆ๋‹ค. "dependencies" : {     "next" : "16.2.2" ,     "react" : "19.2.4" ,     "react-dom" : "19.2.4"   },   "devDependencies" : {     "@biomejs/biome" : "2.2.0" ,     "@types/node" : "^20" ,     "@types/react" : "^19" ,     "@types/react-dom" : "^19" ,     "typescript" : "^5"   } ํด๋” ๋ฐ ํŒŒ์ผ ๊ตฌ์กฐ src |-app |   |- page.tsx |- component     |- modal          |- TestModal.module.css          |- TestModal.tsx page.tsxํŒŒ์ผ์€ ๋ฃจํŠธ ํŽ˜์ด์ง€๋กœ "Open Modal"๋กœ ์ž‘์„ฑ๋œ ๋ฒ„ํŠผ์ด ํ•˜๋‚˜๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฒŒ ๋˜๋ฉด "TestModal.tsx"ํŽ˜์ด์ง€๊ฐ€ ๋ชจ๋‹ฌ์ฐฝ์œผ๋กœ ์—ด๋ฆฝ๋‹ˆ๋‹ค. // src\app\page.tsx 'use client' ; import { TestModal } from "@/component/modal/TestModal" ; import { useState } from "react" ; export default function Home () {   // ๋ชจ๋‹ฌ์ฐฝ์˜ ์ƒํƒœ๋ฅผ...

Nginx์™€ CertBot์„ ์ด์šฉํ•œ SSL ํ™˜๊ฒฝ ๊ตฌ์ถ•

์ด๋ฏธ์ง€
  ํ•ด๋‹น ์„œ๋ฒ„์— Nginx๊ฐ€ ์„ค์น˜ ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์•„๋ž˜๊ธ€ ์ฐธ๊ณ  Nginx ์„ค์น˜ - Ubuntu ํŠน์ • ๋„๋ฉ”์ธ์„ Nginx์—์„œ ํ•ด์ œ ๋ฐ CertBot ์‚ญ์ œ ๋„คํŠธ์›Œํฌ ๊ตฌ์„ฑ IpTime ๊ณต์œ ๊ธฐ 1๋Œ€ (๋ชจ๋ธ : T5008SE) ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ์„œ๋ฒ„ 1๋Œ€ -01์„œ๋ฒ„ (๋ชจ๋ธ : JECS-N5095B, OS : Ubuntu 22.04, Nginx์„ค์น˜) ์„œ๋ฒ„ 1๋Œ€ - 02์„œ๋ฒ„ (๋ชจ๋ธ : JECS-8250B-i5, OS : Ubuntu 20.04) 1. ๊ณต์œ ๊ธฐ ํฌํŠธํฌ์›Œ๋”ฉ์€ 01์„œ๋ฒ„๋กœ ์ง€์ • TCP 80 -> 01์„œ๋ฒ„ : 80 TCP 443 -> 01์„œ๋ฒ„ : 443 2. ๋„๋ฉ”์ธ DNS๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ง„ํ–‰ (์ €๋Š” AWS์˜ Route53์‚ฌ์šฉ) example.com -> 01์„œ๋ฒ„ IP. A๋ ˆ์ฝ”๋“œ(wwwํฌํ•จ) 02์„œ๋ฒ„๋Š” 3000ํฌํŠธ๊ฐ€ ์„œ๋น„์Šค ํฌํŠธ์ด๋‹ค. ๋”ฐ๋ผ์„œ Nginx๊ฐ€ ํ”„๋ก์‹œ ์š”์ฒญ์„ ๋ฐ›์„์‹œ 02์„œ๋ฒ„์˜ 3000ํฌํŠธ๋กœ ์—ฐ๊ฒฐํ•ด ์ค˜์•ผ ํ•œ๋‹ค. 3-1. CertBot์„ ์„ค์น˜ํ•œ๋‹ค. apt ์—…๋ฐ์ดํŠธ $ sudo apt update copy snapd ์„ค์น˜ $ sudo apt install -y snapd copy ์ฝ”์–ด ์„ค์น˜ ๋ฐ ์ƒˆ๋กœ๊ณ ์นจ $ sudo snap install core; sudo snap refresh core copy Snap๋ฅผ ์ด์šฉํ•ด์„œ certbot ์„ค์น˜ $ sudo snap install --classic certbot copy "/usr/bin/certbot" -> "/snap/bin/certbot"์œผ๋กœ ๋ฐ”๋กœ๊ฐ€๊ธฐ(์‹ฌ๋ณผ๋ฆญ ๋งํฌ) ์„ค์ • $ sudo ln -s /snap/bin/certbot /usr/bin/certbot copy certbot ๋ฒ„์ „ ํ™•์ธ (์‚ฌ์šฉ๋ฒ„์ „ : 5.2.2) $ certbot --version copy 4. 01์„œ๋ฒ„๋ฅผ ํ†ตํ•ด์„œ SSL์ธ์ฆ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ธ์ฆ์„œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋จผ์ € ์ธ์ฆ์„ ๋ฐ›๊ธฐ์œ„ํ•œ Nginx confํŒŒ์ผ์„ ์ƒ์„ฑ - ๋„...

Nginx ์„ค์น˜ - Ubuntu

์ด๋ฏธ์ง€
 Nginx ๊ณต์‹ ์‚ฌ์ดํŠธ :  https://nginx.org/ Nginx ๊ณต์‹ ๋ฌธ์„œ :  https://nginx.org/en/docs/ ์„ค์น˜์‹œ ์ฐธ๊ณ ํ•œ ๊ณต์‹ ๋ฌธ์„œ :  https://nginx.org/en/linux_packages.html 1. apt ์—…๋ฐ์ดํŠธ $ sudo apt update copy 2. ํ•„์š” apt install $ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring copy 3. ๊ณต์‹ nginx ์„œ๋ช… ํ‚ค๋ฅผ ๋‹ค์šด $ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null copy 4. ๊ณต์‹ nginx ์„œ๋ช… ํ‚ค๋ฅผ ๊ฒ€์ฆ $ gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg copy 5. Nginx ํŒจํ‚ค์ง€์˜ ์•ˆ์ •์  ์„ค์น˜๋ฅผ ์œ„ํ•˜์—ฌ ์ปค๋ฉ˜๋“œ ์‹คํ–‰ $ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list 6. Nginx ์„ค์น˜ $ sudo apt install nginx copy 7. Nginx ๋™์ž‘ํ™•์ธ $ sudo systemctl status nginx copy 8. Nginx ๋ฒ„์ „ํ™•์ธ $ nginx -v copy nginx๊ฐ€ ์‹คํ–‰๋˜๋Š” ์›น์‚ฌ์ดํŠธ์— ์ ‘์†ํ•˜๋ฉด ์œ„ ์‚ฌ์ง„...

Git Action - GitHub Secrets๋ฅผ Build๊ณผ์ •์— ๋„ฃ๊ธฐ

์ด๋ฏธ์ง€
 NextJS ๋˜๋Š” React๋ฅผ ๋ฐฐํฌํ• ๋•Œ Build ๋˜๋Š” "npm run dev"๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐฐํฌ๋ฅผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ "npm run dev"์‹œ์ ์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์ ์šฉ์ด ๋˜์ง€๋งŒ Build์—์„œ๋Š” Build๋•Œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์ ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ ์‹ค์ œ ๋ฐฐํฌ๋•Œ envํŒŒ์ผ์ด ์ ์šฉ์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์•„๋ž˜ ๊ธ€์€ Dockerfile์—์„œ Build์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. VITE๋ฅผ ์ด์šฉํ•ด์„œ ๋นŒ๋“œ๋ฅผ ํ• ๋ ค๊ณ  ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ์•„๋ž˜ 2๊ฐœ์ด๋‹ค. VITE_API_URL VITE_FILE_UPLOAD_API_URL ๋จผ์ € Dockerfile์— ํ•ด๋‹น ENVํŒŒ์ผ์ด ์ €์žฅ๋ ์ˆ˜ ์žˆ๋„๋ก build์ „ ๋‹จ๊ณ„์—์„œ ์ž‘์„ฑ. ์‚ฌ์ง„1) Dockerfile - ARG, ENV์…‹ํŒ… GitHub์˜ Secreat๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ARG์…‹ํŒ…์ด ํ•„์š”ํ•˜๋‹ค. Git Action์˜ ymlํŒŒ์ผ์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ’์„ Docker์— ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•ด๋‹น ์…‹ํŒ…์„ Dockerfile์— ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ARG๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ฉด build์‹œ Dockerfile๋‚ด๋ถ€์— ์ ‘๊ทผํ• ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ดํ›„ ENV๋กœ ํ•ด๋‹น ๊ฐ’์„ ์ง€์ • ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ "$VITE_API_URL", "$VITE_FILE_UPLOAD_API_URL" ๋ถ€๋ถ„์€ GitHub์—์„œ ๊ฐ–๊ณ ์˜ต๋‹ˆ๋‹ค. ์‚ฌ์ง„2) .ymlํŒŒ์ผ์˜ build๋ถ€๋ถ„ ์ˆ˜์ • ์‚ฌ์ง„2์˜ 84 ~ 86๋ฒˆ์งธ ์ค„์ด build๊ณผ์ •์ค‘์— ENVํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.  ์‚ฌ์ง„3) Repository secrets ์„ค์ • ์˜ต์…˜ ์‚ฌ์ง„4) Repository secrets ์„ค์ • ์˜ต์…˜์„ ์ง€์ • ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฌ์ง„3, 4์™€ ๊ฐ™์ด build์‹œ ์ €์žฅํ•  Repository secrets๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์œ„ ์„ค์ •์ด ๋‹ค ๋œํ›„์— CI/CD๊ฐ€ ์ง„ํ–‰๋˜๋Š” branch์— ํ‘ธ์‹œํ• ์‹œ build๊ณผ์ •์—์„œ Repository secrets๋ฅผ ์ด์šฉํ•ด์„œ build๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

Linux(Ubuntu)์— ์•„ํŒŒ์น˜(Apache2)์™€ SSL์ธ์ฆ์„œ(letsencrypt)๋ฅผ ์ ์šฉํ•ด์„œ ๋„๋ฉ”์ธ๋ณ„๋กœ ์‘๋‹ตํ•˜๊ธฐ - ๊ฐœ๋…

์ด๋ฏธ์ง€
 "Apache"์™€ "Let's Encrypt"์™€ PC๋ฅผ ์ด์šฉํ•ด์„œ HTTPS์›น์‚ฌ์ดํŠธ๋ฅผ ์˜ฌ๋ฆด์ˆ˜ ์žˆ๋‹ค. 1. ์œ ์ €๊ฐ€ URL์„ ์ด์šฉํ•ด์„œ ์„œ๋ฒ„(React)์— ์ ‘์†์„ ํ•œ๋‹ค. 2. Route53์— ๋Œ€์‘๋˜๋Š” IP๊ฐ’์„ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•œ๋‹ค. 3. ํ•ด๋‹น ์„œ๋ฒ„์˜ IP๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ ‘์†ํ•œ๋‹ค. 4. ์•„ํŒŒ์น˜ ์„œ๋ฒ„์—์„œ ํ•ด๋‹น URL์„ ํ™•์ธํ•œ๋‹ค. 5. "Let's Encrypt"์— ๋ฐœ๊ธ‰๋ฐ›์€ SSLํŒŒ์ผ์„ ํ™•์ธํ•œ๋‹ค. 6. ์•„ํŒŒ์น˜์—์„œ "Let's Encrypt"์— ๋ฐœ๊ธ‰๋ฐ›์€ SSL์„ ์ ์šฉํ•œ๋‹ค. - ์ •ํ•ด์ง„ ๋„๋ฉ”์ผ์„ ์ด์šฉํ•ด์„œ HTTPS์ ‘์† 7. React์— ์ ‘์† ์œ„ ๊ฐœ๋…๋„์—์„œ "Let's Encrypt"๊ฐ€ ์ž๋™์œผ๋กœ SSL์ธ์ฆ์„œ๋ฅผ ๊ฐฑ์‹ ํ•ด ์ค€๋‹ค. ๋”ฐ๋ผ์„œ ์ˆ˜๋™์œผ๋กœ ๊ธฐ๊ฐ„์ด ๋‹คํ•œ ์ธ์ฆ์„œ๋ฅผ ๊ต์ฒดํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.  ๋‹ค์Œ ๊ธ€์—์„œ๋Š” ์‹ค์ œ ์ž‘์—… ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ํ„ฐ๋ฏธ๋„ ํ™”๋ฉด๊ณผ ํ•จ๊ป˜ ์ž‘์„ฑํ•˜๊ฒ ๋‹ค.

React-Query๋ž€?

React Query๋ž€ ๋ฌด์—‡์ธ๊ฐ€? React Query ๋Š” ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์บ์‹ฑํ•˜๊ณ , ๊ฐฑ์‹ ํ•˜๊ณ , ๋™๊ธฐํ™”ํ•˜๋Š” ๊ณผ์ •์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋น„๋™๊ธฐ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์  React์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ fetchํ•  ๋•Œ ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒจํ„ด์„ ๋ฐ˜๋ณตํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค: const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch('/api/data') .then((res) => res.json()) .then(setData) .catch(setError) .finally(() => setLoading(false)); }, []); → ์ค‘๋ณต๋˜๊ณ  ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ๋งŽ์•„์ง€๋Š” ๋ฌธ์ œ๋ฅผ React Query๊ฐ€ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. React Query์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์ž๋™ ์บ์‹ฑ: ๋™์ผ ์š”์ฒญ์„ ๋น ๋ฅด๊ฒŒ ์‘๋‹ต ๋กœ๋”ฉ/์—๋Ÿฌ ์ƒํƒœ ์ž๋™ ์ œ๊ณต: isLoading, isError ๋“ฑ ์ œ๊ณต ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฆฌํŽ˜์น˜: ํฌ์ปค์Šค ์‹œ ์ตœ์‹  ๋ฐ์ดํ„ฐ ์žฌ์š”์ฒญ ์ž๋™ ๋ฆฌํŠธ๋ผ์ด: ์‹คํŒจ ์‹œ ์ž๋™ ์žฌ์‹œ๋„ Query ๋ฌดํšจํ™”: mutate ํ›„ ๊ด€๋ จ ์ฟผ๋ฆฌ ๋ฆฌํŽ˜์น˜ Devtools: ์ฟผ๋ฆฌ ์ƒํƒœ ์‹œ๊ฐํ™” ๊ธฐ๋ณธ ์‚ฌ์šฉ ์˜ˆ์‹œ useQuery ์˜ˆ์‹œ import { useQuery } from '@tanstack/react-query'; const fetchUsers = async () => { const res = await fetch('/api/users'); return res.json(); } export d...

์„œ๋ฒ„ ์ƒํƒœ(Server State)์™€ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ(Client State)์˜ ์ฐจ์ด

React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ ์ƒํƒœ(state)๋Š” ํ•ต์‹ฌ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ์ด ์ƒํƒœ๋Š” ํฌ๊ฒŒ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ์™€ ์„œ๋ฒ„ ์ƒํƒœ ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ๊ฐ์˜ ์ƒํƒœ๋Š” ์„ฑ๊ฒฉ๊ณผ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ๋ถ„ํ•ด์„œ ์ดํ•ดํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ (Client State) ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๋Š” ๋ธŒ๋ผ์šฐ์ € ๋ฉ”๋ชจ๋ฆฌ ๋˜๋Š” React ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ๋กœ, ์„œ๋ฒ„์™€์˜ ์ง์ ‘์ ์ธ ์—ฐ๋™์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค(UI)์™€ ๊ด€๋ จ๋œ ์ •๋ณด๋“ค์ด ์ฃผ๋กœ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ ๋ชจ๋‹ฌ์˜ ์—ด๋ฆผ/๋‹ซํž˜ ์ƒํƒœ ํผ ์ž…๋ ฅ๊ฐ’ (์˜ˆ: ์ด๋ฆ„, ์ด๋ฉ”์ผ ๋“ฑ) ๋‹คํฌ๋ชจ๋“œ/๋ผ์ดํŠธ๋ชจ๋“œ ํ† ๊ธ€ ํ˜„์žฌ ํƒญ์ด๋‚˜ ํ•„ํ„ฐ ์„ ํƒ ์ƒํƒœ ํŠน์ง• React์˜ useState , useReducer , Context API ๋˜๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Zustand, Recoil ๋“ฑ)๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ๋น ๋ฅด๊ฒŒ ๋ณ€ํ•˜๊ณ  UI์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ƒํƒœ (Server State) ์„œ๋ฒ„ ์ƒํƒœ ๋Š” ์™ธ๋ถ€ ์‹œ์Šคํ…œ(API, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ)์— ์กด์žฌํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋น„๋™๊ธฐ ์š”์ฒญ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์†Œ์œ ๊ถŒ์ด ์™ธ๋ถ€์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋™๊ธฐํ™” ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ ์‚ฌ์šฉ์ž ๋ชฉ๋ก (GET /users) ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก (GET /posts) ์„œ๋ฒ„์˜ ๊ณต์ง€์‚ฌํ•ญ ์ •๋ณด ์ฃผ๋ฌธ ๋‚ด์—ญ, ๊ฒฐ์ œ ์ƒํƒœ ํŠน์ง• ํ•ญ์ƒ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฉฐ, ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ๋„์ค‘ ๋กœ๋”ฉ ์ƒํƒœ์™€ ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. React Query, SWR, Apoll...

Vite์„ ์ด์šฉํ•ด์„œ React ํ”„๋กœ์ ํŠธ ์ƒ์„ฑํ•˜๊ธฐ

์ด๋ฏธ์ง€
 "npx create-react-app ..."์˜ CRA์˜ ๊ฐœ๋ฐœ์ด ์ค‘๋‹จ๋จ์—๋”ฐ๋ผ ๋‹ค๋ฅธ ๋Œ€์•ˆ์œผ๋กœ Reactํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ์ค‘์— Vite๊ฐ€ ์žˆ๋Š”๋ฐ CRA์ฒ˜๋Ÿผ ์‰ฌ๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ์„ฑํ• ์ˆ˜ ์žˆ๋‹ค. 1) ์‚ฌ์ „ ์ค€๋น„ - 2025๋…„ ๊ธฐ์ค€ Node.js 20+ ๊ถŒ์žฅ (LTS). ๋ฒ„์ „ ํ™•์ธ: $ node -v copy 2) ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ(์ด๋ฆ„: my-app ) ๋ฒ„์ „์€ ๊ธฐ๋ณธ ์ตœ์‹ (latest)์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•„์š”์‹œ ์ด์ „ ๋ฒ„์ „์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. (๊ณต์‹์‚ฌ์ดํŠธ์˜ Version์ฐธ๊ณ  ) ๋Œ€ํ™”ํ˜•(ํ…œํ”Œ๋ฆฟ ์„ ํƒ ํ”„๋กฌํ”„ํŠธ ํ‘œ์‹œ): $ npm create vite@latest my-app copy 1) Window์˜ Git Bash๋กœ ์ƒ์„ฑ ๋น„๋Œ€ํ™”ํ˜•(๋ฐ”๋กœ React + TS ํ…œํ”Œ๋ฆฟ): $ npm create vite@latest my-app -- --template react-ts copy pnpm / yarn ์‚ฌ์šฉ ์‹œ: $ pnpm create vite my-app --template react-ts copy $ yarn create vite my-app --template react-ts copy 3) ์˜์กด์„ฑ ์„ค์น˜ & ์‹คํ–‰ $ cd my-app copy $ npm install copy $ npm run dev copy ๊ธฐ๋ณธ ๊ฐœ๋ฐœ ์„œ๋ฒ„๋Š” http://localhost:5173 ์—์„œ ์‹คํ–‰๋œ๋‹ค. 4) ์ƒ์„ฑ ๊ตฌ์กฐ(์š”์•ฝ) index.html : ์ง„์ž… HTML src/main.tsx : React ์—”ํŠธ๋ฆฌ src/App.tsx : ์ƒ˜ํ”Œ ์ปดํฌ๋„ŒํŠธ tsconfig.json : TypeScript ์„ค์ • vite.config.ts : Vite ์„ค์ • 5) TypeScript ์—„๊ฒฉ ๋ชจ๋“œ(์„ ํƒ) tsconfig.json ์—์„œ "strict": true ๊ถŒ์žฅ. 6) ๊ฒฝ๋กœ ๋ณ„์นญ ์„ค์ •(์„ ํƒ) vite.config.ts ์˜ˆ์‹œ: import { defineCo...