# Auto-Restart Spring Boot App If Port is Down Using Systemd Timer & Bash Script

In production environments, keeping your Spring Boot app up and running is crucial. One lightweight strategy is to **monitor the port** and **redeploy the app if it's down** — using a **systemd timer** and a custom shell script.

Here’s how we built a **self-healing deployment script** on an Ubuntu server using `systemd`, `nc`, and `nohup`.

---

## ✅ Problem Statement

We had a Spring Boot app running on port `8080`. Occasionally, it crashed due to memory issues or deployment glitches. We wanted to:

* **Detect if port 8080 is down**
    
* **Trigger a redeploy**
    
* **Run this check every 5 minutes**
    
* Ensure the redeployed app **is not killed** by systemd after the monitor script exits
    

---

## 🧩 Solution Architecture

1. [`monitor-port.sh`](http://monitor-port.sh) — Checks if port 8080 is up; if not, runs deploy script
    
2. `deploy-genentech` — Kills old process and restarts the Spring Boot app
    
3. `systemd service` — Runs the monitor script
    
4. `systemd timer` — Executes the service every 5 minutes
    

---

## 🧪 1. The Port Monitoring Script: `/usr/local/bin/`[`monitor-port.sh`](http://monitor-port.sh)

```bash
#!/bin/bash

APP_PORT=8080
DEPLOY_COMMAND="/usr/local/bin/deploy-genentech"
LOG_FILE="/home/azureuser/logs/monitor-port.log"

[ ! -f "$LOG_FILE" ] && sudo touch "$LOG_FILE" && sudo chown $USER:$USER "$LOG_FILE"

log() {
  echo "$(date): $1" >> "$LOG_FILE"
}

if ! nc -z localhost $APP_PORT; then
  log "Port $APP_PORT is down. Executing deploy script..."
  nohup $DEPLOY_COMMAND >> $LOG_FILE 2>&1 &
else
  log "Port $APP_PORT is up. No action needed."
fi

exit 0
```

---

## 🚀 2. The Deploy Script: `/usr/local/bin/deploy-genentech`

```bash
#!/bin/bash

APP_DIR="/home/azureuser/projects/investmentproviderbackend"
JAR_PATH="$APP_DIR/base_service/target/base-service-*.jar"
LOG_DIR="/home/azureuser/logs"
LOG_FILE="$LOG_DIR/deploy-debug.log"
APP_PORT=8080
JAVA_BIN="/usr/bin/java"

echo "========== $(date): Starting deploy-genentech ==========" >> "$LOG_FILE"

fuser -k ${APP_PORT}/tcp || echo "$(date): Port $APP_PORT not in use." >> "$LOG_FILE"

cd "$APP_DIR" || { echo "$(date): ❌ Failed to cd into $APP_DIR" >> "$LOG_FILE"; exit 1; }

mkdir -p "$LOG_DIR"

APP_JAR=$(ls -t $JAR_PATH 2>/dev/null | head -n 1)

if [[ -z "$APP_JAR" ]]; then
  echo "$(date): ❌ No JAR found." >> "$LOG_FILE"
  exit 1
fi

nohup "$JAVA_BIN" -jar -Dspring.profiles.active=prod "$APP_JAR" > "$LOG_DIR/app.log" 2>&1 &

# Wait until the app binds to port
for i in {1..20}; do
  sleep 1
  if nc -z localhost $APP_PORT; then
    echo "$(date): ✅ App is up" >> "$LOG_FILE"
    exit 0
  fi
done

echo "$(date): ❌ App failed to start" >> "$LOG_FILE"
exit 1
```

---

## ⚙️ 3. `monitor-port.service`: `/etc/systemd/system/monitor-port.service`

```ini
[Unit]
Description=Monitor Port 8080 and Restart App If Down
After=network.target

[Service]
Type=oneshot
User=azureuser
ExecStart=/usr/local/bin/monitor-port.sh
KillMode=process

[Install]
WantedBy=multi-user.target
```

> `KillMode=process` is **crucial** — it prevents systemd from killing the Java app after [`monitor-port.sh`](http://monitor-port.sh) exits.

---

## ⏱️ 4. `monitor-port.timer`: `/etc/systemd/system/monitor-port.timer`

```ini
[Unit]
Description=Run monitor-port.sh every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=monitor-port.service

[Install]
WantedBy=timers.target
```

---

## 🔄 Enable & Reload Systemd

```bash
sudo chmod +x /usr/local/bin/monitor-port.sh /usr/local/bin/deploy-genentech
sudo systemctl daemon-reload
sudo systemctl enable --now monitor-port.timer
```

You can verify with:

```bash
systemctl list-timers --all | grep monitor-port
```

---

## ✅ Result

* App automatically restarts if it crashes
    
* Port 8080 is checked every 5 minutes
    
* Minimal dependencies — no Docker or Kubernetes required
    
* Easy to extend with alerts, retries, or metrics
    

---

## 🧠 Pro Tip

For production, consider:

* Moving the app to a proper `systemd` service like `myapp.service`
    
* Adding log rotation with `logrotate`
    
* Sending downtime alerts via Slack, Email, or PagerDuty
