- 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>
281 lines
6.0 KiB
Markdown
281 lines
6.0 KiB
Markdown
# 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
|
|
```
|