원샷: nginx + Node API + HTTPS (systemd)
복사-붙여넣기 한 번으로 Node(systemd) + nginx(/api 프록시) + Let’s Encrypt HTTPS까지 구성
처음부터 흐름대로 이해하고 싶다면: nginx로 Node 서버 배포하기 (systemd + HTTPS)
원샷 스크립트
아래 스크립트는 “샘플 Node 서버 생성 → systemd 등록 → nginx 설정 → certbot 발급/리다이렉트 → 갱신 테스트”까지 한 번에 진행합니다.
export DOMAIN="example.com"
export EMAIL="you@example.com"
export APP_NAME="myapp"
export APP_PORT="3000"
sudo bash -euo pipefail <<BASH
set -euo pipefail
: "\${DOMAIN:?DOMAIN is required}"
: "\${EMAIL:?EMAIL is required}"
: "\${APP_NAME:?APP_NAME is required}"
: "\${APP_PORT:?APP_PORT is required}"
apt-get update -y
apt-get install -y nginx certbot python3-certbot-nginx nodejs
id -u "\${APP_NAME}" >/dev/null 2>&1 || useradd --system --create-home --shell /usr/sbin/nologin "\${APP_NAME}"
mkdir -p "/srv/\${APP_NAME}/current"
chown -R "\${APP_NAME}:\${APP_NAME}" "/srv/\${APP_NAME}"
cat >"/srv/\${APP_NAME}/current/server.js" <<'JS'
const http = require("http");
const port = Number(process.env.PORT || 3000);
const server = http.createServer((req, res) => {
if (req.url === "/health") {
res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
res.end("ok");
return;
}
if (req.url === "/hello") {
res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
res.end(JSON.stringify({ ok: true, message: "hello" }));
return;
}
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
res.end("not found");
});
server.listen(port, "127.0.0.1", () => {
console.log(\`listening on http://127.0.0.1:\${port}\`);
});
JS
chown "\${APP_NAME}:\${APP_NAME}" "/srv/\${APP_NAME}/current/server.js"
mkdir -p "/etc/\${APP_NAME}"
cat >"/etc/\${APP_NAME}/\${APP_NAME}.env" <<ENV
NODE_ENV=production
PORT=\${APP_PORT}
ENV
chmod 600 "/etc/\${APP_NAME}/\${APP_NAME}.env"
cat >"/etc/systemd/system/\${APP_NAME}.service" <<UNIT
[Unit]
Description=\${APP_NAME}
After=network.target
[Service]
Type=simple
User=\${APP_NAME}
WorkingDirectory=/srv/\${APP_NAME}/current
EnvironmentFile=/etc/\${APP_NAME}/\${APP_NAME}.env
ExecStart=/usr/bin/node /srv/\${APP_NAME}/current/server.js
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now "\${APP_NAME}.service"
mkdir -p "/var/www/\${DOMAIN}/html"
mkdir -p /var/www/letsencrypt
echo "It works" >"/var/www/\${DOMAIN}/html/index.html"
cat >"/etc/nginx/sites-available/\${DOMAIN}" <<NGINX
server {
listen 80;
listen [::]:80;
server_name \${DOMAIN};
root /var/www/\${DOMAIN}/html;
index index.html;
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location ~ /\\.(?!well-known) {
return 404;
}
location / {
try_files \\$uri \\$uri/ =404;
}
location /api/ {
proxy_http_version 1.1;
proxy_set_header Host \\$host;
proxy_set_header X-Real-IP \\$remote_addr;
proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \\$scheme;
proxy_pass http://127.0.0.1:\${APP_PORT}/;
}
}
NGINX
ln -sf "/etc/nginx/sites-available/\${DOMAIN}" "/etc/nginx/sites-enabled/\${DOMAIN}"
rm -f /etc/nginx/sites-enabled/default || true
nginx -t
systemctl reload nginx
certbot --nginx -d "\${DOMAIN}" --non-interactive --agree-tos -m "\${EMAIL}" --redirect
certbot renew --dry-run
BASH