Skip to content

jrtxio/racket-deployer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

6 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

racket-deployer

A lightweight, high-performance CI/CD webhook server written in Racket.

This project provides a professional self-hosting alternative for Obsidian Digital Garden users. It allows you to transition from Vercel to your own VPS, automating the deployment of your notes while keeping your infrastructure private and efficient.

โœจ Features

  • ๐Ÿš€ Self-Hosted Freedom: Full control over your deployment pipeline
  • ๐Ÿ“ Designed for Obsidian: Optimized for the "Obsidian Digital Garden" plugin workflow
  • โšก Asynchronous Builds: Responds to GitHub immediately while processing builds in background
  • ๐Ÿ”’ Concurrency Safety: Semaphore-based locking prevents simultaneous builds
  • ๐Ÿ” Security: HMAC-SHA256 signature verification for GitHub webhooks
  • ๐ŸŒ Flexible Deployment: Direct HTTP or Nginx reverse proxy modes
  • ๐Ÿ“ฆ Remote Deploy: Optional rsync-based deployment to separate web servers
  • ๐Ÿ’š Health Monitoring: Built-in /health endpoint for status checks
  • ๐ŸŽ“ Educational: A practical example of Racket's multithreading capabilities

๐Ÿ“ Architecture Options

Option 1: Direct HTTP Mode (Simple)

GitHub โ†’ HTTP Webhook โ†’ Racket (0.0.0.0:8080) โ†’ Build โ†’ Deploy

Pros: Simple setup, no Nginx required
Cons: No HTTPS, must disable SSL verification in GitHub

Option 2: Nginx Proxy Mode (Recommended)

GitHub โ†’ HTTPS Webhook โ†’ Nginx (443/8443) โ†’ Racket (127.0.0.1:8080) โ†’ Build โ†’ Deploy

Pros: Secure HTTPS, SSL verification enabled
Cons: Requires Nginx and SSL certificate setup

Option 3: Separated Build & Deploy (Production)

Build Server:
  GitHub โ†’ Webhook โ†’ Racket โ†’ Build โ†’ rsync

Web Server:
  Nginx โ†’ Static Files (synced via rsync)

Pros: Separation of concerns, scalable, secure
Cons: Requires two servers and SSH key setup

๐Ÿ›  Prerequisites

Build Server

  • Racket (v8.0+)
  • Node.js & npm (v22+ recommended)
  • OpenSSL
  • Git
  • rsync (if using remote deploy)
  • Nginx (optional, for HTTPS)

Web Server (if separated)

  • Nginx
  • rsync

๐Ÿ“ฆ Quick Start

1. Clone Repository

git clone https://github.com/yourusername/racket-deployer.git
cd racket-deployer

2. Configure

cp config.example.json config.json
nano config.json

Minimal Configuration (Direct HTTP):

{
  "github-secret": "your-strong-secret",
  "port": 8080,
  "listen-ip": "0.0.0.0",
  "repo-path": "/var/www/blog",
  "repo-url": "https://github.com/username/repo.git",
  "build-output": "/var/www/blog/dist"
}

Production Configuration (Nginx + Remote Deploy):

{
  "github-secret": "your-strong-secret",
  "port": 8080,
  "listen-ip": "127.0.0.1",
  "repo-path": "/var/www/blog",
  "repo-url": "https://github.com/username/repo.git",
  "build-output": "/var/www/blog/dist",
  "deploy": {
    "enabled": true,
    "remote-host": "user@web-server-ip",
    "remote-path": "/var/www/blog/dist",
    "ssh-key": "/home/user/.ssh/id_rsa",
    "rsync-options": "-avz --delete"
  }
}

3. Clone Your Blog Repository

sudo mkdir -p /var/www/blog
sudo chown -R $USER:$USER /var/www/blog
git clone https://github.com/username/your-blog.git /var/www/blog
cd /var/www/blog
npm install
npm run build  # Test build

4. Run

cd racket-deployer
racket main.rkt

5. Setup GitHub Webhook

For Direct HTTP Mode:

  • Payload URL: http://your-server-ip:8080/
  • Content type: application/json
  • Secret: Your github-secret
  • SSL verification: โŒ Disable

For Nginx HTTPS Mode:

  • Payload URL: https://webhook.your-domain.com:8443/
  • Content type: application/json
  • Secret: Your github-secret
  • SSL verification: โœ… Enable

๐Ÿ“‹ Configuration Reference

Option Description Default Required
github-secret GitHub webhook secret - Yes
port Server port 8080 Yes
listen-ip Listen address (0.0.0.0 or 127.0.0.1) 127.0.0.1 Yes
repo-path Local repository path - Yes
repo-url GitHub repository URL - Yes
build-output Build output directory - Yes
deploy.enabled Enable remote deployment false No
deploy.remote-host Remote server (user@host) - If deploy enabled
deploy.remote-path Remote directory path - If deploy enabled
deploy.ssh-key SSH private key path - If deploy enabled
deploy.rsync-options rsync command options -avz --delete No

Listen IP Options

Value Description Use Case
0.0.0.0 Listen on all interfaces Direct HTTP access, testing, internal networks
127.0.0.1 Listen on localhost only Production with Nginx reverse proxy

๐ŸŒ Nginx Setup (Optional)

For Non-Standard Port (e.g., 8443)

server {
    listen 8443 ssl http2;
    server_name webhook.your-domain.com;

    ssl_certificate /etc/letsencrypt/live/webhook.your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/webhook.your-domain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

Enable and test:

sudo ln -s /etc/nginx/sites-available/webhook /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

SSL Certificate

sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d webhook.your-domain.com

๐Ÿ” Remote Deployment Setup

1. Generate SSH Key (Build Server)

ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ""
cat ~/.ssh/id_rsa.pub

2. Add Public Key (Web Server)

# On web server
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
# Paste the public key, save
chmod 600 ~/.ssh/authorized_keys

3. Test Connection

# On build server
ssh -i ~/.ssh/id_rsa user@web-server-ip "echo 'SSH OK'"

4. Test rsync

rsync -avz --delete -e 'ssh -i ~/.ssh/id_rsa' \
  /var/www/blog/dist/ \
  user@web-server-ip:/var/www/blog/dist \
  --dry-run

๐Ÿ”ง Systemd Service

sudo nano /etc/systemd/system/blog-deploy.service
[Unit]
Description=Blog Deploy Webhook Server
After=network.target

[Service]
Type=simple
User=youruser
Group=youruser
WorkingDirectory=/home/youruser/racket-deployer
Environment="PATH=/usr/bin:/bin:/usr/local/bin"
ExecStart=/usr/bin/racket /home/youruser/racket-deployer/main.rkt
Restart=always
RestartSec=10
StandardOutput=append:/var/log/blog-deploy.log
StandardError=append:/var/log/blog-deploy-error.log

[Install]
WantedBy=multi-user.target

Start service:

sudo systemctl daemon-reload
sudo systemctl enable blog-deploy
sudo systemctl start blog-deploy
sudo systemctl status blog-deploy

๐Ÿ“ก API Endpoints

Endpoint Method Description
/ GET Service status
/health GET Build status and last build time
/ POST GitHub webhook receiver

Examples

# Basic status
curl http://localhost:8080
# Response:
# Blog Deploy Webhook
# Status: Running

# Health check
curl http://localhost:8080/health
# Response:
# Status: idle
# (or: Status: building / success / failed)
# Last build: 120 seconds ago

๐Ÿ” Troubleshooting

Service won't start

# Check logs
sudo journalctl -u blog-deploy -n 50

# Test manually
cd ~/racket-deployer
racket main.rkt

Webhook not triggered

# Check GitHub webhook deliveries
# Repository โ†’ Settings โ†’ Webhooks โ†’ Recent Deliveries

# Check signature
sudo journalctl -u blog-deploy -f
# Look for: โœ“ Signature verified

Build fails

# Manual build
cd /var/www/blog
npm run build

# Check disk space
df -h

# Check Node.js version
node --version

Remote deploy fails

# Test SSH
ssh -i ~/.ssh/id_rsa user@web-server "echo OK"

# Test rsync manually
rsync -avz -e 'ssh -i ~/.ssh/id_rsa' \
  /var/www/blog/dist/ \
  user@web-server:/var/www/blog/dist

# Check SSH key permissions
ls -la ~/.ssh/id_rsa  # Should be -rw-------
chmod 600 ~/.ssh/id_rsa

Proxy issues

If using HTTP proxy, disable it for localhost:

export no_proxy="localhost,127.0.0.1"

๐Ÿ” Security Best Practices

  1. Strong Secrets: Generate with openssl rand -hex 32
  2. SSH Keys: Use dedicated keys with proper permissions (600)
  3. Firewall: Only open necessary ports
  4. Nginx: Use HTTPS in production
  5. Updates: Keep dependencies updated

Recommended Port Configuration

Direct HTTP Mode:

  • Open: 8080 (webhook), 22 (SSH)

Nginx Proxy Mode:

  • Open: 8443 (webhook HTTPS), 22 (SSH)
  • Closed: 8080 (Racket, local only)

๐Ÿ“Š Deployment Comparison

Feature Direct HTTP Nginx Proxy Separated Deploy
Setup Complexity โญ Simple โญโญ Medium โญโญโญ Complex
HTTPS Support โŒ โœ… โœ…
Security โš ๏ธ Basic โœ… Good โœ… Excellent
SSL Verification โŒ โœ… โœ…
Scalability โญ โญโญ โญโญโญ
Recommended For Testing Small sites Production

๐Ÿค Contributing

Contributions welcome! Please feel free to submit a Pull Request.

๐Ÿ“ License

MIT License - free to use for personal or commercial purposes.

๐Ÿ™ Acknowledgments

๐Ÿ“ฎ Support


Happy deploying! ๐Ÿš€

About

A lightweight, high-performance CI/CD webhook server written in Racket.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages