Intro
I have a home server that I use for various personal projects and host open source services like jellyfin, linkding etc. I decided to develop a landing page for this server and in this post, I’ll share my experience and some notes on the development process.
The project is developed via React, Vite, and TypeScript. I have chosen React because well, I like and have some experience with it. I have never used Vite previously, but it has been quite fast to test and build the project and did not face any issues so far. I have also never used Typescript but I have been writing Python with types, thus wanted to give it a try for javascript as well.
Project is built and served via Nginx on my home server. I also wanted a Continuous Build setup, but Jenkins was too heavy for this small project, thus have a small Express.js app that listens to GitHub webhooks and triggers a build bash script which is run as a systemd service.
GitHub Project
Check out the project on GitHub: giraycoskun/server.giraycoskun.dev
Step 1: Development
The project development is set up via pnpm version 10.21.0.
Initialize project
pnpm create vite@latest my-app --template react
pnpm install
This sets up a basic React + Vite project with TypeScript support. The development server can be started with:
pnpm dev
Project Structure
The project follows a standard React application structure:
/src- Main application code/src/components- Reusable React components/src/pages- Page components/public- Static assetsvite.config.ts- Vite configuration
Step 2: How to Build via GitHub Webhooks
I have considered Jenkins for Continuous Deployment but it was too heavy and as the Nginx was on the host machine directly, and Jenkins either needed to be directly on host machine as well or else the container creates some overhead due to SSH connection.
I have decided on a simpler solution: A simple Express.js app (./src/server/webhook-server.ts) that is triggered by a GitHub Webhook, run as a systemd service.
Systemd Service
Create a systemd service file at /etc/systemd/system/webhook-server.service:
[Unit]
Description=GitHub Webhook Server
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/project
ExecStart=/usr/bin/node /path/to/webhook-server.js
Restart=always
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl enable webhook-server
sudo systemctl start webhook-server
Webhook Handler
The Express.js application listens for GitHub webhook events and triggers the build script:
const express = require('express');
const { exec } = require('child_process');
app.post('/webhook', (req, res) => {
// Verify webhook signature
// Execute build script
exec('./build.sh', (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error}`);
return;
}
console.log(`Build output: ${stdout}`);
});
res.status(200).send('Webhook received');
});
Step 3: How to Deploy in Nginx on Home Server
Here are the essential steps to deploy the built React application on Nginx:
Build the Project
pnpm build
This creates an optimized production build in the dist directory.
Nginx Configuration
Create an Nginx server block configuration file at /etc/nginx/sites-available/server.giraycoskun.dev:
server {
listen 80;
server_name server.giraycoskun.dev;
root /path/to/project/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/server.giraycoskun.dev /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
SSL/HTTPS with Let’s Encrypt
For HTTPS support, use Certbot:
sudo certbot --nginx -d server.giraycoskun.dev
This automatically updates the Nginx configuration to handle HTTPS and sets up automatic certificate renewal.
Conclusion
This setup provides a lightweight, automated deployment pipeline for a React application on a home server. The combination of GitHub webhooks, systemd services, and Nginx creates an efficient workflow without the overhead of heavier CI/CD solutions like Jenkins.
The entire process from code push to deployment is automated, making it easy to iterate and deploy changes quickly.