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):
sudo apt update
sudo apt install -y openjdk-21-jdk
java -version
javac -versionSet JAVA_HOME for tools that need it (Gradle, some IDEs on SSH sessions):
# 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:
# Single-file demo
javac Hello.java
java Hello
# Run packaged Spring Boot JAR
java -jar /opt/myapp/app.jarProduction: 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:
| Tool | Install hint | Docs |
|---|---|---|
| Maven | sudo apt install -y maven or SDKMAN | /docs/maven |
| Gradle | Wrapper preferred: ./gradlew in repo | /docs/gradle/04_linux_install_gradle |
Typical flow on a build machine:
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 testCopy 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:
cd ~/projects/my-frontend
git pull
npm ci
npm run buildRun API or SSR in dev:
npm run startPM2 keeps Node alive across crashes and reboots (common for hello_code-style deploys):
# 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 startupPM2 complements systemd—pick one standard per team. Nginx still fronts static files and reverse-proxies to Node or Java ports.
Git and Private Repositories
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):
git clone git@github.com:yourorg/your-repo.git
cd your-repo
git pull origin mainHTTPS with token is an alternative on locked-down networks.
Line Endings and File Modes
On Linux, Git tracks the executable bit:
# Ignore chmod-only changes on scripts
git config core.filemode falseWindows 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:
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:
git push- CI:
mvn packageornpm run build scp/rsyncartifact + tar if bundledsudo systemctl restart myapporpm2 restart my-apicurlhealth check (networking, scripts)
Environment Variables and Secrets
# 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 myappNever 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
# 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 -50Disk full breaks builds—check space before large npm ci or Maven downloads.
Mini Example: Fresh Ubuntu Dev Box
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.jarIn 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).