How to Monitor Your Java/Spring Boot App Uptime (Free, Multi-Region)
Your Spring Boot app is running in production — but is it actually up? The framework gives you Spring Actuator out of the box, but no one is watching the /actuator/health endpoint unless you set up external monitoring. One silent 503 at 3 AM can cost you users and revenue before anyone wakes up.
By the end of this guide you'll have external uptime monitoring, multi-region checks, heartbeat monitoring for your scheduled tasks, and a public status page — all running on the free tier.
Why Spring Boot apps still go dark
Spring Boot apps have two failure modes that fly under the radar:
Endpoint failures — your API starts returning 500s, the connection pool is exhausted, or a bad deploy breaks a route. Your health endpoint might still return UP while individual APIs are broken.
Silent @Scheduled task failures — a @Scheduled method throws an unchecked exception. Spring catches it, logs a line, and keeps going. Your nightly data sync just stopped running. Nobody knows.
Both are solvable with one external monitoring tool actively checking from outside your infrastructure.
Step 1: Add Spring Actuator and expose the health endpoint
Add the Actuator dependency to your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Or with Gradle in build.gradle:
implementation 'org.springframework.boot:spring-boot-starter-actuator'
By default, only /actuator/health is exposed over HTTP. That's exactly what you need. The endpoint returns:
{
"status": "UP"
}
To expose component-level details (database, disk space, custom checks), add this to application.properties:
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=health
Now the response shows which components are healthy:
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "PostgreSQL",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 499963174912,
"free": 423123456789,
"threshold": 10485760
}
}
}
}
When the database is down, db.status becomes DOWN and the top-level status becomes DOWN with HTTP 503 — exactly the signal your monitoring tool needs.
Step 2: Write a custom health indicator
For dependencies that Actuator doesn't cover automatically, implement HealthIndicator:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {
private final ExternalApiClient apiClient;
public ExternalApiHealthIndicator(ExternalApiClient apiClient) {
this.apiClient = apiClient;
}
@Override
public Health health() {
try {
boolean reachable = apiClient.ping();
if (reachable) {
return Health.up().withDetail("external-api", "reachable").build();
}
return Health.down().withDetail("external-api", "unreachable").build();
} catch (Exception e) {
return Health.down(e).build();
}
}
}
This component is automatically picked up and included in the /actuator/health response.
Step 3: Set up external monitoring with Vigilmon
With /actuator/health live, point Vigilmon at it:
- Sign up at vigilmon.online — free tier, no credit card
- Click New Monitor → HTTP
- Enter
https://yourdomain.com/actuator/health - Set check interval (5 minutes on free tier)
- Save
Vigilmon probes from multiple regions. If it gets a non-2xx response or a timeout, it opens an incident and alerts you immediately — before your users notice.
Add multiple monitors per service:
| Endpoint | What it catches |
|---|---|
| /actuator/health | Database down, disk full, custom checks |
| /api/v1/ping | API layer breakage |
| / | Frontend serving broken |
Step 4: Heartbeat monitoring for @Scheduled tasks
HTTP uptime checks don't detect silent @Scheduled failures. Heartbeat monitoring does.
The pattern: your scheduled method pings a unique URL at the end of each successful run. If Vigilmon stops receiving the ping within the expected window, it fires an alert.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ReportScheduler {
@Value("${heartbeat.report.url:}")
private String reportHeartbeatUrl;
private final RestTemplate restTemplate = new RestTemplate();
@Scheduled(cron = "0 0 2 * * *") // daily at 2 AM
public void generateDailyReport() {
try {
// your report logic here
processReport();
// Only ping on success
if (!reportHeartbeatUrl.isEmpty()) {
restTemplate.getForObject(reportHeartbeatUrl, String.class);
}
} catch (Exception e) {
// log the error — don't ping the heartbeat
throw e;
}
}
private void processReport() {
// actual report generation
}
}
In Vigilmon:
- Click New Monitor → Heartbeat
- Set the expected interval (e.g. 25 hours for a daily job)
- Copy the unique ping URL
- Add it to your
application.properties:
heartbeat.report.url=https://vigilmon.online/api/heartbeat/your-unique-token
Now if your scheduled job throws an exception, the heartbeat is never pinged, and Vigilmon alerts you within one missed interval.
Step 5: Webhook alerts and badge embed
Slack/Discord alerts:
- In Vigilmon go to Notifications → New Channel
- Choose Slack or Discord, paste your webhook URL
- Enable it on your monitors
You'll get instant alerts when a monitor goes down and a recovery notification when it comes back up.
Add an uptime badge to your README:
In Vigilmon, open any monitor and copy the badge embed code. It looks like this:
[](https://vigilmon.online?utm_source=devto&utm_medium=article&utm_campaign=springboot-tutorial)
Drop it at the top of your README.md or your internal docs. The badge stays green as long as your monitors are up and flips red during an incident.
What you've built
| What | How |
|---|---|
| External health checks | /actuator/health + Vigilmon HTTP monitor |
| Custom dependency checks | HealthIndicator implementation |
| Scheduled task monitoring | Heartbeat ping inside @Scheduled methods |
| Instant alerts | Slack/Discord notifications |
| README status badge | Vigilmon badge embed |
The whole setup runs on the free tier and takes under 30 minutes. You'll catch the next silent failure before your users do.
Get started free at vigilmon.online — monitors running in under a minute, no credit card required.