Skip to main content

Getting Started

This guide walks you through building and running Glass Box locally.

Prerequisites

  • Java 25+Download from Oracle
  • Maven — Included via the Maven Wrapper (./mvnw), no separate install needed
  • Node.js 20+Download from nodejs.org (for frontend and docs)
  • Git — For cloning the repository
  • Docker (optional) — For containerized production builds

Installation

1. Clone the Repository

git clone https://github.com/z10n-dev/BuildYourOwnWebserver.git
cd BuildYourOwnWebserver

2. Build the Backend

cd backend
./mvnw clean package

This compiles the Java source code and creates an executable uber-JAR using the Maven Shade plugin.

3. Build the Frontend

cd ../frontend
npm install
npm run build

Creates an optimized static export in the out/ directory.

4. Build the Documentation

cd ../docs
npm install
npm run build

Creates the static documentation site in build/.

Running the Server

Development Mode

There are two options for development:

Option 1: Run Backend and Frontend Separately

Pros: Frontend reloads automatically on changes. Cons: Frontend runs on a different port and cannot communicate with the backend API.

# Terminal 1 — Backend
cd backend
./mvnw exec:java -Dexec.mainClass=com.ns.webserver.Main dev

# Terminal 2 — Frontend
cd frontend
npm run dev

# Terminal 3 — Documentation
cd docs
npm start
ServiceURL
Backendhttp://localhost:8080
Frontendhttp://localhost:3000
Documentationhttp://localhost:3001

Option 2: Build Frontend First, Then Run Backend

Pros: Behaves like production — backend serves the frontend assets directly. Cons: No hot-reload; you must rebuild the frontend after every change.

cd frontend && npm run build
cd ../docs && npm run build
cd ../backend
./mvnw exec:java -Dexec.mainClass=com.ns.webserver.Main dev

The server will serve both the frontend and API at http://localhost:8080.

Production Mode (Docker)

# Build everything
cd frontend && npm run build
cd ../docs && npm run build
cd ../backend && ./mvnw clean package

# Build and run the Docker image
cd ..
docker build -t glassbox .
docker run -p 8080:8080 glassbox

The server starts with the prod configuration profile by default.

Configuration Profiles

The server loads a YAML config file based on the environment argument:

# Loads config/config.dev.yaml
./mvnw exec:java -Dexec.mainClass=com.ns.webserver.Main dev

# Loads config/config.prod.yaml (default when no argument is given)
./mvnw exec:java -Dexec.mainClass=com.ns.webserver.Main prod

See Server Configuration for details on configuration options.

Verify It Works

Once the server is running, test the endpoints:

# Static page
curl http://localhost:8080/

# Hello World handler
curl http://localhost:8080/hello

# ToDo API — list all
curl http://localhost:8080/api/todos

# ToDo API — create one
curl -X POST http://localhost:8080/api/todos \
-H "Content-Type: application/json" \
-d '{"title": "Learn HTTP", "completed": false}'

# SSE stream (stays open, Ctrl+C to stop)
curl -N http://localhost:8080/api/sse

CI/CD

You can automate building and deploying with a CI pipeline. Below is an example using GitHub Actions:

Example: GitHub Actions Pipeline
name: Build and Push Docker Image

on:
push:
branches: [ "main" ]

env:
REGISTRY: ghcr.io

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Java 25
uses: actions/setup-java@v4
with:
java-version: '25'
distribution: 'temurin'
cache: 'maven'

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: 'frontend/package-lock.json'

- name: Install frontend dependencies
working-directory: ./frontend
run: npm ci

- name: Build Next.js frontend
working-directory: ./frontend
run: npm run build

- name: Copy static files to Java resources
run: |
mkdir -p backend/src/main/resources/static/glassbox
rm -rf backend/src/main/resources/static/glassbox/*
cp -r frontend/out/* backend/src/main/resources/static/glassbox/

- name: Convert repository name to lowercase
run: echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> ${GITHUB_ENV}

- name: Build Java application
working-directory: ./backend
run: ./mvnw clean package -DskipTests

- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest