본문으로 건너뛰기
← 가이드 목록

내가 만든 웹 앱 서버에 올리기 (Node.js·Python)

내 PC에서 만든 Express·Next.js(Node.js)나 Flask·FastAPI(Python) 앱을 서버에서 24시간 돌리고, 도메인으로 접속할 수 있게 하는 전체 흐름입니다. Ubuntu 기준입니다.

전체 흐름

  1. 코드를 서버로 가져오기 (GitHub)
  2. 비밀값을 .env에 넣기
  3. 앱을 상시 실행하기 (Node.js는 pm2, Python은 systemd)
  4. Nginx로 도메인 연결하고 HTTPS 적용하기

1. 코드 가져오기

GitHub 저장소가 공개라면 바로 받습니다.

git clone https://github.com/내아이디/내앱.git
cd 내앱

비공개 저장소라면 (배포 키)

서버 전용 키를 만들어 저장소에 "읽기 전용"으로 등록하면, 내 GitHub 비밀번호를 서버에 두지 않아도 됩니다.

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N ""
cat ~/.ssh/deploy_key.pub

출력된 한 줄을 복사해 GitHub 저장소 → Settings → Deploy keys → Add deploy key에 붙여 넣습니다. ("Allow write access"는 체크하지 않습니다) 그다음 서버가 이 키를 쓰도록 설정하고 받습니다.

printf 'Host github.com\n  IdentityFile ~/.ssh/deploy_key\n' >> ~/.ssh/config
git clone [email protected]:내아이디/내앱.git

2. 비밀값은 .env에

DB 비밀번호, API 키 같은 값은 코드에 직접 쓰지 말고 서버의 .env 파일에 넣습니다.

nano .env

🔒 .env는 .gitignore에 넣어 GitHub에 올라가지 않게 하세요.

3-1. Node.js 앱 (pm2)

Node.js 설치는 디스코드 봇 24시간 호스팅하기 (discord.js·discord.py)의 "Node.js 설치"와 같습니다.

npm ci                                   # package-lock.json 기준으로 설치
npm run build                            # 빌드 단계가 있는 앱만 (Next.js 등)
sudo npm install -g pm2
pm2 start npm --name my-app -- start     # package.json의 start 스크립트로 실행
pm2 save
pm2 startup                              # 출력된 명령어를 한 번 더 복사해서 실행

3-2. Python 앱 (systemd)

sudo apt install -y python3-venv
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
./venv/bin/pip install uvicorn       # FastAPI라면
./venv/bin/pip install gunicorn      # Flask라면

서비스 파일을 만듭니다.

sudo nano /etc/systemd/system/my-app.service

경로의 계정명, 내앱은 실제 값으로 바꾸고, ExecStart는 둘 중 내 앱에 맞는 줄 하나만 남깁니다. (main:app은 main.py 안의 app, app:app은 app.py 안의 app이라는 뜻입니다)

[Unit]
Description=My Web App
After=network-online.target

[Service]
User=계정명
WorkingDirectory=/home/계정명/내앱
EnvironmentFile=/home/계정명/내앱/.env
# FastAPI
ExecStart=/home/계정명/내앱/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
# Flask
# ExecStart=/home/계정명/내앱/venv/bin/gunicorn -w 2 -b 127.0.0.1:8000 app:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now my-app
sudo systemctl status my-app      # active (running)이면 성공

4. 도메인 연결과 HTTPS

웹사이트 띄우기를 따라 Nginx와 도메인, 인증서를 설정하고, "Node.js·Python 앱을 연결하고 싶다면" 부분의 proxy_pass 포트를 내 앱 포트(Node.js는 보통 3000, 위 Python 예시는 8000)로 맞춥니다.

앱 포트(3000, 8000)는 방화벽에서 열 필요가 없습니다. 외부에는 Nginx의 80·443만 열고, 앱은 Nginx를 통해서만 접속되게 하는 것이 안전합니다.

5. 코드를 고친 뒤 업데이트하기

cd ~/내앱
git pull

# Node.js
npm ci && npm run build && pm2 restart my-app

# Python
./venv/bin/pip install -r requirements.txt && sudo systemctl restart my-app

잘 안 될 때

  • 로그부터 확인하세요 — pm2 logs my-app 또는 journalctl -u my-app -f
  • 502 Bad Gateway — 앱이 꺼져 있거나, Nginx의 proxy_pass 포트와 앱 포트가 다릅니다.
  • EADDRINUSE / Address already in use — 그 포트를 이미 다른 프로그램이 쓰고 있습니다. sudo ss -ltnp | grep 3000으로 무엇이 쓰는지 확인하세요.
  • 메모리 부족으로 빌드가 멈춰요 — npm run build 중에 서버가 멈춘다면 스왑을 추가해보세요.

해결되지 않는 문제가 있다면 고객센터로 문의해주세요.