Monorepo for Aesthetic.Computer
aesthetic.computer
1#!/usr/bin/env fish
2# Deploy dp1-feed (SQLite mode) to silo.aesthetic.computer
3#
4# Usage:
5# fish deploy-silo.fish # Full deploy (build, upload, restart)
6# fish deploy-silo.fish --landing # Landing page only (no restart)
7# fish deploy-silo.fish --setup # First-time setup (create dirs, systemd service, env)
8
9set RED '\033[0;31m'
10set GREEN '\033[0;32m'
11set YELLOW '\033[1;33m'
12set NC '\033[0m'
13
14set SCRIPT_DIR (dirname (status --current-filename))
15set VAULT_DIR "$SCRIPT_DIR/../aesthetic-computer-vault"
16set SSH_KEY "$VAULT_DIR/home/.ssh/id_rsa"
17set SILO_HOST "silo.aesthetic.computer"
18set SILO_USER "root"
19set REMOTE_DIR "/opt/dp1-feed"
20set DP1_DIR "$SCRIPT_DIR/dp1-feed"
21
22set SETUP false
23set LANDING_ONLY false
24if contains -- --setup $argv
25 set SETUP true
26end
27if contains -- --landing $argv
28 set LANDING_ONLY true
29end
30
31# Check for SSH key
32if not test -f $SSH_KEY
33 echo -e "$RED x SSH key not found: $SSH_KEY$NC"
34 exit 1
35end
36
37# Test SSH connection
38echo -e "$GREEN-> Testing SSH connection to $SILO_HOST...$NC"
39if not ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=10 $SILO_USER@$SILO_HOST "echo ok" &>/dev/null
40 echo -e "$RED x Cannot connect to $SILO_HOST$NC"
41 exit 1
42end
43echo -e "$GREEN Connected.$NC"
44
45if test $LANDING_ONLY = true
46 echo -e "$GREEN-> Uploading landing-page.html (no restart)...$NC"
47 scp -i $SSH_KEY -o StrictHostKeyChecking=no \
48 $SCRIPT_DIR/landing-page.html \
49 $SILO_USER@$SILO_HOST:$REMOTE_DIR/
50 ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "chown dp1feed:dp1feed $REMOTE_DIR/landing-page.html"
51 echo -e "$GREEN Landing page deployed.$NC"
52 exit 0
53end
54
55if test $SETUP = true
56 # First-time setup: create dirs, systemd service, generate keys
57 echo -e "$GREEN-> First-time setup on $SILO_HOST...$NC"
58
59 ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "
60 # Create app directory and user
61 mkdir -p $REMOTE_DIR/data
62 id -u dp1feed &>/dev/null || useradd -r -s /bin/false dp1feed
63 chown -R dp1feed:dp1feed $REMOTE_DIR
64
65 # Install Node.js 22 if not present
66 if ! command -v node &>/dev/null || [ \$(node -v | cut -d. -f1 | tr -d v) -lt 22 ]; then
67 curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
68 apt-get install -y nodejs
69 fi
70 echo 'Node:' \$(node -v)
71
72 # Install build tools for better-sqlite3
73 apt-get install -y python3 make g++ 2>/dev/null
74
75 # Create systemd service
76 cat > /etc/systemd/system/dp1-feed.service << 'UNIT'
77[Unit]
78Description=DP-1 Feed Operator API (SQLite)
79After=network.target
80
81[Service]
82Type=simple
83User=dp1feed
84WorkingDirectory=/opt/dp1-feed
85ExecStart=/usr/bin/node dist/server-sqlite.js
86EnvironmentFile=/opt/dp1-feed/.env
87Restart=always
88RestartSec=5
89
90[Install]
91WantedBy=multi-user.target
92UNIT
93
94 systemctl daemon-reload
95 systemctl enable dp1-feed
96 echo 'Systemd service created and enabled.'
97 "
98
99 # Read API secret from vault (shared with silo dashboard)
100 echo -e "$GREEN-> Generating .env...$NC"
101 set VAULT_FEED_ENV "$VAULT_DIR/feed/.env"
102 if test -f $VAULT_FEED_ENV
103 set API_SECRET (grep '^FEED_API_SECRET=' $VAULT_FEED_ENV | sed 's/^FEED_API_SECRET=//')
104 end
105 if test -z "$API_SECRET"
106 set API_SECRET (openssl rand -hex 32)
107 echo -e "$YELLOW No vault secret found, generated random API_SECRET$NC"
108 end
109 set ED25519_KEY (node -e "
110 const { generateKeyPairSync } = require('crypto');
111 const kp = generateKeyPairSync('ed25519');
112 const der = kp.privateKey.export({ type: 'pkcs8', format: 'der' });
113 console.log(Buffer.from(der).toString('hex'));
114 " 2>/dev/null; or echo "302e020100300506032b6570042204205e42cad90e34efb36d84b8dbbcf15777ac33f4126a80c087cdedfb030138ac6f")
115
116 ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "cat > $REMOTE_DIR/.env << EOF
117API_SECRET=$API_SECRET
118ED25519_PRIVATE_KEY=$ED25519_KEY
119SQLITE_DB_PATH=/opt/dp1-feed/data/dp1-feed.db
120ENVIRONMENT=sqlite
121SELF_HOSTED_DOMAINS=silo.aesthetic.computer:8787,localhost:8787
122PORT=8787
123EOF
124 chown dp1feed:dp1feed $REMOTE_DIR/.env
125 chmod 600 $REMOTE_DIR/.env"
126
127 echo -e "$GREEN Setup complete. Run 'fish deploy-silo.fish' to deploy.$NC"
128 exit 0
129end
130
131# Regular deploy: build locally, upload, restart
132echo -e "$GREEN-> Building dp1-feed (SQLite)...$NC"
133cd $DP1_DIR
134npm run sqlite:build 2>&1 | tail -1
135
136if test $status -ne 0
137 echo -e "$RED x Build failed$NC"
138 exit 1
139end
140
141echo -e "$GREEN-> Uploading to $SILO_HOST...$NC"
142ssh -i $SSH_KEY -o StrictHostKeyChecking=no $SILO_USER@$SILO_HOST "mkdir -p $REMOTE_DIR/dist"
143scp -i $SSH_KEY -o StrictHostKeyChecking=no \
144 $DP1_DIR/dist/server-sqlite.js \
145 $SILO_USER@$SILO_HOST:$REMOTE_DIR/dist/
146scp -i $SSH_KEY -o StrictHostKeyChecking=no \
147 $DP1_DIR/package.json \
148 $DP1_DIR/package-lock.json \
149 $SILO_USER@$SILO_HOST:$REMOTE_DIR/
150
151# Upload landing page
152echo -e "$GREEN-> Uploading landing page...$NC"
153scp -i $SSH_KEY -o StrictHostKeyChecking=no \
154 $SCRIPT_DIR/landing-page.html \
155 $SILO_USER@$SILO_HOST:$REMOTE_DIR/
156
157echo -e "$GREEN-> Installing dependencies & restarting...$NC"
158ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "
159 chown -R dp1feed:dp1feed $REMOTE_DIR
160 cd $REMOTE_DIR && npm install --production --silent 2>&1 | tail -1
161 systemctl restart dp1-feed
162 sleep 2
163 systemctl is-active dp1-feed
164"
165
166set STATUS $status
167if test $STATUS -eq 0
168 echo -e "$GREEN dp1-feed is running.$NC"
169
170 # Quick health check
171 sleep 1
172 ssh -i $SSH_KEY $SILO_USER@$SILO_HOST "curl -s http://localhost:8787/api/v1/health"
173 echo ""
174else
175 echo -e "$RED x dp1-feed failed to start. Check logs:$NC"
176 echo -e "$YELLOW ssh -i $SSH_KEY $SILO_USER@$SILO_HOST journalctl -u dp1-feed -n 30$NC"
177 exit 1
178end
179
180echo ""
181echo -e "$GREEN Done. dp1-feed deployed to $SILO_HOST:8787$NC"