Add Alpine Linux service setup and CI/CD deployment
- 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:
parent
33019c116b
commit
e2216c17e8
41
.github/workflows/build.yml
vendored
41
.github/workflows/build.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Build
|
name: Build and Deploy
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@ -9,6 +9,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: linux_amd64
|
runs-on: linux_amd64
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
@ -16,13 +17,43 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
timeout-minutes: 5
|
||||||
|
|
||||||
- name: Build Front End
|
- name: Build Front End
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
timeout-minutes: 10
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: '--max-old-space-size=4096'
|
NODE_OPTIONS: '--max-old-space-size=4096'
|
||||||
|
|
||||||
- name: Restart Server
|
- name: Stop Service
|
||||||
run: |
|
run: |
|
||||||
# Start server in background with nohup
|
sudo rc-service immersive stop || true
|
||||||
nohup npm run start > /tmp/immersive.log 2>&1 &
|
|
||||||
|
- 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
1
.gitignore
vendored
@ -26,3 +26,4 @@ dist-ssr
|
|||||||
# Local Netlify folder
|
# Local Netlify folder
|
||||||
.netlify
|
.netlify
|
||||||
/data/
|
/data/
|
||||||
|
/.env.production
|
||||||
|
|||||||
280
ALPINE_SERVICE.md
Normal file
280
ALPINE_SERVICE.md
Normal 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
|
||||||
|
```
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "immersive",
|
"name": "immersive",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.8-43",
|
"version": "0.0.8-44",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
19
start.sh
Normal file
19
start.sh
Normal 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"
|
||||||
Loading…
Reference in New Issue
Block a user