Developer Workflow on Linux

Introduction

Linux is where many teams build, test, and run Java and Node backends. This chapter ties together install paths from other hello_code tracks: JDK, Maven/Gradle, Node, Git, running JARs, and process supervision—so your laptop, CI runner, and VPS share the same habits.

Prerequisites

Java on Linux

Install OpenJDK 21 with apt (details in Java Linux install):

bash
sudo apt update
sudo apt install -y openjdk-21-jdk
java -version
javac -version

Set JAVA_HOME for tools that need it (Gradle, some IDEs on SSH sessions):

bash
# Typical path on Ubuntu
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export PATH="$JAVA_HOME/bin:$PATH"

Add those lines to ~/.bashrc if you use them every login.

Compile and run without an IDE:

bash
# Single-file demo
javac Hello.java
java Hello
 
# Run packaged Spring Boot JAR
java -jar /opt/myapp/app.jar

Production: use a systemd unit instead of leaving java -jar in an SSH session.

Maven and Gradle on the Server

Install CLI tools when CI or a small VPS builds from source:

ToolInstall hintDocs
Mavensudo apt install -y maven or SDKMAN/docs/maven
GradleWrapper preferred: ./gradlew in repo/docs/gradle/04_linux_install_gradle

Typical flow on a build machine:

bash
git clone git@github.com:yourorg/your-backend.git
cd your-backend
 
# Maven
mvn -q clean package -DskipTests
 
# Or Gradle wrapper (no global Gradle required)
./gradlew build -x test

Copy target/*.jar or build/libs/*.jar to the app server with scp/rsync, then restart the service.

Tip

Build on CI, Deploy Artifact

Many teams never compile on production—only upload the JAR. Linux skills still matter for logs, disk, and systemctl.

Node.js on Linux

Follow Install Node.js on Linux for LTS (nvm, NodeSource, or distro packages).

Project workflow:

bash
cd ~/projects/my-frontend
git pull
npm ci
npm run build

Run API or SSR in dev:

bash
npm run start

PM2 keeps Node alive across crashes and reboots (common for hello_code-style deploys):

bash
# Install globally
sudo npm install -g pm2
 
# Start app
cd /srv/my-api
pm2 start npm --name my-api -- start
 
# Save process list for resurrect after reboot
pm2 save
pm2 startup

PM2 complements systemd—pick one standard per team. Nginx still fronts static files and reverse-proxies to Node or Java ports.

Git and Private Repositories

bash
sudo apt install -y git
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

Clone over SSH (key from learning environment):

bash
git clone git@github.com:yourorg/your-repo.git
cd your-repo
git pull origin main

HTTPS with token is an alternative on locked-down networks.

Line Endings and File Modes

On Linux, Git tracks the executable bit:

bash
# Ignore chmod-only changes on scripts
git config core.filemode false

Windows developers should use core.autocrlf on Windows hosts; on Linux servers, checkout is usually LF—avoid editing production files on Windows Notepad.

Mark deploy scripts executable in repo:

bash
chmod +x scripts/deploy.sh
git add scripts/deploy.sh
git commit -m "Add deploy script"

End-to-End Workflow Sketch

Developer laptop (WSL or VM) → push to Git → CI (Linux runner) builds → artifact to VPS:

  1. git push
  2. CI: mvn package or npm run build
  3. scp / rsync artifact + tar if bundled
  4. sudo systemctl restart myapp or pm2 restart my-api
  5. curl health check (networking, scripts)

Environment Variables and Secrets

bash
# Per-session
export SPRING_PROFILES_ACTIVE=prod
export DATABASE_URL='jdbc:mysql://127.0.0.1:3306/app'
 
# systemd: Environment= in unit file or EnvironmentFile=
sudo systemctl edit myapp

Never commit .env with passwords—use server-side files with chmod 600. JDBC URL patterns appear in /docs/jdbc when you connect apps to MySQL.

Logs and Debugging Builds

bash
# Tail application log
tail -f /opt/myapp/logs/spring.log
 
# JVM out-of-memory — check dmesg and journal
sudo journalctl -u myapp -n 200 --no-pager
 
# Maven verbose once
mvn -X clean package 2>&1 | tail -50

Disk full breaks builds—check space before large npm ci or Maven downloads.

Mini Example: Fresh Ubuntu Dev Box

bash
sudo apt update
sudo apt install -y openjdk-21-jdk git curl maven
git clone git@github.com:yourorg/demo.git
cd demo
./mvnw -q package || mvn -q package
java -jar target/demo-0.0.1-SNAPSHOT.jar

In another terminal: curl -s http://127.0.0.1:8080/ | head.

FAQ

Same code works locally but not on server?

Check Java/Node versions, env vars, firewall, and listening address (0.0.0.0 vs 127.0.0.1).

mvn: command not found but project has wrapper?

Use ./mvnw from repo root.

Gradle wrapper permission denied?

chmod +x gradlew

Node EACCES on global npm install?

Avoid sudo npm install -g; use nvm or a user prefix.

Build caches filling disk?

Remove old ~/.m2/repository artifacts carefully, or ~/.gradle/caches—only if you understand re-download cost.

What comes next?

Docker introduction (upcoming).