How to Build and Secure a Spring Boot Admin Dashboard with Eureka Integration
This tutorial walks through setting up Spring Boot Admin as a monitoring server and client, integrating it with Eureka for service discovery, adding Spring Security for authentication, and configuring email and custom notifications, complete with Maven and YAML configurations and Java code examples.
What is Spring Boot Admin?
Spring Boot Admin is an open‑source community project for managing and monitoring Spring Boot applications. Clients register with the Admin Server via HTTP or a Spring Cloud registry (e.g., Eureka, Consul). The UI, built with Vue.js, displays health status, JVM and memory metrics, Micrometer metrics, datasource and cache metrics, build information, log files, environment properties, Spring Boot configuration properties, JMX beans, thread dumps, HTTP traces, audit events, scheduled tasks, active sessions, Flyway/Liquibase migrations, heap dumps, and supports status change notifications via email, Slack, HipChat, etc.
Display health status
Show detailed metrics (JVM, memory, micrometer.io, datasource, cache)
Show build information
Download log files
View JVM system and environment properties
View Spring Boot configuration properties
Support Spring Cloud's /postable, /env, and /refresh endpoints
Easy log level management
Interact with JMX beans
View thread dumps
View HTTP traces
View audit events
View HTTP endpoints
View scheduled tasks
View and delete active sessions (spring‑session)
View Flyway/Liquibase migrations
Download heap dumps
Status change notifications (email, Slack, HipChat, …)
Non‑persistent event log for status changes
Getting Started
1. Create Spring Boot Admin Server
pom.xml
<code><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.gf</groupId>
<artifactId>admin-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-boot-admin.version>2.1.0</spring-boot-admin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project></code>application.yml
<code>spring:
application:
name: admin-server
server:
port: 8769</code>AdminServerApplication
<code>@SpringBootApplication
@EnableAdminServer
public class AdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(AdminServerApplication.class, args);
}
}</code>2. Create Spring Boot Admin Client
pom.xml
<code><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.gf</groupId>
<artifactId>admin-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-boot-admin.version>2.1.0</spring-boot-admin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project></code>application.yml
<code>spring:
application:
name: admin-client
boot:
admin:
client:
url: http://localhost:8769
server:
port: 8768
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS</code>AdminClientApplication
<code>@SpringBootApplication
public class AdminClientApplication {
public static void main(String[] args) {
SpringApplication.run(AdminClientApplication.class, args);
}
}</code>Run both projects and open
Integrating Eureka
1. Create sc-eureka-server
pom.xml
<code><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
... (same structure as previous pom, adding spring-cloud-starter-netflix-eureka-client) ...
</project></code>application.yml
<code>spring:
application:
name: sc-eureka-server
server:
port: 8761
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
register-with-eureka: false
fetch-registry: false
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS</code>ScEurekaServerApplication
<code>@SpringBootApplication
@EnableEurekaServer
public class ScEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(ScEurekaServerApplication.class, args);
}
}</code>2. Create sc-admin-server (Spring Boot Admin Server with Eureka)
pom.xml
<code>(pom similar to admin‑server but adds spring-cloud-starter-netflix-eureka-client)</code>application.yml
<code>spring:
application:
name: admin-server
server:
port: 8769
eureka:
client:
registryFetchIntervalSeconds: 5
service-url:
defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
health-check-url-path: /actuator/health
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS</code>ScAdminServerApplication
<code>@SpringBootApplication
@EnableAdminServer
@EnableDiscoveryClient
public class ScAdminServerApplication {
public static void main(String[] args) {
SpringApplication.run(ScAdminServerApplication.class, args);
}
}</code>3. Create sc-admin-client (Spring Boot Admin Client with Eureka)
pom.xml
<code>(pom adds spring-boot-admin-starter-client and spring-cloud-starter-netflix-eureka-client)</code>application.yml
<code>spring:
application:
name: sc-admin-client
eureka:
instance:
leaseRenewalIntervalInSeconds: 10
health-check-url-path: /actuator/health
client:
registryFetchIntervalSeconds: 5
service-url:
defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
server:
port: 8762</code>ScAdminClientApplication
<code>@SpringBootApplication
@EnableDiscoveryClient
public class ScAdminClientApplication {
public static void main(String[] args) {
SpringApplication.run(ScAdminClientApplication.class, args);
}
}</code>After starting the three services, visit
to see the auto‑registered applications.
Integrating Spring Security
Add the security starter to the admin‑server pom:
<code><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency></code>Configure username and password in
application.ymland expose them via Eureka metadata:
<code>spring:
security:
user:
name: "admin"
password: "admin"
eureka:
instance:
metadata-map:
user.name: ${spring.security.user.name}
user.password: ${spring.security.user.password}</code>Create a security configuration class:
<code>@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeRequests()
.antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
.logout().logoutUrl(adminContextPath + "/logout").and()
.httpBasic();
}
}</code>Access
http://localhost:8769/and you will be prompted for the credentials (admin / admin).
Notifications
1. Email Notification
Add the mail starter to the admin‑server pom:
<code><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency></code>Configure mail properties and notification recipients in
application.yml:
<code>spring:
mail:
host: smtp.163.com
username: [email protected]
password: xxxx
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
boot:
admin:
notify:
mail:
from: [email protected]
to: [email protected]</code>Optionally increase the monitor read timeout or disable unused health checks to avoid repeated offline notifications:
<code># Increase timeout (ms)
spring.boot.admin.monitor.read-timeout=20000
# Disable unimportant health checks
management.health.db.enabled=false
management.health.mail.enabled=false
management.health.redis.enabled=false
management.health.mongo.enabled=false</code>2. Custom Notification
Implement a custom notifier by extending
AbstractStatusChangeNotifier:
<code>@Component
public class CustomNotifier extends AbstractStatusChangeNotifier {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomNotifier.class);
public CustomNotifier(InstanceRepository repository) {
super(repository);
}
@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
if (event instanceof InstanceStatusChangedEvent) {
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
switch (status) {
case "DOWN":
System.out.println("Send DOWN notification");
break;
case "OFFLINE":
System.out.println("Send OFFLINE notification");
break;
case "UP":
System.out.println("Send UP notification");
break;
case "UNKNOWN":
System.out.println("Send UNKNOWN notification");
break;
default:
break;
}
} else {
LOGGER.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(), event.getType());
}
});
}
}</code>Source code repository: GitHub
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.