tayo 0.1.13 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -75
- data/README.md +77 -68
- data/lib/tayo/cli.rb +4 -4
- data/lib/tayo/commands/cf.rb +196 -221
- data/lib/tayo/commands/gh.rb +0 -9
- data/lib/tayo/commands/init.rb +35 -35
- data/lib/tayo/commands/proxy.rb +97 -0
- data/lib/tayo/proxy/cloudflare_client.rb +323 -0
- data/lib/tayo/proxy/docker_manager.rb +150 -0
- data/lib/tayo/proxy/network_config.rb +147 -0
- data/lib/tayo/proxy/traefik_config.rb +303 -0
- data/lib/tayo/proxy/welcome_service.rb +337 -0
- data/lib/tayo/version.rb +1 -1
- data/lib/templates/welcome/Dockerfile +14 -0
- data/lib/templates/welcome/index.html +173 -0
- metadata +24 -6
- data/CLAUDE.md +0 -58
- data/lib/tayo/commands/base.rb +0 -13
- data/lib/tayo/commands/sqlite.rb +0 -413
- data/scripts/setup_rubygems_key.sh +0 -60
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "colorize"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
module Tayo
|
|
7
|
+
module Proxy
|
|
8
|
+
class WelcomeService
|
|
9
|
+
def initialize
|
|
10
|
+
@docker = DockerManager.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ensure_running
|
|
14
|
+
# 호스트에서 3000 포트 서비스 확인 (Docker 제외)
|
|
15
|
+
if host_port_in_use?(3000)
|
|
16
|
+
puts "✅ 3000 포트에 호스트 서비스(Rails 등)가 실행 중입니다.".colorize(:green)
|
|
17
|
+
|
|
18
|
+
# 기존 Welcome 컨테이너가 있다면 중지
|
|
19
|
+
if @docker.container_running?("tayo-welcome")
|
|
20
|
+
puts "🛑 기존 Welcome 서비스를 중지합니다...".colorize(:yellow)
|
|
21
|
+
@docker.stop_container("tayo-welcome")
|
|
22
|
+
end
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Docker 컨테이너로 3000 포트가 사용 중인 경우
|
|
27
|
+
if @docker.container_running?("tayo-welcome")
|
|
28
|
+
puts "✅ Welcome 서비스가 이미 실행 중입니다.".colorize(:green)
|
|
29
|
+
return
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
puts "\n🚀 3000 포트에 Welcome 서비스를 시작합니다...".colorize(:yellow)
|
|
33
|
+
puts " (Rails 서버를 시작하면 자동으로 중지됩니다)".colorize(:gray)
|
|
34
|
+
|
|
35
|
+
prepare_welcome_files
|
|
36
|
+
build_image
|
|
37
|
+
start_container
|
|
38
|
+
|
|
39
|
+
puts "✅ Welcome 서비스가 시작되었습니다.".colorize(:green)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def host_port_in_use?(port)
|
|
45
|
+
# macOS와 Linux에서 호스트 포트 확인 (Docker 컨테이너 제외)
|
|
46
|
+
if RUBY_PLATFORM.include?("darwin")
|
|
47
|
+
# macOS: lsof 사용, Docker 프로세스 제외
|
|
48
|
+
output = `lsof -i :#{port} -sTCP:LISTEN 2>/dev/null | grep -v docker | grep -v com.docke | grep -v tayo-welcome`.strip
|
|
49
|
+
!output.empty?
|
|
50
|
+
else
|
|
51
|
+
# Linux: netstat 또는 ss 사용
|
|
52
|
+
output = `netstat -tln 2>/dev/null | grep ":#{port} " | grep -v docker`.strip
|
|
53
|
+
if output.empty?
|
|
54
|
+
output = `ss -tln 2>/dev/null | grep ":#{port} " | grep -v docker`.strip
|
|
55
|
+
end
|
|
56
|
+
!output.empty?
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def template_dir
|
|
61
|
+
File.expand_path("../../../templates/welcome", __FILE__)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def prepare_welcome_files
|
|
65
|
+
puts "📁 Welcome 서비스 파일을 준비합니다...".colorize(:yellow)
|
|
66
|
+
|
|
67
|
+
# 템플릿 디렉토리 생성
|
|
68
|
+
FileUtils.mkdir_p(template_dir)
|
|
69
|
+
|
|
70
|
+
# Dockerfile 생성
|
|
71
|
+
create_dockerfile
|
|
72
|
+
|
|
73
|
+
# index.html 생성
|
|
74
|
+
create_index_html
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def create_dockerfile
|
|
78
|
+
dockerfile_content = <<~DOCKERFILE
|
|
79
|
+
FROM nginx:alpine
|
|
80
|
+
|
|
81
|
+
# Nginx 설정
|
|
82
|
+
RUN echo 'server { listen 80; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ =404; } }' > /etc/nginx/conf.d/default.conf
|
|
83
|
+
|
|
84
|
+
# HTML 파일 복사
|
|
85
|
+
COPY index.html /usr/share/nginx/html/
|
|
86
|
+
|
|
87
|
+
# 헬스체크
|
|
88
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
89
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost || exit 1
|
|
90
|
+
|
|
91
|
+
EXPOSE 80
|
|
92
|
+
|
|
93
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
94
|
+
DOCKERFILE
|
|
95
|
+
|
|
96
|
+
File.write(File.join(template_dir, "Dockerfile"), dockerfile_content)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def create_index_html
|
|
100
|
+
html_content = <<~HTML
|
|
101
|
+
<!DOCTYPE html>
|
|
102
|
+
<html lang="ko">
|
|
103
|
+
<head>
|
|
104
|
+
<meta charset="UTF-8">
|
|
105
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
106
|
+
<title>Tayo Proxy - Welcome</title>
|
|
107
|
+
<style>
|
|
108
|
+
* {
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding: 0;
|
|
111
|
+
box-sizing: border-box;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
body {
|
|
115
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
116
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
117
|
+
min-height: 100vh;
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
color: white;
|
|
122
|
+
padding: 20px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.container {
|
|
126
|
+
text-align: center;
|
|
127
|
+
max-width: 600px;
|
|
128
|
+
animation: fadeIn 1s ease-in;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@keyframes fadeIn {
|
|
132
|
+
from { opacity: 0; transform: translateY(-20px); }
|
|
133
|
+
to { opacity: 1; transform: translateY(0); }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.logo {
|
|
137
|
+
font-size: 5em;
|
|
138
|
+
margin-bottom: 20px;
|
|
139
|
+
animation: bounce 2s infinite;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@keyframes bounce {
|
|
143
|
+
0%, 100% { transform: translateY(0); }
|
|
144
|
+
50% { transform: translateY(-10px); }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
h1 {
|
|
148
|
+
font-size: 3em;
|
|
149
|
+
margin-bottom: 20px;
|
|
150
|
+
font-weight: 700;
|
|
151
|
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.subtitle {
|
|
155
|
+
font-size: 1.3em;
|
|
156
|
+
opacity: 0.95;
|
|
157
|
+
margin-bottom: 30px;
|
|
158
|
+
line-height: 1.5;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.status {
|
|
162
|
+
background: rgba(255, 255, 255, 0.2);
|
|
163
|
+
border-radius: 10px;
|
|
164
|
+
padding: 20px;
|
|
165
|
+
backdrop-filter: blur(10px);
|
|
166
|
+
margin-top: 30px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.status-item {
|
|
170
|
+
display: flex;
|
|
171
|
+
justify-content: space-between;
|
|
172
|
+
padding: 10px 0;
|
|
173
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.status-item:last-child {
|
|
177
|
+
border-bottom: none;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.status-label {
|
|
181
|
+
font-weight: 600;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.status-value {
|
|
185
|
+
opacity: 0.9;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.status-ok {
|
|
189
|
+
color: #4ade80;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.info-box {
|
|
193
|
+
background: rgba(255, 255, 255, 0.1);
|
|
194
|
+
border-radius: 8px;
|
|
195
|
+
padding: 15px;
|
|
196
|
+
margin-top: 30px;
|
|
197
|
+
font-size: 0.9em;
|
|
198
|
+
opacity: 0.85;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.footer {
|
|
202
|
+
margin-top: 50px;
|
|
203
|
+
font-size: 0.85em;
|
|
204
|
+
opacity: 0.7;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.footer a {
|
|
208
|
+
color: white;
|
|
209
|
+
text-decoration: none;
|
|
210
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
|
211
|
+
transition: border-color 0.3s;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.footer a:hover {
|
|
215
|
+
border-bottom-color: white;
|
|
216
|
+
}
|
|
217
|
+
</style>
|
|
218
|
+
</head>
|
|
219
|
+
<body>
|
|
220
|
+
<div class="container">
|
|
221
|
+
<div class="logo">🚀</div>
|
|
222
|
+
<h1>Tayo Proxy</h1>
|
|
223
|
+
<p class="subtitle">
|
|
224
|
+
홈서버 프록시 서비스가 정상적으로 작동 중입니다<br>
|
|
225
|
+
Your home server proxy is running successfully
|
|
226
|
+
</p>
|
|
227
|
+
|
|
228
|
+
<div class="status">
|
|
229
|
+
<div class="status-item">
|
|
230
|
+
<span class="status-label">프록시 상태</span>
|
|
231
|
+
<span class="status-value status-ok">✓ 활성</span>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="status-item">
|
|
234
|
+
<span class="status-label">Kamal Proxy</span>
|
|
235
|
+
<span class="status-value status-ok">✓ 실행 중</span>
|
|
236
|
+
</div>
|
|
237
|
+
<div class="status-item">
|
|
238
|
+
<span class="status-label">Caddy Server</span>
|
|
239
|
+
<span class="status-value status-ok">✓ 실행 중</span>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="status-item">
|
|
242
|
+
<span class="status-label">SSL/TLS</span>
|
|
243
|
+
<span class="status-value status-ok">✓ 준비됨</span>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
<div class="info-box">
|
|
248
|
+
<strong>💡 다음 단계:</strong><br>
|
|
249
|
+
이제 실제 애플리케이션을 3000 포트에 배포하면<br>
|
|
250
|
+
이 페이지 대신 애플리케이션이 표시됩니다.
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<div class="footer">
|
|
254
|
+
<p>
|
|
255
|
+
Powered by <a href="https://github.com/TeamMilestone/tayo" target="_blank">Tayo</a> |
|
|
256
|
+
<a href="https://kamal-deploy.org" target="_blank">Kamal</a> |
|
|
257
|
+
<a href="https://caddyserver.com" target="_blank">Caddy</a>
|
|
258
|
+
</p>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<script>
|
|
263
|
+
// 현재 시간 표시 (옵션)
|
|
264
|
+
const updateTime = () => {
|
|
265
|
+
const now = new Date();
|
|
266
|
+
const timeString = now.toLocaleTimeString('ko-KR');
|
|
267
|
+
// 시간 표시 기능이 필요한 경우 활성화
|
|
268
|
+
};
|
|
269
|
+
setInterval(updateTime, 1000);
|
|
270
|
+
updateTime();
|
|
271
|
+
</script>
|
|
272
|
+
</body>
|
|
273
|
+
</html>
|
|
274
|
+
HTML
|
|
275
|
+
|
|
276
|
+
File.write(File.join(template_dir, "index.html"), html_content)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def build_image
|
|
280
|
+
puts "🔨 Docker 이미지를 빌드합니다...".colorize(:yellow)
|
|
281
|
+
|
|
282
|
+
cmd = "docker build -t tayo-welcome:latest #{template_dir}"
|
|
283
|
+
|
|
284
|
+
if system(cmd)
|
|
285
|
+
puts "✅ Docker 이미지 빌드가 완료되었습니다.".colorize(:green)
|
|
286
|
+
else
|
|
287
|
+
puts "❌ Docker 이미지 빌드에 실패했습니다.".colorize(:red)
|
|
288
|
+
exit 1
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def start_container
|
|
293
|
+
puts "🚀 Welcome 컨테이너를 시작합니다...".colorize(:yellow)
|
|
294
|
+
|
|
295
|
+
# 기존 컨테이너가 있다면 제거
|
|
296
|
+
if @docker.container_exists?("tayo-welcome")
|
|
297
|
+
@docker.stop_container("tayo-welcome")
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# 네트워크 확인
|
|
301
|
+
network = @docker.create_network_if_not_exists("tayo-proxy")
|
|
302
|
+
|
|
303
|
+
# Welcome 컨테이너 실행
|
|
304
|
+
cmd = <<~DOCKER
|
|
305
|
+
docker run -d \
|
|
306
|
+
--name tayo-welcome \
|
|
307
|
+
--network #{network} \
|
|
308
|
+
-p 3000:80 \
|
|
309
|
+
--restart unless-stopped \
|
|
310
|
+
tayo-welcome:latest
|
|
311
|
+
DOCKER
|
|
312
|
+
|
|
313
|
+
if system(cmd)
|
|
314
|
+
puts "✅ Welcome 서비스가 포트 3000에서 시작되었습니다.".colorize(:green)
|
|
315
|
+
|
|
316
|
+
# 서비스 확인
|
|
317
|
+
sleep 2
|
|
318
|
+
check_service_health
|
|
319
|
+
else
|
|
320
|
+
puts "❌ Welcome 서비스 시작에 실패했습니다.".colorize(:red)
|
|
321
|
+
exit 1
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def check_service_health
|
|
326
|
+
# curl로 서비스 확인
|
|
327
|
+
response = `curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 2>/dev/null`.strip
|
|
328
|
+
|
|
329
|
+
if response == "200"
|
|
330
|
+
puts "✅ Welcome 서비스가 정상적으로 응답합니다.".colorize(:green)
|
|
331
|
+
else
|
|
332
|
+
puts "⚠️ Welcome 서비스 응답 확인 중... (HTTP #{response})".colorize(:yellow)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
data/lib/tayo/version.rb
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
FROM nginx:alpine
|
|
2
|
+
|
|
3
|
+
# Nginx 설정
|
|
4
|
+
RUN echo 'server { listen 80; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ =404; } }' > /etc/nginx/conf.d/default.conf
|
|
5
|
+
|
|
6
|
+
# HTML 파일 복사
|
|
7
|
+
COPY index.html /usr/share/nginx/html/
|
|
8
|
+
|
|
9
|
+
# 헬스체크
|
|
10
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD wget --no-verbose --tries=1 --spider http://localhost || exit 1
|
|
11
|
+
|
|
12
|
+
EXPOSE 80
|
|
13
|
+
|
|
14
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="ko">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Tayo Proxy - Welcome</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
color: white;
|
|
22
|
+
padding: 20px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.container {
|
|
26
|
+
text-align: center;
|
|
27
|
+
max-width: 600px;
|
|
28
|
+
animation: fadeIn 1s ease-in;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@keyframes fadeIn {
|
|
32
|
+
from { opacity: 0; transform: translateY(-20px); }
|
|
33
|
+
to { opacity: 1; transform: translateY(0); }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.logo {
|
|
37
|
+
font-size: 5em;
|
|
38
|
+
margin-bottom: 20px;
|
|
39
|
+
animation: bounce 2s infinite;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@keyframes bounce {
|
|
43
|
+
0%, 100% { transform: translateY(0); }
|
|
44
|
+
50% { transform: translateY(-10px); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
h1 {
|
|
48
|
+
font-size: 3em;
|
|
49
|
+
margin-bottom: 20px;
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.subtitle {
|
|
55
|
+
font-size: 1.3em;
|
|
56
|
+
opacity: 0.95;
|
|
57
|
+
margin-bottom: 30px;
|
|
58
|
+
line-height: 1.5;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.status {
|
|
62
|
+
background: rgba(255, 255, 255, 0.2);
|
|
63
|
+
border-radius: 10px;
|
|
64
|
+
padding: 20px;
|
|
65
|
+
backdrop-filter: blur(10px);
|
|
66
|
+
margin-top: 30px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.status-item {
|
|
70
|
+
display: flex;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
padding: 10px 0;
|
|
73
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.status-item:last-child {
|
|
77
|
+
border-bottom: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.status-label {
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.status-value {
|
|
85
|
+
opacity: 0.9;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.status-ok {
|
|
89
|
+
color: #4ade80;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.info-box {
|
|
93
|
+
background: rgba(255, 255, 255, 0.1);
|
|
94
|
+
border-radius: 8px;
|
|
95
|
+
padding: 15px;
|
|
96
|
+
margin-top: 30px;
|
|
97
|
+
font-size: 0.9em;
|
|
98
|
+
opacity: 0.85;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.footer {
|
|
102
|
+
margin-top: 50px;
|
|
103
|
+
font-size: 0.85em;
|
|
104
|
+
opacity: 0.7;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.footer a {
|
|
108
|
+
color: white;
|
|
109
|
+
text-decoration: none;
|
|
110
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
|
111
|
+
transition: border-color 0.3s;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.footer a:hover {
|
|
115
|
+
border-bottom-color: white;
|
|
116
|
+
}
|
|
117
|
+
</style>
|
|
118
|
+
</head>
|
|
119
|
+
<body>
|
|
120
|
+
<div class="container">
|
|
121
|
+
<div class="logo">🚀</div>
|
|
122
|
+
<h1>Tayo Proxy</h1>
|
|
123
|
+
<p class="subtitle">
|
|
124
|
+
홈서버 프록시 서비스가 정상적으로 작동 중입니다<br>
|
|
125
|
+
Your home server proxy is running successfully
|
|
126
|
+
</p>
|
|
127
|
+
|
|
128
|
+
<div class="status">
|
|
129
|
+
<div class="status-item">
|
|
130
|
+
<span class="status-label">프록시 상태</span>
|
|
131
|
+
<span class="status-value status-ok">✓ 활성</span>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="status-item">
|
|
134
|
+
<span class="status-label">Kamal Proxy</span>
|
|
135
|
+
<span class="status-value status-ok">✓ 실행 중</span>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="status-item">
|
|
138
|
+
<span class="status-label">Caddy Server</span>
|
|
139
|
+
<span class="status-value status-ok">✓ 실행 중</span>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="status-item">
|
|
142
|
+
<span class="status-label">SSL/TLS</span>
|
|
143
|
+
<span class="status-value status-ok">✓ 준비됨</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="info-box">
|
|
148
|
+
<strong>💡 다음 단계:</strong><br>
|
|
149
|
+
이제 실제 애플리케이션을 3000 포트에 배포하면<br>
|
|
150
|
+
이 페이지 대신 애플리케이션이 표시됩니다.
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div class="footer">
|
|
154
|
+
<p>
|
|
155
|
+
Powered by <a href="https://github.com/TeamMilestone/tayo" target="_blank">Tayo</a> |
|
|
156
|
+
<a href="https://kamal-deploy.org" target="_blank">Kamal</a> |
|
|
157
|
+
<a href="https://caddyserver.com" target="_blank">Caddy</a>
|
|
158
|
+
</p>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<script>
|
|
163
|
+
// 현재 시간 표시 (옵션)
|
|
164
|
+
const updateTime = () => {
|
|
165
|
+
const now = new Date();
|
|
166
|
+
const timeString = now.toLocaleTimeString('ko-KR');
|
|
167
|
+
// 시간 표시 기능이 필요한 경우 활성화
|
|
168
|
+
};
|
|
169
|
+
setInterval(updateTime, 1000);
|
|
170
|
+
updateTime();
|
|
171
|
+
</script>
|
|
172
|
+
</body>
|
|
173
|
+
</html>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tayo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 이원섭wonsup Lee/Alfonso
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '0.23'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: logger
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '1.6'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '1.6'
|
|
68
82
|
description: Tayo is a deployment tool for Rails applications to home servers using
|
|
69
83
|
GitHub Container Registry and Cloudflare CLI.
|
|
70
84
|
email:
|
|
@@ -76,22 +90,26 @@ extra_rdoc_files: []
|
|
|
76
90
|
files:
|
|
77
91
|
- ".DS_Store"
|
|
78
92
|
- CHANGELOG.md
|
|
79
|
-
- CLAUDE.md
|
|
80
93
|
- README.md
|
|
81
94
|
- Rakefile
|
|
82
95
|
- exe/tayo
|
|
83
96
|
- lib/tayo.rb
|
|
84
97
|
- lib/tayo/cli.rb
|
|
85
|
-
- lib/tayo/commands/base.rb
|
|
86
98
|
- lib/tayo/commands/cf.rb
|
|
87
99
|
- lib/tayo/commands/gh.rb
|
|
88
100
|
- lib/tayo/commands/init.rb
|
|
89
|
-
- lib/tayo/commands/
|
|
101
|
+
- lib/tayo/commands/proxy.rb
|
|
90
102
|
- lib/tayo/dockerfile_modifier.rb
|
|
103
|
+
- lib/tayo/proxy/cloudflare_client.rb
|
|
104
|
+
- lib/tayo/proxy/docker_manager.rb
|
|
105
|
+
- lib/tayo/proxy/network_config.rb
|
|
106
|
+
- lib/tayo/proxy/traefik_config.rb
|
|
107
|
+
- lib/tayo/proxy/welcome_service.rb
|
|
91
108
|
- lib/tayo/version.rb
|
|
109
|
+
- lib/templates/welcome/Dockerfile
|
|
110
|
+
- lib/templates/welcome/index.html
|
|
92
111
|
- pkg/homebody-0.1.0.gem
|
|
93
112
|
- repomix-output.xml
|
|
94
|
-
- scripts/setup_rubygems_key.sh
|
|
95
113
|
- sig/tayo.rbs
|
|
96
114
|
homepage: https://github.com/TeamMilestone/tayo
|
|
97
115
|
licenses: []
|
|
@@ -113,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
113
131
|
- !ruby/object:Gem::Version
|
|
114
132
|
version: '0'
|
|
115
133
|
requirements: []
|
|
116
|
-
rubygems_version: 3.
|
|
134
|
+
rubygems_version: 3.7.1
|
|
117
135
|
specification_version: 4
|
|
118
136
|
summary: Rails deployment tool for home servers
|
|
119
137
|
test_files: []
|
data/CLAUDE.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
Tayo is a Ruby gem that simplifies Rails app deployment to home servers using GitHub Container Registry and Cloudflare.
|
|
7
|
-
|
|
8
|
-
## Common Development Commands
|
|
9
|
-
|
|
10
|
-
### Testing
|
|
11
|
-
```bash
|
|
12
|
-
# Run all tests
|
|
13
|
-
rake test
|
|
14
|
-
|
|
15
|
-
# Run specific test file
|
|
16
|
-
ruby -Ilib:test test/dockerfile_modifier_test.rb
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### Building and Installing
|
|
20
|
-
```bash
|
|
21
|
-
# Build gem
|
|
22
|
-
rake build
|
|
23
|
-
|
|
24
|
-
# Install locally
|
|
25
|
-
rake install
|
|
26
|
-
|
|
27
|
-
# Release to RubyGems.org
|
|
28
|
-
rake release
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Architecture
|
|
32
|
-
|
|
33
|
-
### Core Structure
|
|
34
|
-
- `lib/tayo/cli.rb` - Thor-based CLI entry point
|
|
35
|
-
- `lib/tayo/commands/` - Command modules:
|
|
36
|
-
- `init.rb` - Rails project initialization with Docker setup
|
|
37
|
-
- `gh.rb` - GitHub repository and Container Registry configuration
|
|
38
|
-
- `cf.rb` - Cloudflare DNS configuration
|
|
39
|
-
- `lib/tayo/dockerfile_modifier.rb` - Handles bootsnap removal from Dockerfiles
|
|
40
|
-
|
|
41
|
-
### Key Patterns
|
|
42
|
-
1. **Command Structure**: Each command is a separate module under `Commands`
|
|
43
|
-
2. **Error Handling**: Use colorized Korean messages for user-friendly output
|
|
44
|
-
3. **Security**: Store sensitive tokens with 600 permissions, use macOS Keychain for Cloudflare tokens
|
|
45
|
-
4. **Git Integration**: Auto-commit after each major step with descriptive messages
|
|
46
|
-
5. **User Interaction**: Use TTY::Prompt for interactive configuration
|
|
47
|
-
|
|
48
|
-
### Workflow
|
|
49
|
-
The typical usage flow:
|
|
50
|
-
1. `tayo init` - Sets up Rails project with Docker
|
|
51
|
-
2. `tayo gh` - Configures GitHub repository and Container Registry
|
|
52
|
-
3. `tayo cf` - Sets up Cloudflare DNS
|
|
53
|
-
4. `bin/kamal setup` - Deploys the application
|
|
54
|
-
|
|
55
|
-
### Testing Approach
|
|
56
|
-
- Uses Minitest framework
|
|
57
|
-
- Tests focus on unit testing individual components
|
|
58
|
-
- DockerfileModifier has comprehensive test coverage
|