Initial commit: Add HomeBase application with Docker support, deployment scripts, and health check endpoint
Some checks failed
Deploy to BeePC / deploy (push) Has been cancelled
Some checks failed
Deploy to BeePC / deploy (push) Has been cancelled
This commit is contained in:
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.git/
|
||||
.github/
|
||||
node_modules/
|
||||
*.log
|
||||
README.md
|
||||
.gitignore
|
||||
47
.github/workflows/deploy.yml
vendored
Normal file
47
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Deploy to BeePC
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H beepc >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||
|
||||
- name: Deploy to server
|
||||
run: |
|
||||
ssh spencer@beepc "mkdir -p /home/spencer/homebase"
|
||||
rsync -avz --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude '.git' \
|
||||
--exclude '.github' \
|
||||
--exclude '*.log' \
|
||||
./ spencer@beepc:/home/spencer/homebase/
|
||||
|
||||
- name: Run Docker Compose
|
||||
run: |
|
||||
ssh spencer@beepc << 'ENDSSH'
|
||||
cd /home/spencer/homebase
|
||||
docker compose down 2>/dev/null || true
|
||||
docker compose up -d --build
|
||||
sleep 5
|
||||
docker compose ps
|
||||
docker compose logs --tail=20
|
||||
ENDSSH
|
||||
|
||||
- name: Verify deployment
|
||||
run: |
|
||||
sleep 10
|
||||
curl -f http://homebase.sketchferret.com/health || exit 1
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.env
|
||||
*.log
|
||||
.DS_Store
|
||||
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install --omit=dev
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
USER node
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
236
README.md
Normal file
236
README.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# HomeBase
|
||||
|
||||
Simple self-hosted Node.js Docker application with automated SSH deployment.
|
||||
|
||||
## Features
|
||||
|
||||
- 🚀 Simple Express.js server
|
||||
- 🐳 Docker containerized
|
||||
- 🔄 Automated deployment via SSH
|
||||
- ✅ Health check endpoint
|
||||
- 🔐 SSH key-based authentication
|
||||
|
||||
## Prerequisites
|
||||
|
||||
On your local machine:
|
||||
- Node.js (for local testing)
|
||||
- Docker (for local testing)
|
||||
- SSH access to beepc server
|
||||
|
||||
On the remote server (beepc):
|
||||
- Docker installed
|
||||
- Docker Compose installed
|
||||
- SSH access configured for user `spencer`
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Run locally
|
||||
npm start
|
||||
|
||||
# Visit http://localhost:3001
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
### Option 1: Manual Deployment (Windows)
|
||||
|
||||
```bash
|
||||
# Run the deployment script from project root
|
||||
.\scripts\deploy.bat
|
||||
```
|
||||
|
||||
### Option 2: Manual Deployment (Linux/Mac)
|
||||
|
||||
```bash
|
||||
# Make script executable
|
||||
chmod +x scripts/deploy.sh
|
||||
|
||||
# Run deployment
|
||||
bash scripts/deploy.sh
|
||||
```
|
||||
|
||||
### Option 3: Manual Deployment (PowerShell)
|
||||
|
||||
```powershell
|
||||
# Run the deployment script from project root
|
||||
.\scripts\deploy.ps1
|
||||
```
|
||||
|
||||
### Option 4: Automated Deployment (GitHub Actions)
|
||||
|
||||
1. Add your SSH private key to GitHub Secrets:
|
||||
- Go to your repository Settings > Secrets and variables > Actions
|
||||
- Add a new secret named `SSH_PRIVATE_KEY`
|
||||
- Paste your SSH private key content
|
||||
|
||||
2. Push to main branch:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
3. The app will automatically deploy to spencer@beepc
|
||||
|
||||
## SSH Setup
|
||||
|
||||
Ensure you have SSH key-based authentication set up:
|
||||
|
||||
```bash
|
||||
# Generate SSH key if you don't have one
|
||||
ssh-keygen -t ed25519 -C "your_email@example.com"
|
||||
|
||||
# Copy key to remote server
|
||||
ssh-copy-id spencer@beepc
|
||||
|
||||
# Test connection
|
||||
ssh spencer@beepc
|
||||
```
|
||||
|
||||
## Remote Server Setup
|
||||
|
||||
On beepc, ensure Docker is installed:
|
||||
|
||||
```bash
|
||||
# Install Docker (Ubuntu/Debian)
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
|
||||
# Add user to docker group
|
||||
sudo usermod -aG docker spencer
|
||||
|
||||
# Install Docker Compose
|
||||
sudo apt-get update
|
||||
sudo apt-get install docker-compose-plugin
|
||||
|
||||
# Logout and login again for group changes to take effect
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
- `GET /` - Main endpoint, returns app status
|
||||
- `GET /health` - Health check endpoint
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
HomeBase/
|
||||
├── scripts/
|
||||
│ ├── deploy.ps1 # PowerShell deployment script
|
||||
│ ├── deploy.sh # Bash deployment script
|
||||
│ └── deploy.bat # Windows batch deployment script
|
||||
├── .github/
|
||||
│ └── workflows/
|
||||
│ └── deploy.yml # GitHub Actions workflow
|
||||
├── .dockerignore # Docker ignore file
|
||||
├── .gitignore # Git ignore file
|
||||
├── Dockerfile # Docker configuration
|
||||
├── docker-compose.yml # Docker Compose configuration
|
||||
├── homebase.service # Systemd service file
|
||||
├── package.json # Node.js dependencies
|
||||
├── server.js # Express server
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Deployment Process
|
||||
|
||||
The deployment script does the following:
|
||||
|
||||
1. Creates remote directory if it doesn't exist
|
||||
2. Syncs files to remote server via rsync/scp
|
||||
3. Stops existing Docker container
|
||||
4. Builds new Docker image
|
||||
5. Starts new container
|
||||
6. Verifies container is running
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check logs on remote server
|
||||
|
||||
```bash
|
||||
ssh spencer@beepc
|
||||
cd /home/spencer/homebase
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
### Check container status
|
||||
|
||||
```bash
|
||||
ssh spencer@beepc "docker ps"
|
||||
```
|
||||
|
||||
### Restart container
|
||||
|
||||
```bash
|
||||
ssh spencer@beepc "cd /home/spencer/homebase && docker compose restart"
|
||||
```
|
||||
|
||||
### Remove and rebuild
|
||||
|
||||
```bash
|
||||
ssh spencer@beepc "cd /home/spencer/homebase && docker compose down && docker compose up -d --build"
|
||||
```
|
||||
|
||||
## Accessing the App
|
||||
|
||||
Once deployed, access the app at:
|
||||
- `http://homebase.sketchferret.com` (reverse proxied, no port needed)
|
||||
- `http://beepc:3001` (direct access from local network)
|
||||
- `http://localhost:3001` (direct access on the server)
|
||||
|
||||
**Note:** The app runs on port 3001 internally but is accessed via reverse proxy at the standard HTTP port.
|
||||
|
||||
## Auto-Start on Boot
|
||||
|
||||
The deployment script automatically sets up a systemd service that:
|
||||
- Starts the Docker container on server boot
|
||||
- Restarts the container if it crashes
|
||||
- Runs as the spencer user
|
||||
|
||||
To manually manage the service:
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
ssh spencer@beepc "sudo systemctl status homebase"
|
||||
|
||||
# Stop service
|
||||
ssh spencer@beepc "sudo systemctl stop homebase"
|
||||
|
||||
# Start service
|
||||
ssh spencer@beepc "sudo systemctl start homebase"
|
||||
|
||||
# Restart service
|
||||
ssh spencer@beepc "sudo systemctl restart homebase"
|
||||
|
||||
# Disable auto-start
|
||||
ssh spencer@beepc "sudo systemctl disable homebase"
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
You can customize settings by modifying [docker-compose.yml](docker-compose.yml):
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- PORT=3001 # Internal port (reverse proxy maps to standard HTTP)
|
||||
- DOMAIN=homebase.sketchferret.com # Your domain
|
||||
ports:
|
||||
- "3001:3001" # Port mapping for reverse proxy backend
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Uses SSH key authentication (no passwords)
|
||||
- Container runs as non-root user
|
||||
- Only production dependencies installed in Docker image
|
||||
- Health check endpoint for monitoring
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
11
docker-compose.yml
Normal file
11
docker-compose.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
container_name: homebase
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3001:3001"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- PORT=3001
|
||||
- DOMAIN=homebase.sketchferret.com
|
||||
16
homebase.service
Normal file
16
homebase.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=HomeBase Docker Application
|
||||
Requires=docker.service
|
||||
After=docker.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
WorkingDirectory=/home/spencer/homebase
|
||||
ExecStart=/usr/bin/docker compose up -d
|
||||
ExecStop=/usr/bin/docker compose down
|
||||
User=spencer
|
||||
Group=spencer
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
16
package.json
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "homebase",
|
||||
"version": "1.0.0",
|
||||
"description": "Simple self-hosted Node.js app",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"dev": "node server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2"
|
||||
}
|
||||
}
|
||||
30
scripts/deploy.bat
Normal file
30
scripts/deploy.bat
Normal file
@@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
REM Batch deployment script for HomeBase (Windows)
|
||||
REM Run this from the project root: scripts\deploy.bat
|
||||
|
||||
set REMOTE_USER=spencer
|
||||
set REMOTE_HOST=beepc
|
||||
set REMOTE_DIR=/home/spencer/homebase
|
||||
set APP_NAME=homebase
|
||||
|
||||
echo Starting deployment to %REMOTE_USER%@%REMOTE_HOST%...
|
||||
|
||||
REM Create remote directory if it doesn't exist
|
||||
echo Ensuring remote directory exists...
|
||||
ssh %REMOTE_USER%@%REMOTE_HOST% "mkdir -p %REMOTE_DIR%"
|
||||
|
||||
REM Sync files to remote server
|
||||
echo Syncing files to remote server...
|
||||
scp -r Dockerfile docker-compose.yml package.json server.js .dockerignore homebase.service %REMOTE_USER%@%REMOTE_HOST%:%REMOTE_DIR%/
|
||||
|
||||
REM Deploy on remote server
|
||||
echo Deploying application on remote server...
|
||||
ssh %REMOTE_USER%@%REMOTE_HOST% "cd %REMOTE_DIR% && docker compose down 2>nul & docker compose up -d --build && timeout /t 5 && docker ps | findstr homebase"
|
||||
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo Deployment successful!
|
||||
echo App should be available at http://homebase.sketchferret.com
|
||||
) else (
|
||||
echo Deployment failed!
|
||||
exit /b 1
|
||||
)
|
||||
82
scripts/deploy.ps1
Normal file
82
scripts/deploy.ps1
Normal file
@@ -0,0 +1,82 @@
|
||||
# PowerShell deployment script for HomeBase
|
||||
# Run this from the project root directory: .\scripts\deploy.ps1
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$REMOTE_USER = "spencer"
|
||||
$REMOTE_HOST = "beepc"
|
||||
$REMOTE_DIR = "/home/spencer/homebase"
|
||||
|
||||
Write-Host "🚀 Starting deployment to $REMOTE_USER@$REMOTE_HOST..." -ForegroundColor Cyan
|
||||
|
||||
# Create remote directory
|
||||
Write-Host "📁 Ensuring remote directory exists..." -ForegroundColor Yellow
|
||||
ssh $REMOTE_USER@$REMOTE_HOST "mkdir -p $REMOTE_DIR"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ Failed to create remote directory" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Copy files to remote server
|
||||
Write-Host "📦 Copying files to remote server..." -ForegroundColor Yellow
|
||||
$files = @(
|
||||
"Dockerfile",
|
||||
"docker-compose.yml",
|
||||
"package.json",
|
||||
"server.js",
|
||||
".dockerignore",
|
||||
"homebase.service"
|
||||
)
|
||||
|
||||
foreach ($file in $files) {
|
||||
Write-Host " Copying $file..." -ForegroundColor Gray
|
||||
scp $file "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "❌ Failed to copy $file" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Deploy and start the application
|
||||
Write-Host "🐳 Deploying application..." -ForegroundColor Yellow
|
||||
$deployScript = @'
|
||||
cd /home/spencer/homebase
|
||||
|
||||
echo "⏹️ Stopping existing container..."
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
echo "🔨 Building and starting container..."
|
||||
docker compose up -d --build
|
||||
|
||||
echo "⚙️ Setting up systemd service..."
|
||||
sudo cp homebase.service /etc/systemd/system/homebase.service 2>/dev/null || echo "Note: Could not set up systemd service (may need manual setup)"
|
||||
sudo systemctl daemon-reload 2>/dev/null || true
|
||||
sudo systemctl enable homebase.service 2>/dev/null || true
|
||||
sudo systemctl start homebase.service 2>/dev/null || true
|
||||
|
||||
echo "⏳ Waiting for container to start..."
|
||||
sleep 5
|
||||
|
||||
echo "✅ Checking container status..."
|
||||
docker compose ps
|
||||
docker compose logs --tail=20
|
||||
|
||||
if docker ps | grep -q homebase; then
|
||||
echo "✅ Container is running!"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Container failed to start!"
|
||||
exit 1
|
||||
fi
|
||||
'@
|
||||
|
||||
ssh $REMOTE_USER@$REMOTE_HOST $deployScript
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "✅ Deployment successful!" -ForegroundColor Green
|
||||
Write-Host "🌐 App should be available at http://homebase.sketchferret.com" -ForegroundColor Cyan
|
||||
} else {
|
||||
Write-Host "❌ Deployment failed!" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
68
scripts/deploy.sh
Normal file
68
scripts/deploy.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Bash deployment script for HomeBase
|
||||
# Run this from the project root: bash scripts/deploy.sh
|
||||
|
||||
# Configuration
|
||||
REMOTE_USER="spencer"
|
||||
REMOTE_HOST="beepc"
|
||||
REMOTE_DIR="/home/spencer/homebase"
|
||||
APP_NAME="homebase"
|
||||
|
||||
echo "🚀 Starting deployment to ${REMOTE_USER}@${REMOTE_HOST}..."
|
||||
|
||||
# Create remote directory if it doesn't exist
|
||||
echo "📁 Ensuring remote directory exists..."
|
||||
ssh ${REMOTE_USER}@${REMOTE_HOST} "mkdir -p ${REMOTE_DIR}"
|
||||
|
||||
# Sync files to remote server (excluding unnecessary files)
|
||||
echo "📦 Syncing files to remote server..."
|
||||
rsync -avz --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude '.git' \
|
||||
--exclude '.github' \
|
||||
--exclude '*.log' \
|
||||
./ ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/
|
||||
|
||||
# Deploy on remote server
|
||||
echo "🐳 Deploying application on remote server..."
|
||||
ssh ${REMOTE_USER}@${REMOTE_HOST} << 'ENDSSH'
|
||||
cd /home/spencer/homebase
|
||||
|
||||
# Stop and remove existing container
|
||||
echo "⏹️ Stopping existing container..."
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# Build and start new container
|
||||
echo "🔨 Building and starting container..."
|
||||
docker compose up -d --build
|
||||
|
||||
# Set up systemd service for auto-start on boot
|
||||
echo "⚙️ Setting up systemd service..."
|
||||
sudo cp homebase.service /etc/systemd/system/homebase.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable homebase.service
|
||||
sudo systemctl start homebase.service 2>/dev/null || true
|
||||
|
||||
# Wait for container to be healthy
|
||||
echo "⏳ Waiting for container to start..."
|
||||
sleep 5
|
||||
|
||||
# Check if container is running
|
||||
if docker ps | grep -q homebase; then
|
||||
echo "✅ Container is running!"
|
||||
docker compose logs --tail=20
|
||||
else
|
||||
echo "❌ Container failed to start!"
|
||||
docker compose logs --tail=50
|
||||
exit 1
|
||||
fi
|
||||
ENDSSH
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Deployment successful!"
|
||||
echo "🌐 App should be available at http://homebase.sketchferret.com"
|
||||
else
|
||||
echo "❌ Deployment failed!"
|
||||
exit 1
|
||||
fi
|
||||
25
server.js
Normal file
25
server.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
const DOMAIN = process.env.DOMAIN || 'homebase.sketchferret.com';
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.json({
|
||||
message: 'HomeBase is running!',
|
||||
domain: DOMAIN,
|
||||
timestamp: new Date().toISOString(),
|
||||
version: '1.0.0'
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({ status: 'healthy' });
|
||||
});
|
||||
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
console.log(`Domain: ${DOMAIN}`);
|
||||
console.log(`Visit: http://${DOMAIN}`);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user