PES
KO English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

알림을 켜는 방법

이 브라우저 또는 주소에서는 알림을 사용할 수 없습니다. 지원되는 브라우저로 보안 연결된 PES 사이트에 접속해 주세요.

알림이 차단되어 있으면 브라우저 설정에서 허용해 주세요.

  1. 주소 표시줄 옆의 사이트 설정 또는 브라우저의 사이트 설정을 열고, 이 사이트의 알림을 허용으로 바꾸세요.
  2. 기기 설정에서 브라우저 알림을 허용하고 방해 금지 또는 집중 모드를 확인하세요.
  3. PES로 돌아와 페이지를 새로고침한 뒤 벨을 눌러 알림을 켜세요.

iPhone 또는 iPad에서는 PES를 홈 화면에 추가하고 거기에서 연 뒤 알림을 허용하세요.

나의 학습 진도
  1. 인공지능 사용법
  2. 터미널 명령어
  3. 인공지능 심화
  4. 바이브코딩
  5. 인공지능 자격증 준비 중
  6. 키보드
바이브코딩 전체 보기
바이브코딩

웹서버

브라우저가 말을 걸어 주는 쉘 스크립트 20줄.

웹서버는 요청을 기다렸다가 응답을 보내는 프로그램일 뿐입니다. 그것을 증명하기 위해 bash 와 netcat, 이름 있는 파이프만으로 서버를 만듭니다 — 한 줄도 빠짐없이 읽을 수 있습니다. 그다음 실제 사이트를 HTTPS 까지 붙여 돌리는 Caddy 로 넘어갑니다.

Docker: 상자에 담은 Caddy 로 진짜 사이트를 인터넷에

는 프로그램과 그 프로그램이 도는 데 필요한 모든 것 — 라이브러리, 설정, 작은 운영체제까지 — 를 하나에 담고, 그 이미지를 로 실행합니다. 컨테이너는 내 노트북에서도 빌린 서버에서도 똑같이 움직이므로 "제 컴퓨터에서는 되는데요"라는 오래된 핑계가 사라집니다.

Caddy 는 이미 파일 하나인데 굳이 왜 도커를 쓸까요? 진짜 에서는 곧 여러 가지가 함께 돌기 때문입니다 — 사이트, 앱, . 도커는 그 하나하나에 자기 상자를 주고, 같은 몇 가지 명령으로 켜고 끄고 새로 바꾸고 지웁니다. 서버에 다른 것을 설치하지 않고 이웃도 건드리지 않습니다.

먼저 알아 둘 낱말 네 개

  1. 이미지프로그램과 그것에 필요한 모든 것을 얼려 둔 꾸러미입니다. 내려받거나(caddy:2) Dockerfile 이라는 조리법 파일로 직접 만듭니다. 실행하는 동안 바뀌지 않습니다.
  2. 컨테이너실행 중인 이미지입니다. 이미지 하나로 컨테이너를 여러 개 띄울 수 있고, 컨테이너를 지워도 이미지는 그대로입니다 — 다음에 켜면 새것으로 시작합니다.
  3. 포트 연결컨테이너에는 바깥에서 보이지 않는 자기만의 포트가 있습니다. -p 8080:80 은 내 컴퓨터의 8080 포트를 컨테이너 안의 80 포트에 이어서 브라우저가 닿을 수 있게 합니다.
  4. 볼륨컨테이너가 자기 안에 쓴 파일은 컨테이너를 지우면 함께 사라집니다. 볼륨이나 컨테이너에 연결한 내 폴더는 남는 저장소입니다 — 페이지, 설정, Caddy 의 인증서가 거기에 삽니다.

도커 설치

Mac 이나 Windows PC 에서는 docker.com 에서 Docker Desktop 을 설치하고 한 번 실행해 둡니다. 그러면 터미널에서 docker 명령이 됩니다. 리눅스 서버에서는 도커의 공식 스크립트가 한 줄로 모두 설치합니다. 다음으로 넘어가기 전에 확인 명령 두 개가 모두 답해야 합니다.

install
# macOS · Windows: install Docker Desktop from docker.com and start it once

# Ubuntu / Debian server: Docker's official install script
curl -fsSL https://get.docker.com | sh

# check that both commands answer
docker --version
docker compose version

명령 한 줄로 Caddy 띄우기

index.html 이 있는 폴더로 가서 아래 한 줄을 실행합니다. 처음에는 도커가 Caddy 이미지를 내려받고, 그다음부터는 1초쯤이면 켜집니다. http://localhost:8080 을 열면 내 페이지가 보입니다.

terminal
# serve this folder at http://localhost:8080 (Control-C stops it)
docker run --rm -p 8080:80 -v "$PWD":/usr/share/caddy caddy:2
  1. docker run이미지로 컨테이너를 만들고 실행합니다.
  2. --rm멈추자마자 컨테이너를 지웁니다. 멈춘 컨테이너가 쌓이지 않게 하려는 것입니다. 이미지는 남으므로 다음 실행도 똑같이 빠릅니다.
  3. -p 8080:80내 컴퓨터의 8080 포트를 Caddy 가 기다리는 컨테이너 안의 80 포트에 잇습니다. 왼쪽 숫자는 마음대로 고르고, 오른쪽 숫자는 이미지가 정해 둔 값입니다.
  4. -v "$PWD":/usr/share/caddy지금 폴더($PWD)를 컨테이너 안의 /usr/share/caddy 로 보이게 합니다 — 공식 이미지가 기본으로 내놓는 폴더입니다. 여기서 파일을 고치면 다음 새로 고침에 바로 보입니다.
  5. caddy:2실행할 이미지 — 공식 Caddy 이미지의 2.x 버전입니다. :2 꼬리표를 빼면 도커는 latest 를 가져오는데, 어느 날 큰 버전이 바뀌어 발밑이 흔들릴 수 있습니다.

Control-C 로 멈춥니다. 잠깐 보기에는 그만이지만 명령이 길고, 터미널을 닫는 순간 잊힙니다. 오래 둘 것은 파일에 적어 둡니다 — 그것이 다음 프로젝트입니다.

프로젝트 1: HTML 홈페이지를 폴더에서 인터넷까지

프로젝트 전체가 작은 파일 세 개입니다. index.html 은 페이지, Caddyfile 은 Caddy 가 무엇을 내놓을지, compose.yaml 은 도커가 Caddy 를 어떻게 실행할지를 적습니다. Docker Compose 가 그 파일을 읽으므로 긴 docker run 명령을 다시 칠 일이 없습니다.

my-site
my-site/
├── compose.yaml
├── conf/
│   └── Caddyfile
└── site/
    └── index.html
compose.yaml
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./conf:/etc/caddy
      - ./site:/srv
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:

compose.yaml 한 줄씩

  1. image: caddy:2실행할 이미지 — 앞에서와 같은 공식 Caddy 이미지입니다.
  2. restart: unless-stopped컨테이너가 죽거나 서버가 다시 켜지면, 일부러 멈추기 전까지 도커가 알아서 다시 띄웁니다.
  3. "80:80" · "443:443"기계의 80(http) · 443(https) 포트를 Caddy 에 엽니다. 인증서를 받고 http 손님을 https 로 넘기려면 둘 다 필요합니다.
  4. "443:443/udp"같은 443 포트를 UDP 로 한 번 더 엽니다. 브라우저가 가장 새로운 HTTP/3 를 쓸 수 있게 합니다. 빼도 해롭지 않고, 그러면 사이트는 HTTP/2 로 돕니다.
  5. ./conf:/etc/caddy내 conf 폴더가 Caddy 가 Caddyfile 을 찾는 /etc/caddy 가 됩니다. Caddy 문서가 파일 하나 대신 폴더를 연결하는 까닭은, 많은 편집기가 저장할 때 파일을 새것으로 갈아 끼워서 파일 하나만 연결해 두면 옛 내용이 계속 보이기 때문입니다.
  6. ./site:/srv내 site 폴더가 Caddyfile 이 내놓는 /srv 가 됩니다. 디스크에서 페이지를 고치면 다시 켜지 않아도 Caddy 가 바로 새 판을 내놓습니다.
  7. caddy_data:/data도커가 맡아 두는 이름 있는 볼륨입니다. Caddy 가 HTTPS 인증서와 키를 여기에 두므로 컨테이너를 지우고 다시 만들어도 살아남습니다. 옆의 caddy_config 도 Caddy 의 자동 설정을 같은 방식으로 지킵니다.

먼저 내 컴퓨터에서

Caddyfile 의 주소 자리에 :80 을 씁니다. "어떤 이름으로 물어 오든 80 포트에서 답하라"는 뜻으로, 인증서 없는 맨 http 입니다. 도메인이 없는 내 컴퓨터에는 이것이 딱 맞습니다. 그다음 켜고 http://localhost 를 엽니다.

conf/Caddyfile
:80 {
	root * /srv
	file_server
}
terminal
cd my-site
docker compose up -d      # start Caddy in the background
open http://localhost     # or type the address into a browser
docker compose logs -f    # watch requests arrive (Control-C stops watching)

인터넷에 올리기

  1. 서버 빌리기공인 IP 주소가 있는 VPS 면 무엇이든 됩니다 — 작고 싼 것으로 충분합니다. 위의 스크립트로 도커를 설치하고, 방화벽이 80 · 443 포트를 들여보내는지 확인합니다.
  2. 도메인이 서버를 가리키게을 산 곳에서 에 A 레코드를 더합니다 — 이름은 example.com, 값은 서버의 IP 주소입니다. 인터넷 전체가 바뀐 값을 보기까지 몇 분에서 몇 시간이 걸릴 수 있습니다.
  3. 진짜 주소 적기Caddyfile 의 :80 을 내 도메인으로 바꿉니다. 이 한 곳을 바꾸는 것이 자동 HTTPS 를 켭니다 — Caddy 가 인증서를 요청하고, 설치하고, 갱신하고, http 손님을 https 로 넘깁니다.
  4. 복사하고 켜기rsync 로 폴더를 서버에 복사하고, ssh 로 들어가 docker compose up -d 로 켭니다. 기록을 지켜보다가 인증서를 받았다는 줄이 나오면 사이트가 열린 것입니다.
conf/Caddyfile
example.com {
	root * /srv
	file_server
	encode gzip zstd
}

아래의 203.0.113.10 은 예시용으로 비워 둔 주소이니 내 서버의 IP 로 바꿉니다. 나중에 페이지를 고칠 때는 index.html 을 고치고 같은 rsync 를 다시 실행합니다. site 폴더가 컨테이너에 연결되어 있어서 아무것도 다시 켜지 않아도 다음 새로 고침에 새 페이지가 나옵니다.

terminal
# on your computer: copy the project folder to the server
rsync -av my-site/ root@203.0.113.10:~/my-site/

# on the server: start it — Caddy fetches the HTTPS certificate by itself
ssh root@203.0.113.10
cd ~/my-site
docker compose up -d
docker compose logs -f caddy

프로젝트 2: React 홈페이지

는 작게 나눠 다시 쓰는 부품(컴포넌트)으로 페이지를 만드는 라이브러리입니다. 배포에서 중요한 것은 하나입니다 — React 프로젝트는 그대로 내놓지 않습니다. 빌드 단계가 그것을 dist 폴더 안의 평범한 HTML · CSS · JavaScript 파일로 바꾸고, 거기서부터는 프로젝트 1 과 같은 일입니다.

아래 명령에는 내 컴퓨터에 Node.js 가 있어야 합니다. Vite 가 바로 돌아가는 React 프로젝트를 만들고, npm run dev 가 작업하는 동안 화면을 보여 주고, npm run build 가 완성된 사이트를 씁니다.

terminal
# needs Node.js (nodejs.org) — create a React project with Vite
npm create vite@latest my-react -- --template react
cd my-react
npm install
npm run dev      # development server at http://localhost:5173

npm run build    # the finished site is written to dist/

방법 A: 내 컴퓨터에서 빌드하고 결과만 복사

가장 쉬운 길은 프로젝트 1 을 그대로 다시 쓰는 것입니다. 빌드한 뒤 dist 폴더만 서버의 site 폴더로 복사합니다. --delete 는 이번 빌드에 없는 지난 빌드의 파일을 지워서 찌꺼기가 쌓이지 않게 합니다.

terminal
# way A: build here, copy only the result into Project 1's site folder
npm run build
rsync -av --delete dist/ root@203.0.113.10:~/my-site/site/
React 가 Caddyfile 에 꼭 필요로 하는 한 줄

React 앱은 index.html 하나에서 모든 페이지를 스스로 그립니다. /about 같은 주소는 디스크의 파일이 아니라서, 도움 없이는 누군가 그 페이지를 새로 고치거나 공유된 링크로 들어오는 순간 Caddy 가 404 로 답합니다. try_files 는 Caddy 에게 "파일이 있으면 그것을, 없으면 index.html 을 주고 React 가 알맞은 페이지를 그리게 하라"고 말합니다.

Caddyfile
example.com {
	root * /srv
	encode gzip zstd
	try_files {path} /index.html
	file_server
}

방법 B: 두 단계 Dockerfile 로 도커가 빌드하게

더 튼튼한 길은 도커 안에서 빌드하는 것입니다. 그러면 서버든 동료의 컴퓨터든 늘 똑같이 빌드되고, 서버에 Node 를 설치할 사람도 없습니다. Dockerfile 은 두 단계입니다 — 첫 단계는 Node 로 빌드하고, 둘째 단계는 결과만 챙깁니다.

Dockerfile
# stage 1: build the React app with Node
FROM node:24-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# stage 2: only the finished files go into the Caddy image
FROM caddy:2
COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=build /app/dist /srv

Dockerfile 한 줄씩

  1. FROM node:24-alpine AS build첫 단계는 Node.js 가 든 이미지에서 시작하고, 다음 단계가 여기서 파일을 가져갈 수 있게 이 단계에 build 라는 이름을 붙입니다.
  2. COPY package*.json ./ · RUN npm ci패키지 목록만 먼저 복사하고 잠금 파일에 적힌 버전 그대로 설치합니다. 목록이 그대로인 동안 도커가 이 단계를 다시 쓰므로, 다음 빌드부터는 느린 설치를 건너뜁니다.
  3. COPY . . · RUN npm run build나머지 소스를 복사하고 빌드합니다. 완성된 사이트가 build 단계 안의 /app/dist 에 생깁니다.
  4. FROM caddy:2둘째 단계는 깨끗한 Caddy 이미지에서 다시 시작합니다. 복사하지 않은 것은 첫 단계에서 하나도 따라오지 않습니다.
  5. COPY --from=build /app/dist /srvbuild 단계에서 빌드된 파일만 가져와 Caddyfile 이 내놓는 자리에 둡니다. Node 와 node_modules 는 남겨 두므로 최종 이미지가 작습니다.

try_files 를 넣은 Caddyfile 을 Dockerfile 옆에 두고 아래 compose.yaml 을 씁니다. build: . 은 이미지를 내려받는 대신 "이 폴더의 Dockerfile 로 만들라"는 뜻입니다. 서버에서 코드를 clone 하면 명령 하나로 빌드하고 켜고, 고칠 때마다 pull 한 뒤 같은 명령을 다시 실행합니다.

compose.yaml
services:
  web:
    build: .
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:
terminal
# keep node_modules and old builds out of the image
printf 'node_modules\ndist\n' > .dockerignore

# on the server: get the code, then build and start in one step
git clone https://github.com/you/my-react.git
cd my-react
docker compose up -d --build

# after you push a change: pull it and rebuild
git pull && docker compose up -d --build

자주 쓰는 명령

명령하는 일
docker compose up -dcompose.yaml 에 적힌 것을 모두 뒤에서 켭니다. compose.yaml 을 고친 뒤 다시 실행하면 바뀐 것만 새로 만듭니다.
docker compose ps이 프로젝트의 컨테이너와 도는지 여부를 보여 줍니다. 사이트가 답하지 않을 때 가장 먼저 봅니다.
docker compose logs -f기록을 실시간으로 따라갑니다. 인증서 문제, 틀린 경로, 죽는 일이 모두 여기에 먼저 나옵니다. Control-C 는 서버가 아니라 지켜보기만 멈춥니다.
docker compose exec -w /etc/caddy caddy caddy reload도는 컨테이너 안에서 Caddy 가 연결 하나 끊지 않고 Caddyfile 을 다시 읽게 합니다. Caddyfile 을 고친 뒤에 씁니다.
docker compose down컨테이너를 멈추고 지웁니다. 이름 있는 볼륨은 남으므로 인증서도 살아남습니다. -v 를 붙이면 그것까지 지우니 피합니다.
docker compose pull더 새 Caddy 이미지를 내려받습니다. 이어서 docker compose up -d 를 실행해야 새것으로 바뀝니다.
caddy_data 는 절대 버리지 않는다

인증서는 caddy_data 볼륨에 삽니다. docker compose down -v 로, 또는 compose.yaml 에서 볼륨을 빼먹어서 그것이 지워지면 Caddy 는 켤 때마다 인증서를 새로 요청해야 합니다. 인증 기관은 한 도메인이 한 주에 받을 수 있는 인증서 수를 제한하므로, 몇 번의 부주의한 재시작으로 사이트가 며칠 동안 HTTPS 없이 지낼 수 있습니다.

웹 클라이언트

스스로 표시하는 칸이에요. 여기서 채점하지는 않아요.

이 단계를 이해한 것으로 표시할까요?

아직 취소할 수 없으니, 정말 이해했을 때만 표시해 주세요.

이해한 것으로 표시했어요

스스로 표시하는 칸이에요. 여기서 채점하지는 않아요.

가이드라인

인공지능

인공지능 자격증

공부

바이브코딩

게임 개발

연습

튜터

채팅

게시판

만들기

소통

더보기

용어 사전

모르는 말을 골라 보세요. 쉬운 설명과 관련 용어를 볼 수 있어요.

찾는 용어가 아직 없어요.

용어를 고르면 설명이 보여요.