deploy.sh raw
1 #!/bin/bash
2
3 # ORLY Relay Deployment Script
4 # This script installs Go, builds the relay, and sets up systemd service
5
6 set -e
7
8 # Configuration
9 GO_VERSION="1.25.3"
10 GOROOT="$HOME/go"
11 GOPATH="$HOME"
12 GOBIN="$HOME/.local/bin"
13 GOENV_FILE="$HOME/.goenv"
14 BASHRC_FILE="$HOME/.bashrc"
15 SERVICE_NAME="orly"
16 BINARY_NAME="orly"
17
18 # Colors for output
19 RED='\033[0;31m'
20 GREEN='\033[0;32m'
21 YELLOW='\033[1;33m'
22 BLUE='\033[0;34m'
23 NC='\033[0m' # No Color
24
25 # Logging functions
26 log_info() {
27 echo -e "${BLUE}[INFO]${NC} $1"
28 }
29
30 log_success() {
31 echo -e "${GREEN}[SUCCESS]${NC} $1"
32 }
33
34 log_warning() {
35 echo -e "${YELLOW}[WARNING]${NC} $1"
36 }
37
38 log_error() {
39 echo -e "${RED}[ERROR]${NC} $1"
40 }
41
42 # Check if running as root for certain operations
43 check_root() {
44 if [[ $EUID -eq 0 ]]; then
45 return 0
46 else
47 return 1
48 fi
49 }
50
51 # Check if bun is installed
52 check_bun_installation() {
53 if command -v bun >/dev/null 2>&1; then
54 local installed_version=$(bun --version)
55 log_success "Bun $installed_version is already installed"
56 return 0
57 else
58 log_info "Bun is not installed"
59 return 1
60 fi
61 }
62
63 # Install bun
64 install_bun() {
65 log_info "Installing Bun..."
66
67 # Install bun using official installer
68 curl -fsSL https://bun.com/install | bash
69
70 # Source bashrc to pick up bun in current session
71 if [[ -f "$HOME/.bashrc" ]]; then
72 source "$HOME/.bashrc"
73 fi
74
75 # Verify installation
76 if command -v bun >/dev/null 2>&1; then
77 log_success "Bun installed successfully"
78 else
79 log_error "Failed to install Bun"
80 exit 1
81 fi
82 }
83
84 # Check if Go is installed and get version
85 check_go_installation() {
86 if command -v go >/dev/null 2>&1; then
87 local installed_version=$(go version | grep -o 'go[0-9]\+\.[0-9]\+\.[0-9]\+' | sed 's/go//')
88 local required_version=$(echo $GO_VERSION | sed 's/go//')
89
90 if [[ "$installed_version" == "$required_version" ]]; then
91 log_success "Go $installed_version is already installed"
92 return 0
93 else
94 log_warning "Go $installed_version is installed, but version $required_version is required"
95 return 1
96 fi
97 else
98 log_info "Go is not installed"
99 return 1
100 fi
101 }
102
103 # Install Go
104 install_go() {
105 log_info "Installing Go $GO_VERSION..."
106
107 # Save original directory
108 local original_dir=$(pwd)
109
110 # Determine architecture
111 local arch=$(uname -m)
112 case $arch in
113 x86_64) arch="amd64" ;;
114 aarch64|arm64) arch="arm64" ;;
115 armv7l) arch="armv6l" ;;
116 *) log_error "Unsupported architecture: $arch"; exit 1 ;;
117 esac
118
119 local go_archive="go${GO_VERSION}.linux-${arch}.tar.gz"
120 local download_url="https://golang.org/dl/${go_archive}"
121
122 # Remove existing installation if present (before download to save space/time)
123 if [[ -d "$GOROOT" ]]; then
124 log_info "Removing existing Go installation..."
125 # Make it writable in case it's read-only
126 chmod -R u+w "$GOROOT" 2>/dev/null || true
127 rm -rf "$GOROOT"
128 fi
129
130 # Create directories
131 mkdir -p "$GOBIN"
132
133 # Change to home directory and download Go
134 log_info "Downloading Go from $download_url..."
135 cd ~
136 wget -q "$download_url" || {
137 log_error "Failed to download Go"
138 exit 1
139 }
140
141 # Extract Go to a temporary location first, then move to final destination
142 log_info "Extracting Go..."
143 tar -xf "$go_archive" -C /tmp
144 mv /tmp/go "$GOROOT"
145
146 # Clean up
147 rm -f "$go_archive"
148
149 # Return to original directory
150 cd "$original_dir"
151
152 log_success "Go $GO_VERSION installed successfully"
153 }
154
155 # Setup Go environment
156 setup_go_environment() {
157 log_info "Setting up Go environment..."
158
159 # Create .goenv file
160 cat > "$GOENV_FILE" << EOF
161 # Go environment configuration
162 export GOROOT="$GOROOT"
163 export GOPATH="$GOPATH"
164 export GOBIN="$GOBIN"
165 export PATH="\$GOBIN:\$GOROOT/bin:\$PATH"
166 EOF
167
168 # Source the environment for current session
169 source "$GOENV_FILE"
170
171 # Add to .bashrc if not already present
172 if ! grep -q "source $GOENV_FILE" "$BASHRC_FILE" 2>/dev/null; then
173 log_info "Adding Go environment to $BASHRC_FILE..."
174 echo "" >> "$BASHRC_FILE"
175 echo "# Go environment" >> "$BASHRC_FILE"
176 echo "if [[ -f \"$GOENV_FILE\" ]]; then" >> "$BASHRC_FILE"
177 echo " source \"$GOENV_FILE\"" >> "$BASHRC_FILE"
178 echo "fi" >> "$BASHRC_FILE"
179 log_success "Go environment added to $BASHRC_FILE"
180 else
181 log_info "Go environment already configured in $BASHRC_FILE"
182 fi
183 }
184
185 # Build the application
186 build_application() {
187 log_info "Building ORLY relay..."
188
189 # Source Go environment
190 source "$GOENV_FILE"
191
192 # Update embedded web assets
193 log_info "Updating embedded web assets..."
194 ./scripts/update-embedded-web.sh
195
196 # Build the binary in the current directory
197 log_info "Building binary in current directory (pure Go + purego)..."
198 CGO_ENABLED=0 go build -o "$BINARY_NAME"
199
200 # Verify libsecp256k1.so exists in repo (used by purego for runtime crypto)
201 if [[ -f "./libsecp256k1.so" ]]; then
202 chmod +x libsecp256k1.so
203 log_success "Found libsecp256k1.so in repository"
204 else
205 log_warning "libsecp256k1.so not found in repo - relay will still work but may have slower crypto"
206 fi
207
208 if [[ -f "./$BINARY_NAME" ]]; then
209 log_success "ORLY relay built successfully"
210 else
211 log_error "Failed to build ORLY relay"
212 exit 1
213 fi
214 }
215
216 # Set capabilities for port 443 binding
217 set_capabilities() {
218 log_info "Setting capabilities for port 443 binding..."
219
220 if check_root; then
221 setcap 'cap_net_bind_service=+ep' "./$BINARY_NAME"
222 else
223 sudo setcap 'cap_net_bind_service=+ep' "./$BINARY_NAME"
224 fi
225
226 log_success "Capabilities set for port 443 binding"
227 }
228
229 # Install binary
230 install_binary() {
231 log_info "Installing binary to $GOBIN..."
232
233 # Ensure GOBIN directory exists
234 mkdir -p "$GOBIN"
235
236 # Copy binary and library
237 cp "./$BINARY_NAME" "$GOBIN/"
238 chmod +x "$GOBIN/$BINARY_NAME"
239
240 # Copy library if it exists
241 if [[ -f "./libsecp256k1.so" ]]; then
242 cp "./libsecp256k1.so" "$GOBIN/"
243 log_info "Copied libsecp256k1.so to $GOBIN/"
244 fi
245
246 log_success "Binary installed to $GOBIN/$BINARY_NAME"
247 }
248
249 # Create systemd service
250 create_systemd_service() {
251 local port="$1"
252 log_info "Creating systemd service (port: $port)..."
253
254 local service_file="/etc/systemd/system/${SERVICE_NAME}.service"
255 local working_dir=$(pwd)
256
257 # Create service file content
258 local service_content="[Unit]
259 Description=ORLY Nostr Relay
260 After=network.target
261 Wants=network.target
262
263 [Service]
264 Type=simple
265 User=$USER
266 Group=$USER
267 WorkingDirectory=$working_dir
268 Environment=ORLY_PORT=$port
269 ExecStart=$GOBIN/$BINARY_NAME
270 Restart=always
271 RestartSec=5
272 StandardOutput=journal
273 StandardError=journal
274 SyslogIdentifier=$SERVICE_NAME
275
276 # Network settings
277 AmbientCapabilities=CAP_NET_BIND_SERVICE
278
279 [Install]
280 WantedBy=multi-user.target"
281
282 # Write service file
283 if check_root; then
284 echo "$service_content" > "$service_file"
285 else
286 echo "$service_content" | sudo tee "$service_file" > /dev/null
287 fi
288
289 # Reload systemd and enable service
290 if check_root; then
291 systemctl daemon-reload
292 systemctl enable "$SERVICE_NAME"
293 else
294 sudo systemctl daemon-reload
295 sudo systemctl enable "$SERVICE_NAME"
296 fi
297
298 log_success "Systemd service created and enabled"
299 }
300
301 # Main deployment function
302 main() {
303 local port="${1:-3334}"
304 log_info "Starting ORLY relay deployment (port: $port)..."
305
306 # Check if we're in the right directory
307 if [[ ! -f "go.mod" ]] || ! grep -q "next.orly.dev" go.mod; then
308 log_error "This script must be run from the next.orly.dev project root directory"
309 exit 1
310 fi
311
312 # Check and install Bun if needed
313 if ! check_bun_installation; then
314 install_bun
315 fi
316
317 # Check and install Go if needed
318 if ! check_go_installation; then
319 install_go
320 setup_go_environment
321 fi
322
323 # Build application
324 build_application
325
326 # Set capabilities
327 set_capabilities
328
329 # Install binary
330 install_binary
331
332 # Create systemd service
333 create_systemd_service "$port"
334
335 log_success "ORLY relay deployment completed successfully!"
336 echo ""
337 log_info "Next steps:"
338 echo " 1. Reload your terminal environment: source ~/.bashrc"
339 echo " 2. Configure your relay by setting environment variables"
340 echo " 3. Start the service: sudo systemctl start $SERVICE_NAME"
341 echo " 4. Check service status: sudo systemctl status $SERVICE_NAME"
342 echo " 5. View logs: sudo journalctl -u $SERVICE_NAME -f"
343 echo ""
344 log_info "Service management commands:"
345 echo " Start: sudo systemctl start $SERVICE_NAME"
346 echo " Stop: sudo systemctl stop $SERVICE_NAME"
347 echo " Restart: sudo systemctl restart $SERVICE_NAME"
348 echo " Enable: sudo systemctl enable $SERVICE_NAME --now"
349 echo " Disable: sudo systemctl disable $SERVICE_NAME --now"
350 echo " Status: sudo systemctl status $SERVICE_NAME"
351 echo " Logs: sudo journalctl -u $SERVICE_NAME -f"
352 }
353
354 # Handle command line arguments
355 PORT=""
356 case "${1:-}" in
357 --help|-h)
358 echo "ORLY Relay Deployment Script"
359 echo ""
360 echo "Usage: $0 [options] [port]"
361 echo ""
362 echo "Arguments:"
363 echo " port Port number for the relay to listen on (default: 3334)"
364 echo ""
365 echo "Options:"
366 echo " --help, -h Show this help message"
367 echo ""
368 echo "This script will:"
369 echo " 1. Install Bun if not present"
370 echo " 2. Install Go $GO_VERSION if not present"
371 echo " 3. Set up Go environment in ~/.goenv"
372 echo " 4. Install build dependencies (requires sudo)"
373 echo " 5. Build the ORLY relay"
374 echo " 6. Set capabilities for port 443 binding"
375 echo " 7. Install the binary to ~/.local/bin"
376 echo " 8. Create and enable systemd service"
377 echo ""
378 echo "Examples:"
379 echo " $0 # Deploy with default port 3334"
380 echo " $0 8080 # Deploy with port 8080"
381 exit 0
382 ;;
383 [0-9]*)
384 # First argument is a number, treat it as port
385 PORT="$1"
386 shift
387 main "$PORT" "$@"
388 ;;
389 *)
390 main "$@"
391 ;;
392 esac
393