Add Alpine Linux service setup and CI/CD deployment
Some checks failed
Build and Deploy / build (push) Failing after 1m44s
Node.js CI / build (push) Has been cancelled

- Add ALPINE_SERVICE.md with full setup instructions
- Add start.sh script for OpenRC service
- Update build.yml for deployment to /opt/immersive
- Configure proper permissions for immersive user
- Add Gitea runner setup instructions with sudo config
- Add .env.production to gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Michael Mainguy 2025-12-30 09:21:08 -06:00
parent 33019c116b
commit e2216c17e8
5 changed files with 337 additions and 6 deletions

View File

@ -1,4 +1,4 @@
name: Build
name: Build and Deploy
on:
push:
@ -9,6 +9,7 @@ on:
jobs:
build:
runs-on: linux_amd64
timeout-minutes: 15
steps:
- name: Checkout code
@ -16,13 +17,43 @@ jobs:
- name: Install dependencies
run: npm ci
timeout-minutes: 5
- name: Build Front End
run: npm run build
timeout-minutes: 10
env:
NODE_OPTIONS: '--max-old-space-size=4096'
- name: Restart Server
run: |
# Start server in background with nohup
nohup npm run start > /tmp/immersive.log 2>&1 &
- name: Stop Service
run: |
sudo rc-service immersive stop || true
- name: Deploy to /opt/immersive
run: |
# Remove old deployment (keep data directory if it exists)
rm -rf /opt/immersive.old
[ -d /opt/immersive ] && mv /opt/immersive /opt/immersive.old
# Copy built files to target
mkdir -p /opt/immersive
cp -r . /opt/immersive/
# Remove unnecessary directories
rm -rf /opt/immersive/.git /opt/immersive/.github
# Restore data directory from old deployment if it existed
[ -d /opt/immersive.old/data ] && mv /opt/immersive.old/data /opt/immersive/
# Clean up old deployment
rm -rf /opt/immersive.old
# Set permissions on start.sh
chmod +x /opt/immersive/start.sh
# Set ownership to immersive user
sudo chown -R immersive:immersive /opt/immersive
- name: Start Service
run: |
sudo rc-service immersive start

1
.gitignore vendored
View File

@ -26,3 +26,4 @@ dist-ssr
# Local Netlify folder
.netlify
/data/
/.env.production

280
ALPINE_SERVICE.md Normal file
View File

@ -0,0 +1,280 @@
# Alpine Linux Service Setup
This guide covers installing and running Immersive as a service on Alpine Linux using OpenRC.
## Prerequisites
```bash
# Update packages
apk update
# Install Node.js 18+ and npm
apk add nodejs npm
# Install build dependencies (required for native modules like leveldown)
apk add python3 make g++ git
# Verify Node version (must be >= 18)
node --version
```
## Create Service User
Create a dedicated user to run the service (security best practice):
```bash
# Create immersive group and user (no login shell, no home directory)
addgroup -S immersive
adduser -S -G immersive -H -s /sbin/nologin immersive
# Create directories with proper ownership
mkdir -p /opt/immersive
mkdir -p /var/log/immersive
mkdir -p /var/run/immersive
chown -R immersive:immersive /opt/immersive
chown -R immersive:immersive /var/log/immersive
chown -R immersive:immersive /var/run/immersive
```
## Installation
```bash
# Create application directory
mkdir -p /opt/immersive
cd /opt/immersive
# Clone or copy the application
git clone <your-repo-url> .
# OR copy files manually
# Install dependencies
npm ci --production=false
# Build the application
NODE_OPTIONS='--max-old-space-size=4096' npm run build
# Copy Havok physics WASM (if not already done by build)
npm run havok
# Create data directory for PouchDB
mkdir -p /opt/immersive/data
# Set ownership to immersive user
chown -R immersive:immersive /opt/immersive
```
## Start Script
The `start.sh` script is included in the repository. After deployment, ensure it's executable:
```bash
chmod +x /opt/immersive/start.sh
```
The script sets up the environment and starts the Node.js server, logging output to `/var/log/immersive/`.
## OpenRC Service
Create `/etc/init.d/immersive`:
```bash
#!/sbin/openrc-run
name="immersive"
description="Immersive WebXR Diagramming Application"
command="/opt/immersive/start.sh"
command_user="immersive:immersive"
command_background="yes"
pidfile="/var/run/immersive/immersive.pid"
directory="/opt/immersive"
output_log="/var/log/immersive/app.log"
error_log="/var/log/immersive/error.log"
depend() {
need net
after firewall
}
start_pre() {
checkpath --directory --owner immersive:immersive --mode 0755 /var/log/immersive
checkpath --directory --owner immersive:immersive --mode 0755 /var/run/immersive
checkpath --file --owner immersive:immersive --mode 0644 /var/log/immersive/app.log
checkpath --file --owner immersive:immersive --mode 0644 /var/log/immersive/error.log
}
```
Make it executable and enable:
```bash
chmod +x /etc/init.d/immersive
rc-update add immersive default
```
## Service Management
```bash
# Start the service
rc-service immersive start
# Stop the service
rc-service immersive stop
# Restart the service
rc-service immersive restart
# Check status
rc-service immersive status
# View logs
tail -f /var/log/immersive/app.log
tail -f /var/log/immersive/error.log
```
## Log Rotation
Create `/etc/logrotate.d/immersive`:
```
/var/log/immersive/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 immersive immersive
postrotate
rc-service immersive restart > /dev/null 2>&1 || true
endscript
}
```
Install logrotate if not present:
```bash
apk add logrotate
```
## Environment Variables
Create `/opt/immersive/.env.production` for production settings:
```bash
# Server
NODE_ENV=production
PORT=3001
# Auth0 (if using authentication)
# VITE_AUTH0_DOMAIN=your-domain.auth0.com
# VITE_AUTH0_CLIENT_ID=your-client-id
# Database sync endpoint (optional)
# VITE_SYNCDB_ENDPOINT=https://your-couchdb-server.com
```
## Firewall (if using iptables)
```bash
# Allow port 3001
iptables -A INPUT -p tcp --dport 3001 -j ACCEPT
# Save rules
rc-service iptables save
```
## Reverse Proxy (Optional)
If using nginx as a reverse proxy:
```bash
apk add nginx
```
Create `/etc/nginx/http.d/immersive.conf`:
```nginx
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable and start nginx:
```bash
rc-update add nginx default
rc-service nginx start
```
## Gitea CI/CD Runner (Optional)
If using a Gitea Actions runner to deploy, grant the runner user write access to `/opt/immersive`:
```bash
# Add gitea-runner to immersive group
adduser gitea-runner immersive
# Set group write permissions on /opt/immersive
chmod -R g+w /opt/immersive
# Ensure new files inherit group ownership
chmod g+s /opt/immersive
# Allow runner to manage the service
# Add to /etc/sudoers.d/gitea-runner:
echo 'gitea-runner ALL=(ALL) NOPASSWD: /sbin/rc-service immersive *' > /etc/sudoers.d/gitea-runner
echo 'gitea-runner ALL=(ALL) NOPASSWD: /bin/chown -R immersive\:immersive /opt/immersive' >> /etc/sudoers.d/gitea-runner
chmod 440 /etc/sudoers.d/gitea-runner
```
The GitHub Actions workflow in `.github/workflows/build.yml` will handle deployment automatically on push to main.
## Troubleshooting
**Service fails to start:**
```bash
# Check logs
cat /var/log/immersive/error.log
# Run manually as immersive user to see errors
su -s /bin/sh immersive -c "cd /opt/immersive && NODE_ENV=production node server.js"
```
**Native module errors (leveldown):**
```bash
# Rebuild native modules
cd /opt/immersive
npm rebuild leveldown
```
**Permission issues:**
```bash
# Ensure proper ownership (must be immersive user)
chown -R immersive:immersive /opt/immersive
chown -R immersive:immersive /var/log/immersive
chown -R immersive:immersive /var/run/immersive
chmod -R 755 /opt/immersive
```
**Port already in use:**
```bash
# Find process using port 3001
lsof -i :3001
# Or
netstat -tlnp | grep 3001
```

View File

@ -1,7 +1,7 @@
{
"name": "immersive",
"private": true,
"version": "0.0.8-43",
"version": "0.0.8-44",
"type": "module",
"license": "MIT",
"engines": {

19
start.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/sh
# Immersive start script for Alpine Linux
APP_DIR="/opt/immersive"
LOG_DIR="/var/log/immersive"
PID_FILE="/var/run/immersive.pid"
cd "$APP_DIR"
# Environment
export NODE_ENV=production
export NODE_OPTIONS="--max-old-space-size=2048"
# Optional: Set port (default 3001)
# export PORT=3001
# Start the server
exec node server.js >> "$LOG_DIR/app.log" 2>> "$LOG_DIR/error.log"