Skip to content

Commit 47fd9a9

Browse files
authored
Merge pull request #58 from ToRvaLDz/master
feat: add named Cloudflare tunnel support
2 parents 14f7d82 + f1a126e commit 47fd9a9

2 files changed

Lines changed: 219 additions & 36 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[Unit]
2+
Description=Codeman Cloudflare Named Tunnel
3+
After=network-online.target codeman-web.service
4+
Wants=network-online.target
5+
6+
[Service]
7+
Type=simple
8+
ExecStart=/usr/bin/cloudflared tunnel --config %h/.cloudflared/codeman.yml run codeman
9+
Restart=always
10+
RestartSec=5
11+
KillMode=process
12+
13+
# Logging
14+
StandardOutput=journal
15+
StandardError=journal
16+
SyslogIdentifier=codeman-tunnel-named
17+
18+
[Install]
19+
WantedBy=default.target

scripts/tunnel.sh

Lines changed: 200 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,209 @@
11
#!/usr/bin/env bash
2-
# Quick Cloudflare Tunnel for Codeman
3-
# Usage: ./scripts/tunnel.sh [start|stop|status|url]
2+
# Cloudflare Tunnel manager for Codeman
3+
# Usage: ./scripts/tunnel.sh [quick|named] [start|stop|status|url]
4+
#
5+
# Modes:
6+
# quick — Quick tunnel with random trycloudflare.com URL (default)
7+
# named — Named tunnel on a fixed hostname (requires setup, see below)
8+
#
9+
# Environment variables:
10+
# CLOUDFLARED_TUNNEL_NAME — tunnel name (default: codeman)
11+
# CLOUDFLARED_TUNNEL_ID — tunnel UUID (from: cloudflared tunnel list)
12+
# CODEMAN_TUNNEL_HOSTNAME — public hostname (e.g. codeman.example.com)
13+
#
14+
# First-time named tunnel setup:
15+
# cloudflared tunnel login
16+
# cloudflared tunnel create <tunnel-name>
17+
# cloudflared tunnel route dns <tunnel-name> <hostname>
18+
# ./scripts/tunnel.sh named setup # writes ~/.cloudflared/<tunnel-name>.yml
419
set -euo pipefail
520

6-
SERVICE="codeman-tunnel"
7-
8-
case "${1:-start}" in
9-
start)
10-
if ! systemctl --user is-active "$SERVICE" &>/dev/null; then
11-
# Install service if not already
12-
if ! systemctl --user cat "$SERVICE" &>/dev/null 2>&1; then
13-
cp "$(dirname "$0")/codeman-tunnel.service" "$HOME/.config/systemd/user/"
14-
systemctl --user daemon-reload
15-
fi
16-
systemctl --user start "$SERVICE"
17-
echo "Tunnel starting... waiting for URL"
18-
sleep 6
19-
fi
20-
# Extract the tunnel URL from journal
21-
URL=$(grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$HOME/.codeman/tunnel.log" 2>/dev/null | tail -1)
22-
if [ -n "$URL" ]; then
23-
echo "$URL"
24-
else
25-
echo "URL not ready yet, try: $0 url"
26-
fi
27-
;;
28-
stop)
29-
systemctl --user stop "$SERVICE"
30-
echo "Tunnel stopped"
31-
;;
32-
status)
33-
systemctl --user status "$SERVICE" --no-pager 2>&1 | head -10
34-
echo ""
35-
echo "URL:"
36-
grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$HOME/.codeman/tunnel.log" 2>/dev/null | tail -1
21+
QUICK_SERVICE="codeman-tunnel"
22+
NAMED_SERVICE="codeman-tunnel-named"
23+
TUNNEL_NAME="${CLOUDFLARED_TUNNEL_NAME:-codeman}"
24+
TUNNEL_HOSTNAME="${CODEMAN_TUNNEL_HOSTNAME:-codeman.example.com}"
25+
CODEMAN_PORT="3000"
26+
LOG_FILE="$HOME/.codeman/tunnel.log"
27+
28+
# ── helpers ──────────────────────────────────────────────────────────────────
29+
30+
_require_cloudflared() {
31+
if ! command -v cloudflared &>/dev/null; then
32+
echo "Error: cloudflared not found. Install with: yay -S cloudflared" >&2
33+
exit 1
34+
fi
35+
}
36+
37+
_cloudflared_bin() {
38+
command -v cloudflared
39+
}
40+
41+
_install_service() {
42+
local svc_file="$1"
43+
local svc_name="$2"
44+
if ! systemctl --user cat "$svc_name" &>/dev/null 2>&1; then
45+
cp "$(dirname "$0")/$svc_file" "$HOME/.config/systemd/user/"
46+
systemctl --user daemon-reload
47+
echo "Service $svc_name installed."
48+
fi
49+
}
50+
51+
_install_named_service() {
52+
if ! systemctl --user cat "$NAMED_SERVICE" &>/dev/null 2>&1; then
53+
# Generate service file with the configured tunnel name
54+
sed "s/codeman\.yml/$TUNNEL_NAME.yml/g; s/run codeman/run $TUNNEL_NAME/g" \
55+
"$(dirname "$0")/codeman-tunnel-named.service" \
56+
> "$HOME/.config/systemd/user/codeman-tunnel-named.service"
57+
systemctl --user daemon-reload
58+
echo "Service $NAMED_SERVICE installed (tunnel: $TUNNEL_NAME)."
59+
fi
60+
}
61+
62+
# ── named tunnel setup ───────────────────────────────────────────────────────
63+
64+
_named_setup() {
65+
_require_cloudflared
66+
67+
local creds_dir="$HOME/.cloudflared"
68+
local config_file="$creds_dir/$TUNNEL_NAME.yml"
69+
# Replace with your tunnel ID (from: cloudflared tunnel list)
70+
local tunnel_id="${CLOUDFLARED_TUNNEL_ID:-YOUR_TUNNEL_ID_HERE}"
71+
local creds_file="$creds_dir/$tunnel_id.json"
72+
73+
if [ ! -f "$creds_file" ]; then
74+
echo "Credentials not found: $creds_file"
75+
echo "Run: cloudflared tunnel create $TUNNEL_NAME"
76+
exit 1
77+
fi
78+
79+
cat > "$config_file" <<EOF
80+
tunnel: $tunnel_id
81+
credentials-file: $creds_file
82+
83+
ingress:
84+
- hostname: $TUNNEL_HOSTNAME
85+
service: http://localhost:$CODEMAN_PORT
86+
- service: http_status:404
87+
EOF
88+
89+
echo "Config written to $config_file"
90+
echo "Tunnel ID: $tunnel_id"
91+
echo "Hostname: $TUNNEL_HOSTNAME"
92+
echo ""
93+
echo "Next steps:"
94+
echo " 1. Add Cloudflare Access policy for $TUNNEL_HOSTNAME (Zero Trust dashboard)"
95+
echo " 2. ./scripts/tunnel.sh named start"
96+
}
97+
98+
# ── quick mode ───────────────────────────────────────────────────────────────
99+
100+
_quick_start() {
101+
if ! systemctl --user is-active "$QUICK_SERVICE" &>/dev/null; then
102+
_install_service "codeman-tunnel.service" "$QUICK_SERVICE"
103+
systemctl --user start "$QUICK_SERVICE"
104+
echo "Quick tunnel starting... waiting for URL"
105+
sleep 6
106+
fi
107+
local url
108+
url=$(grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$LOG_FILE" 2>/dev/null | tail -1)
109+
if [ -n "$url" ]; then
110+
echo "$url"
111+
else
112+
echo "URL not ready yet, try: $0 quick url"
113+
fi
114+
}
115+
116+
_quick_stop() {
117+
systemctl --user stop "$QUICK_SERVICE"
118+
echo "Quick tunnel stopped"
119+
}
120+
121+
_quick_status() {
122+
systemctl --user status "$QUICK_SERVICE" --no-pager 2>&1 | head -10
123+
echo ""
124+
echo "URL:"
125+
grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$LOG_FILE" 2>/dev/null | tail -1
126+
}
127+
128+
_quick_url() {
129+
grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$LOG_FILE" 2>/dev/null | tail -1
130+
}
131+
132+
# ── named mode ───────────────────────────────────────────────────────────────
133+
134+
_named_start() {
135+
_require_cloudflared
136+
if [ ! -f "$HOME/.cloudflared/$TUNNEL_NAME.yml" ]; then
137+
echo "Config not found. Run: $0 named setup"
138+
exit 1
139+
fi
140+
if ! systemctl --user is-active "$NAMED_SERVICE" &>/dev/null; then
141+
_install_named_service
142+
systemctl --user start "$NAMED_SERVICE"
143+
echo "Named tunnel starting..."
144+
sleep 3
145+
fi
146+
echo "https://$TUNNEL_HOSTNAME"
147+
}
148+
149+
_named_stop() {
150+
systemctl --user stop "$NAMED_SERVICE"
151+
echo "Named tunnel stopped"
152+
}
153+
154+
_named_status() {
155+
systemctl --user status "$NAMED_SERVICE" --no-pager 2>&1 | head -10
156+
echo ""
157+
echo "URL: https://$TUNNEL_HOSTNAME"
158+
}
159+
160+
_named_enable() {
161+
_install_named_service
162+
systemctl --user enable "$NAMED_SERVICE"
163+
echo "Named tunnel enabled at boot."
164+
}
165+
166+
_named_disable() {
167+
systemctl --user disable "$NAMED_SERVICE"
168+
echo "Named tunnel disabled."
169+
}
170+
171+
# ── dispatch ─────────────────────────────────────────────────────────────────
172+
173+
MODE="${1:-quick}"
174+
CMD="${2:-start}"
175+
176+
case "$MODE" in
177+
quick)
178+
case "$CMD" in
179+
start) _quick_start ;;
180+
stop) _quick_stop ;;
181+
status) _quick_status ;;
182+
url) _quick_url ;;
183+
*) echo "Usage: $0 quick [start|stop|status|url]"; exit 1 ;;
184+
esac
37185
;;
38-
url)
39-
grep -oP 'https://[a-z0-9-]+\.trycloudflare\.com' "$HOME/.codeman/tunnel.log" 2>/dev/null | tail -1
186+
named)
187+
case "$CMD" in
188+
start) _named_start ;;
189+
stop) _named_stop ;;
190+
status) _named_status ;;
191+
url) echo "https://$TUNNEL_HOSTNAME" ;;
192+
setup) _named_setup ;;
193+
enable) _named_enable ;;
194+
disable) _named_disable ;;
195+
*) echo "Usage: $0 named [start|stop|status|url|setup|enable|disable]"; exit 1 ;;
196+
esac
40197
;;
198+
# backward compat: no mode prefix → quick tunnel
199+
start) _quick_start ;;
200+
stop) _quick_stop ;;
201+
status) _quick_status ;;
202+
url) _quick_url ;;
41203
*)
42-
echo "Usage: $0 [start|stop|status|url]"
204+
echo "Usage: $0 [quick|named] [start|stop|status|url]"
205+
echo " $0 named setup # first-time named tunnel configuration"
206+
echo " $0 named enable # start at boot"
43207
exit 1
44208
;;
45209
esac

0 commit comments

Comments
 (0)