This is a draft post and may be incomplete or subject to change.

Back to Blog
Giray Coskun
Giray Coskun
4 min read
Develop Server Landing Page
Develop Server Landing Page — photo by Giray Coskun

Develop Server Landing Page

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 assets
  • vite.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.

Tags: development, homeserver, react
Photo credits: Giray Coskun • 15 Dec 2024