Repository navigation
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
Β·293 lines (273 loc) Β· 14.4 KB
/
Copy pathsetup.sh
File metadata and controls
executable file
Β·293 lines (273 loc) Β· 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#!/usr/bin/env bash
# =============================================================================
# HoneyRest μλ² μ΅μ΄ μ€μΉ (Oracle Cloud Always Free Ampere A1, Ubuntu 26.04 Minimal aarch64 κΈ°μ€)
#
# μ¬μ μ€λΉ (SSH μ μ ν, μμΈν μμλ docs/DEPLOY.md)
# sudo apt-get update && sudo apt-get install -y git
# sudo mkdir -p /opt/honeyrest && sudo chown "$USER:$USER" /opt/honeyrest
# git clone https://github.com/Seongwonp/honeyRest_user.git /opt/honeyrest/honeyRest_user
# sudo /opt/honeyrest/honeyRest_user/deploy/setup.sh
#
# νλ μΌ (μ¬λ¬ λ² μ€νν΄λ μμ : μ΄λ―Έ λ λ¨κ³λ 건λλ΄λ€)
# 1) κΈ°λ³Έ ν¨ν€μ§(curl, git, openssl, cron λ±) μ€μΉ, μκ°λ Asia/Seoul
# 2) μ€μ νμΌ (κΈ°λ³Έ 4G) β 6GB RAM μμ Gradle/Node μ΄λ―Έμ§ λΉλ μ€ λ©λͺ¨λ¦¬ λΆμ‘± λ°©μ§
# 3) OS λ°©νλ²½μμ TCP 80/443 νμ© β Oracle Ubuntu μ΄λ―Έμ§μ iptables REJECT κ·μΉ / ufw λͺ¨λ μ²λ¦¬
# 4) Docker Engine + compose/buildx νλ¬κ·ΈμΈ (곡μ μ μ₯μ, arm64)
# 5) λλ¨Έμ§ λ μ μ₯μλ₯Ό /opt/honeyrest μ λλν ν΄λ‘ (--recurse-submodules)
# 6) deploy/.env μμ±: λΉλ°κ°μ openssl rand λ‘ μμ±, κ³΅μΈ IP λ‘ SITE_DOMAIN(sslip.io) μλ μ€μ
# 7) μ΄λ―Έμ§ λΉλ(μλΉμ€λ³ μμ°¨) β docker compose up -d β healthy λκΈ°
# 8) μ΄κΈ° λ°μ΄ν° μλ (seed.sh β κΈ°μ΄ λ°μ΄ν°λ ν λ²λ§ μ μ¬λ¨)
# 9) cron: 5λΆλ§λ€ ν¬μ€ 체ν¬, λ§€μΌ 04:30 λ°±μ
#
# νκ²½λ³μλ‘ λ°κΏ μ μλ κ°
# BASE_DIR=/opt/honeyrest SWAP_SIZE=4G(0 μ΄λ©΄ 건λλ) SITE_DOMAIN=(μλ) SKIP_SEED=1 SKIP_CRON=1 SKIP_FIREWALL=1
# HOST_REPO_URL / REACT_REPO_URL / HOST_BRANCH(main) / REACT_BRANCH(master)
# =============================================================================
set -Eeuo pipefail
# root λ‘ λ€μ μ€ν
if [[ "$(id -u)" -ne 0 ]]; then
exec sudo -E bash "$0" "$@"
fi
# shellcheck source=lib/common.sh
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/lib/common.sh"
SWAP_SIZE="${SWAP_SIZE:-4G}"
HOST_REPO_URL="${HOST_REPO_URL:-https://github.com/Seongwonp/honeyRest_host.git}"
REACT_REPO_URL="${REACT_REPO_URL:-https://github.com/Seongwonp/honeyrest_user_react.git}"
HOST_BRANCH="${HOST_BRANCH:-main}"
REACT_BRANCH="${REACT_BRANCH:-master}"
# μ μ₯μΒ·.env μμ μ: sudo λ₯Ό μ€νν SSH μ¬μ©μ (μμΌλ©΄ μ¬μ©μ μ μ₯μμ μμ μ)
TARGET_USER="${SUDO_USER:-}"
if [[ -z "$TARGET_USER" || "$TARGET_USER" == "root" ]]; then
TARGET_USER="$(stat -c %U "$USER_REPO")"
fi
[[ "$(uname -m)" == "aarch64" || "$(uname -m)" == "x86_64" ]] || warn "κ²μ¦λμ§ μμ μν€ν
μ²: $(uname -m)"
# shellcheck disable=SC1091
. /etc/os-release
[[ "${ID:-}" == "ubuntu" ]] || warn "Ubuntu κ° μλλλ€ (${PRETTY_NAME:-unknown}). Docker μ€μΉ λ¨κ³κ° μ€ν¨ν μ μμ΅λλ€."
export DEBIAN_FRONTEND=noninteractive
# ---- 1) κΈ°λ³Έ ν¨ν€μ§ ---------------------------------------------------------------
log "1) κΈ°λ³Έ ν¨ν€μ§ μ€μΉ"
apt-get update -y -q
apt-get install -y -q ca-certificates curl gnupg git openssl cron tar gzip iptables
systemctl enable --now cron >/dev/null 2>&1 || true
if command -v timedatectl >/dev/null 2>&1; then
timedatectl set-timezone Asia/Seoul 2>/dev/null || warn "μκ°λ μ€μ μ€ν¨ (UTC μ μ§)"
fi
# ---- 2) μ€μ ------------------------------------------------------------------
log "2) μ€μ νμΌ (${SWAP_SIZE})"
if [[ "$SWAP_SIZE" == "0" ]]; then
warn "μ€μ λ¨κ³ 건λλ (SWAP_SIZE=0)"
elif swapon --show --noheadings | grep -q .; then
ok "μ€μμ΄ μ΄λ―Έ μμ΅λλ€: $(swapon --show --noheadings | awk '{print $1" "$3}' | tr '\n' ' ')"
else
if [[ ! -f /swapfile ]]; then
fallocate -l "$SWAP_SIZE" /swapfile 2>/dev/null || dd if=/dev/zero of=/swapfile bs=1M count="$(( $(numfmt --from=iec "$SWAP_SIZE") / 1048576 ))" status=none
chmod 600 /swapfile
mkswap /swapfile >/dev/null
fi
swapon /swapfile
grep -q '^/swapfile ' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab
ok "μ€μ νμ±ν: $SWAP_SIZE"
fi
# λ©λͺ¨λ¦¬κ° λ¨μ λλ μ€μμ κ±°μ μ°μ§ μκ² (λΉλ νΌν¬ λλ§ μ¬μ©)
cat > /etc/sysctl.d/99-honeyrest.conf <<'EOF'
vm.swappiness=10
vm.vfs_cache_pressure=50
EOF
sysctl -q --system >/dev/null 2>&1 || true
# ---- 3) OS λ°©νλ²½ (80/443) ----------------------------------------------------------
# OCI μ½μμ 보μ λͺ©λ‘(Security List) μΈκ·Έλ μ€ κ·μΉμ μ΄ μ€ν¬λ¦½νΈκ° μ΄ μ μλ€ β docs/DEPLOY.md 2μ₯(μ¬μ μ€λΉ)μμ μ§μ μ°λ€.
open_firewall() {
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then
ufw allow 80/tcp >/dev/null
ufw allow 443/tcp >/dev/null
ok "ufw: 80/tcp, 443/tcp νμ©"
return
fi
# Oracle Ubuntu μ΄λ―Έμ§: /etc/iptables/rules.v4 μ "-A INPUT -j REJECT --reject-with icmp-host-prohibited" κ° μλ€.
# μ€ν μ€μΈ κ·μΉ: REJECT μμ ACCEPT λ₯Ό λΌμ λ£λλ€ (μ΄λ―Έ μμΌλ©΄ 건λλ)
local port line
for port in 80 443; do
if ! iptables -C INPUT -p tcp -m state --state NEW -m tcp --dport "$port" -j ACCEPT 2>/dev/null; then
line="$(iptables -L INPUT --line-numbers -n | awk '$2 == "REJECT" { print $1; exit }')"
if [[ -n "$line" ]]; then
iptables -I INPUT "$line" -p tcp -m state --state NEW -m tcp --dport "$port" -j ACCEPT
else
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport "$port" -j ACCEPT
fi
fi
done
# μ¬λΆν
νμλ μ μ§: μ μ₯ νμΌμ μ§μ μμ νλ€.
# (netfilter-persistent save λ Docker κ° λ§λ κ·μΉκΉμ§ μ μ₯ν΄ μ¬λΆν
μ κΌ¬μΌ μ μμΌλ―λ‘ μ°μ§ μλλ€)
local rules=/etc/iptables/rules.v4
if [[ -f "$rules" ]]; then
for port in 80 443; do
if ! grep -Eq -- "--dport $port -j ACCEPT" "$rules"; then
if grep -q -- '^-A INPUT -j REJECT' "$rules"; then
sed -i "0,/^-A INPUT -j REJECT/s//-A INPUT -p tcp -m state --state NEW -m tcp --dport $port -j ACCEPT\n&/" "$rules"
else
sed -i "0,/^COMMIT/s//-A INPUT -p tcp -m state --state NEW -m tcp --dport $port -j ACCEPT\n&/" "$rules"
fi
fi
done
ok "iptables: 80/443 νμ© (μ€ν μ€ κ·μΉ + $rules)"
else
# rules.v4 κ° μλ μ΄λ―Έμ§: iptables-persistent λ‘ μ§κΈ(= Docker μ€μΉ μ ) μνλ₯Ό μ μ₯νλ€
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections
apt-get install -y -q iptables-persistent >/dev/null
if ! systemctl is-active --quiet docker 2>/dev/null; then
netfilter-persistent save >/dev/null 2>&1 || true
fi
ok "iptables: 80/443 νμ© (iptables-persistent)"
fi
}
if [[ "${SKIP_FIREWALL:-0}" == "1" ]]; then
warn "3) λ°©νλ²½ λ¨κ³ 건λλ (SKIP_FIREWALL=1)"
else
log "3) OS λ°©νλ²½ 80/443 νμ©"
open_firewall
fi
# ---- 4) Docker -----------------------------------------------------------------
install_docker() {
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 && docker buildx version >/dev/null 2>&1; then
ok "Docker κ° μ΄λ―Έ μ€μΉλμ΄ μμ΅λλ€: $(docker --version)"
return
fi
local arch codename
arch="$(dpkg --print-architecture)"
codename="${VERSION_CODENAME:-${UBUNTU_CODENAME:-}}"
# μ Ubuntu 릴리μ€κ° Docker μ μ₯μμ μμ§ μμΌλ©΄ μ§μ LTS(noble) ν¨ν€μ§λ₯Ό μ΄λ€
if ! curl -fsSI "https://download.docker.com/linux/ubuntu/dists/${codename}/Release" >/dev/null 2>&1; then
warn "Docker μ μ₯μμ '${codename}' μ΄ μμ΄ noble μ μ₯μλ₯Ό μ¬μ©ν©λλ€."
codename="noble"
fi
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=${arch} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${codename} stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -y -q
if ! apt-get install -y -q docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
warn "곡μ μ μ₯μ μ€μΉ μ€ν¨ β Ubuntu ν¨ν€μ§(docker.io, docker-compose-v2, docker-buildx)λ‘ μ€μΉν©λλ€."
rm -f /etc/apt/sources.list.d/docker.list
apt-get update -y -q
apt-get install -y -q docker.io docker-compose-v2 docker-buildx
fi
}
log "4) Docker Engine + compose νλ¬κ·ΈμΈ"
install_docker
systemctl enable --now docker
if [[ "$TARGET_USER" != "root" ]] && ! id -nG "$TARGET_USER" | grep -qw docker; then
usermod -aG docker "$TARGET_USER"
warn "$TARGET_USER λ₯Ό docker κ·Έλ£Ήμ μΆκ°νμ΅λλ€. sudo μμ΄ docker λ₯Ό μ°λ €λ©΄ λ€μ λ‘κ·ΈμΈνμΈμ."
fi
docker compose version >/dev/null || die "docker compose νλ¬κ·ΈμΈμ μΈ μ μμ΅λλ€."
ok "$(docker --version) / $(docker compose version --short 2>/dev/null || echo compose)"
# ---- 5) μ μ₯μ ν΄λ‘ ---------------------------------------------------------------
clone_repo() {
local url="$1" dir="$2" branch="$3"
if [[ -d "$dir/.git" ]]; then
ok "μ΄λ―Έ μμ: $dir"
else
log "ν΄λ‘ : $url β $dir"
sudo -u "$TARGET_USER" -H git clone --recurse-submodules --branch "$branch" "$url" "$dir"
fi
}
log "5) μ μ₯μ μ€λΉ ($BASE_DIR)"
chown "$TARGET_USER:" "$BASE_DIR" 2>/dev/null || true
clone_repo "$HOST_REPO_URL" "$BASE_DIR/honeyRest_host" "$HOST_BRANCH"
clone_repo "$REACT_REPO_URL" "$BASE_DIR/honeyrest_user_react" "$REACT_BRANCH"
git_as_owner "$BASE_DIR/honeyRest_host" submodule update --init --recursive
[[ -f "$BASE_DIR/honeyRest_host/libs/honeyrest-user/honeyrest-domain/build.gradle" ]] \
|| die "κ΄λ¦¬μ μ μ₯μ μλΈλͺ¨λ(libs/honeyrest-user)μ΄ λΉμ΄ μμ΅λλ€."
# ---- 6) .env ------------------------------------------------------------------
detect_public_ip() {
local ip url
for url in https://ifconfig.me https://api.ipify.org https://checkip.amazonaws.com; do
ip="$(curl -fsS4 --max-time 10 "$url" 2>/dev/null | tr -d '[:space:]')" || true
if [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then printf '%s' "$ip"; return 0; fi
done
return 1
}
gen_hex() { openssl rand -hex "$1"; }
# μ¬λμ΄ μ
λ ₯ν λ°λͺ¨ λΉλ°λ²νΈ: μμ«μ 16μ
gen_password() { openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 16; }
log "6) deploy/.env"
FIRST_INSTALL=0
if [[ ! -f "$ENV_FILE" ]]; then
FIRST_INSTALL=1
install -m 600 -o "$TARGET_USER" "$DEPLOY_DIR/.env.example" "$ENV_FILE"
env_set MYSQL_PASSWORD "$(gen_hex 24)"
env_set MYSQL_ROOT_PASSWORD "$(gen_hex 24)"
env_set USER_JWT_SECRET "$(gen_hex 48)"
env_set HOST_JWT_SECRET "$(gen_hex 48)"
env_set DEMO_COMPANY_PASSWORD "$(gen_password)"
env_set DEMO_ADMIN_PASSWORD "$(gen_password)"
ok ".env μμ± (λΉλ°κ° μλ μμ±, κΆν 600)"
else
ok ".env κ° μ΄λ―Έ μμ΄ κ·Έλλ‘ μ¬μ©ν©λλ€ (λΉλ°κ°μ λ€μ λ§λ€μ§ μμ)"
fi
CURRENT_DOMAIN="$(env_get SITE_DOMAIN)"
if [[ -n "${SITE_DOMAIN:-}" ]]; then
env_set SITE_DOMAIN "$SITE_DOMAIN"
elif [[ -z "$CURRENT_DOMAIN" || "$CURRENT_DOMAIN" == CHANGE_ME* ]]; then
PUBLIC_IP="$(detect_public_ip)" || die "κ³΅μΈ IP λ₯Ό μμλ΄μ§ λͺ»νμ΅λλ€. SITE_DOMAIN=<IP-νμ΄ν>.sslip.io λ‘ μ§μ ν΄ λ€μ μ€ννμΈμ."
env_set SITE_DOMAIN "${PUBLIC_IP//./-}.sslip.io"
fi
SITE="$(env_get SITE_DOMAIN)"
ok "SITE_DOMAIN=$SITE"
# ---- 7) λΉλ & κΈ°λ ---------------------------------------------------------------
log "7) μ΄λ―Έμ§ λΉλ (μλΉμ€λ³ μμ°¨ β 첫 λΉλλ 1 OCPU μμ 15~30λΆ κ±Έλ¦΄ μ μμ΅λλ€)"
for svc in user-api host-admin caddy; do
log "λΉλ: $svc"
compose build "$svc"
done
log "κΈ°λ: docker compose up -d"
compose up -d --remove-orphans
wait_healthy user-api 900 || die "user-api κΈ°λ μ€ν¨ (docker compose logs user-api)"
wait_healthy host-admin 900 || die "host-admin κΈ°λ μ€ν¨ (docker compose logs host-admin)"
# ---- 8) μλ ------------------------------------------------------------------
if [[ "${SKIP_SEED:-0}" == "1" ]]; then
warn "8) μλ 건λλ (SKIP_SEED=1)"
else
log "8) μ΄κΈ° λ°μ΄ν° μλ"
"$DEPLOY_DIR/seed.sh"
fi
# ---- 9) cron ------------------------------------------------------------------
if [[ "${SKIP_CRON:-0}" == "1" ]]; then
warn "9) cron 건λλ (SKIP_CRON=1)"
else
log "9) cron λ±λ‘: /etc/cron.d/honeyrest"
cat > /etc/cron.d/honeyrest <<EOF
# HoneyRest (deploy/setup.sh κ° μμ±) β μκ°μ μλ² μκ°λ(Asia/Seoul) κΈ°μ€
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 5λΆλ§λ€ κ³΅κ° μ£Όμλ‘ μ¬μ©μ APIΒ·κ΄λ¦¬μ μ± ν¬μ€ μ²΄ν¬ (CaddyΒ·μΈμ¦μκΉμ§ ν¨κ» νμΈ, μ€ν¨ μ syslog μ κΈ°λ‘: journalctl -t honeyrest-health)
*/5 * * * * root curl -fsS --max-time 20 -o /dev/null https://${SITE}/api/banner/list && curl -fsS --max-time 20 -o /dev/null https://admin.${SITE}/actuator/health || logger -t honeyrest-health "health check failed: ${SITE}"
# λ§€μΌ 04:30 DBΒ·μ
λ‘λ λ°±μ
(μ΅κ·Ό 7κ° λ³΄κ΄)
30 4 * * * root ${DEPLOY_DIR}/backup.sh >> /var/log/honeyrest-backup.log 2>&1
EOF
chmod 644 /etc/cron.d/honeyrest
ok "cron λ±λ‘ μλ£"
fi
# ---- μλ£ ----------------------------------------------------------------------
cat <<EOF
${C_OK}==================== μ€μΉ μλ£ ====================${C_END}
μ¬μ©μ μ¬μ΄νΈ : https://${SITE}
κ΄λ¦¬μ μ¬μ΄νΈ : https://admin.${SITE}
EOF
if [[ "$(env_get HOST_SPRING_PROFILES)" == *local-demo* ]]; then
cat <<EOF
κ΄λ¦¬μ λ°λͺ¨ κ³μ (λΉλ°λ²νΈλ $ENV_FILE μ μ μ₯λμ΄ μμ)
μ
체 κ΄λ¦¬μ : contact@honeyrest.com / $(env_get DEMO_COMPANY_PASSWORD)
μ΄κ΄λ¦¬μ : admin@honeyrest.com / $(env_get DEMO_ADMIN_PASSWORD)
EOF
fi
cat <<EOF
- HTTPS μΈμ¦μλ 첫 μ μ μ νλ‘ Caddy κ° λ°κΈν©λλ€(μμ μ΄). μ€ν¨νλ©΄: docker compose -f $DEPLOY_DIR/docker-compose.yml logs caddy
- OCI μ½μ 보μ λͺ©λ‘μμ TCP 80/443 μΈκ·Έλ μ€λ₯Ό μ΄μλμ§ νμΈνμΈμ.
- κ²°μ (TOSS_*), λ©μΌ(MAIL_*), μμ
λ‘κ·ΈμΈ ν€λ $ENV_FILE μ μ±μ΄ λ€: sudo $DEPLOY_DIR/update.sh --no-pull
EOF
(( FIRST_INSTALL )) && echo " - μ²μ μμ±λ .env λ λ°±μ
ν΄ λμΈμ (DB λΉλ°λ²νΈλ₯Ό μμΌλ©΄ λ°μ΄ν°μ μ κ·Όν μ μμ΅λλ€)."
exit 0