![An Easy Step-By-Step Guide to Changing Server Port in a Spring Boot Application [4 Ways]](/images/blog/2023-09-A-Step-By-Step-Guide-to-Changing-Server-Port-in-a-Spring-Boot-Application.png)
Spring Boot applications run on port 8080 by default, but production environments often require different port configurations. Whether you’re avoiding port conflicts, running microservices on the same server, or adhering to organizational standards, knowing how to change the server port is essential. This guide covers four distinct methods with practical examples and troubleshooting solutions.
Table of Contents
Open Table of Contents
- Why Change the Default Port?
- Method 1: Using application.properties
- Method 2: Using application.yml
- Method 3: Command-Line Arguments
- Method 4: Programmatic Configuration
- Environment-Specific Port Configuration
- Random Port Assignment
- Common Errors and Solutions
- Best Practices
- Real-World Example: Microservices Architecture
- Conclusion
- References
- YouTube Videos
Why Change the Default Port?
Spring Boot’s default port 8080 works fine for development, but real-world scenarios demand flexibility:
Common Use Cases
1. Port Conflicts
When port 8080 is already occupied by another application (Apache Tomcat, Jenkins, or another Spring Boot app), you’ll encounter java.net.BindException: Address already in use.
2. Microservices Architecture Running multiple Spring Boot services on the same server requires each service to use a unique port:
- User Service: 8081
- Order Service: 8082
- Payment Service: 8083
3. Production Standards Many organizations have port assignment policies:
- Development: 8000-8999
- Staging: 9000-9999
- Production: Standard ports (80 for HTTP, 443 for HTTPS)
4. Security Requirements Running applications on non-standard ports can add a layer of security through obscurity, though this should never be your primary security measure.
Method 1: Using application.properties
The most straightforward method is configuring the port in your application.properties file located in src/main/resources/.
Basic Configuration
# application.properties
server.port=9090
This sets the server port to 9090 for all environments.
Real-World Example: Development vs Production
# application.properties (default for all environments)
server.port=8080
spring.application.name=customer-service
For development, you might want a different port:
# application-dev.properties
server.port=8081
logging.level.root=DEBUG
For production:
# application-prod.properties
server.port=80
logging.level.root=WARN
server.compression.enabled=true
Activate the profile when running:
java -jar customer-service.jar --spring.profiles.active=prod
Advantages
- ✅ Simple and intuitive
- ✅ Version-controlled with your code
- ✅ Supports profile-specific configurations
- ✅ No code changes required
Disadvantages
- ❌ Requires application rebuild/redeploy to change
- ❌ Less flexible for dynamic scenarios
Method 2: Using application.yml
If you prefer YAML syntax for better readability and hierarchical structure, use application.yml instead.
Basic Configuration
# application.yml
server:
port: 9090
Advanced Configuration with Multiple Settings
# application.yml
server:
port: 9090
servlet:
context-path: /api
compression:
enabled: true
mime-types: application/json,application/xml,text/html,text/xml,text/plain
error:
include-message: always
include-binding-errors: always
Profile-Specific Configuration
# application.yml
spring:
application:
name: inventory-service
profiles:
active: dev
server:
port: 8080 # Default port
---
# Development profile
spring:
config:
activate:
on-profile: dev
server:
port: 8081
logging:
level:
root: DEBUG
---
# Production profile
spring:
config:
activate:
on-profile: prod
server:
port: 443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: ${SSL_PASSWORD}
key-store-type: PKCS12
logging:
level:
root: WARN
Advantages
- ✅ Better readability for complex configurations
- ✅ Supports multiple profiles in one file
- ✅ Hierarchical structure reduces repetition
- ✅ Industry-standard format
Disadvantages
- ❌ YAML syntax can be error-prone (indentation matters)
- ❌ Same deployment limitations as properties files
Method 3: Command-Line Arguments
Perfect for containerized environments, CI/CD pipelines, or when you need to override configuration without modifying files.
Basic Usage
java -jar myapp.jar --server.port=9090
Multiple Arguments
java -jar myapp.jar \
--server.port=9090 \
--spring.profiles.active=prod \
--logging.level.root=INFO
Real-World Example: Docker Container
When deploying Spring Boot applications using Docker, you can override the port dynamically:
Dockerfile:
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Run with custom port:
# Override port at runtime
docker run -p 9090:9090 myapp --server.port=9090
# Using environment variable (recommended)
docker run -e SERVER_PORT=9090 -p 9090:9090 myapp --server.port=${SERVER_PORT}
Docker Compose:
version: '3.8'
services:
user-service:
image: myapp:latest
ports:
- "8081:8081"
command: ["--server.port=8081"]
order-service:
image: myapp:latest
ports:
- "8082:8082"
command: ["--server.port=8082"]
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: customer-service
spec:
replicas: 3
template:
spec:
containers:
- name: app
image: customer-service:1.0
args:
- "--server.port=8080"
- "--spring.profiles.active=prod"
ports:
- containerPort: 8080
env:
- name: SERVER_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: server.port
Advantages
- ✅ Dynamic port assignment without code changes
- ✅ Perfect for containers and cloud deployments
- ✅ Overrides file-based configuration
- ✅ No rebuild required
Disadvantages
- ❌ Must be specified every time you run the app
- ❌ Not documented in code repository
- ❌ Can be forgotten in deployment scripts
Method 4: Programmatic Configuration
For advanced scenarios where you need conditional logic, runtime calculations, or integration with external configuration systems.
Using WebServerFactoryCustomizer
package com.example.config;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServerConfig {
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
webServerFactoryCustomizer() {
return factory -> factory.setPort(9090);
}
}
Dynamic Port Based on Environment
package com.example.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DynamicPortConfig {
@Value("${ENVIRONMENT:dev}")
private String environment;
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
customizer() {
return factory -> {
int port = calculatePort(environment);
factory.setPort(port);
System.out.println("Starting server on port: " + port);
};
}
private int calculatePort(String env) {
return switch (env.toLowerCase()) {
case "dev" -> 8081;
case "staging" -> 9090;
case "prod" -> 80;
default -> 8080;
};
}
}
Port Assignment from External Config Server
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ExternalConfigPortSetup {
@Autowired
private RestTemplate restTemplate;
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
externalConfigCustomizer() {
return factory -> {
try {
// Fetch port from external configuration service
String configUrl = "http://config-server:8888/port-assignment";
Integer port = restTemplate.getForObject(configUrl, Integer.class);
if (port != null && port > 0 && port <= 65535) {
factory.setPort(port);
} else {
factory.setPort(8080); // Fallback to default
}
} catch (Exception e) {
System.err.println("Failed to fetch port from config server: " + e.getMessage());
factory.setPort(8080); // Fallback to default
}
};
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Advantages
- ✅ Full control over port selection logic
- ✅ Can integrate with external systems
- ✅ Supports complex conditional logic
- ✅ Useful for multi-tenant applications
Disadvantages
- ❌ More complex to implement and maintain
- ❌ Harder to debug port assignment issues
- ❌ Overkill for simple use cases
Environment-Specific Port Configuration
Modern applications run in multiple environments. Here’s how to manage ports across dev, staging, and production:
Using Spring Profiles
application.properties:
# Default configuration
server.port=8080
spring.application.name=payment-service
application-dev.properties:
server.port=8081
spring.datasource.url=jdbc:mysql://localhost:3306/dev_db
application-staging.properties:
server.port=9090
spring.datasource.url=jdbc:mysql://staging-db:3306/staging_db
application-prod.properties:
server.port=443
server.ssl.enabled=true
spring.datasource.url=jdbc:mysql://prod-db:3306/prod_db
Run with specific profile:
# Development
java -jar payment-service.jar --spring.profiles.active=dev
# Production
java -jar payment-service.jar --spring.profiles.active=prod
Using Environment Variables
Set the port via environment variable (works across all methods):
# Linux/Mac
export SERVER_PORT=9090
java -jar myapp.jar
# Windows
set SERVER_PORT=9090
java -jar myapp.jar
# Docker
docker run -e SERVER_PORT=9090 -p 9090:9090 myapp
Spring Boot automatically maps SERVER_PORT to server.port property.
Random Port Assignment
Useful for testing environments or when running multiple instances:
Configuration
# application.properties
server.port=0
Or in YAML:
server:
port: 0
Spring Boot will assign a random available port.
Retrieving the Assigned Port
package com.example.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class InfoController {
@LocalServerPort
private int port;
@GetMapping("/port")
public String getPort() {
return "Application is running on port: " + port;
}
}
Use in Integration Tests
package com.example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void testRandomPortAssignment() {
String response = restTemplate.getForObject(
"http://localhost:" + port + "/port",
String.class
);
assertThat(response).contains("running on port: " + port);
}
}
Common Errors and Solutions
Error 1: Port Already in Use
Error Message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Web server failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Full Exception:
org.springframework.boot.web.server.PortInUseException: Port 8080 is already in use
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:226)
Caused by: java.net.BindException: Address already in use
Solution 1: Find and Kill the Process
Linux/Mac:
# Find process using port 8080
lsof -i :8080
# Output example:
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# java 12345 user 123u IPv6 123456 0t0 TCP *:8080 (LISTEN)
# Kill the process
kill -9 12345
Windows:
# Find process using port 8080
netstat -ano | findstr :8080
# Output example:
# TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 12345
# Kill the process
taskkill /PID 12345 /F
Solution 2: Change to Different Port
# application.properties
server.port=9090
Solution 3: Use Random Port
server.port=0
Error 2: Invalid Port Number
Error Message:
java.lang.IllegalArgumentException: Port must be between 0 and 65535
at org.springframework.boot.web.server.AbstractConfigurableWebServerFactory.setPort
Common Invalid Configurations:
# ❌ Negative port
server.port=-1
# ❌ Port exceeds limit
server.port=70000
# ❌ Non-numeric value
server.port=eight-zero-eight-zero
Solution:
Use valid port range (1-65535, or 0 for random):
# ✅ Valid configurations
server.port=8080
server.port=443
server.port=0
Note: Ports 1-1023 are privileged ports and require root/administrator access on Unix systems.
Error 3: Configuration Not Taking Effect
Problem: You’ve set the port in application.properties but the app still starts on 8080.
Common Causes:
1. Multiple Configuration Files
Check for multiple configuration files:
flowchart TD
R[src/main/resources] --> P[application.properties server.port 9090]
R --> Y[application.yml server.port 8080 takes precedence]
Solution: Spring Boot loads configurations in this order (later overrides earlier):
application.propertiesapplication.yml- Profile-specific properties (
application-{profile}.properties) - Profile-specific YAML (
application-{profile}.yml) - Command-line arguments (highest priority)
Remove duplicate configurations or use command-line to override:
java -jar myapp.jar --server.port=9090
2. Wrong File Location
# ❌ Wrong location
src/resources/application.properties
# ✅ Correct location
src/main/resources/application.properties
3. Typos in Property Name
# ❌ Wrong
server.port=9090
Server.Port=9090
# ✅ Correct
server.port=9090
4. Active Profile Overriding
# application.properties has server.port=8080
# application-dev.properties has server.port=9090
# This will use port 9090 (dev profile overrides default)
java -jar myapp.jar --spring.profiles.active=dev
Debugging Tips:
Enable debug logging to see which configuration files are loaded:
logging.level.org.springframework.boot=DEBUG
Or run with debug flag:
java -jar myapp.jar --debug
Look for lines like:
INFO: Loaded config file 'file:/path/to/application.properties'
INFO: Loaded config file 'file:/path/to/application-dev.properties'
Error 4: Permission Denied (Ports < 1024 on Linux)
Error Message:
java.net.SocketException: Permission denied
Problem: Trying to use port 80 or 443 without proper permissions.
Solution 1: Run with sudo (not recommended)
sudo java -jar myapp.jar
Solution 2: Use authbind (recommended)
# Install authbind
sudo apt-get install authbind
# Allow binding to port 80
sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
sudo chown yourusername /etc/authbind/byport/80
# Run application
authbind --deep java -jar myapp.jar
Solution 3: Use reverse proxy (best practice)
Use nginx or Apache as reverse proxy on port 80/443, forwarding to your Spring Boot app on 8080:
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Best Practices
1. Use Profile-Specific Configuration
Don’t hardcode ports for different environments in the same file:
# ✅ Good: application.yml
server:
port: ${SERVER_PORT:8080} # Environment variable with fallback
---
# application-dev.yml
server:
port: 8081
---
# application-prod.yml
server:
port: 443
2. Document Port Assignments
Maintain a ports.md file in your repository:
# Port Assignments
| Service | Dev | Staging | Production |
|------------------|------|---------|------------|
| API Gateway | 8080 | 9000 | 443 |
| User Service | 8081 | 9001 | 8081 |
| Order Service | 8082 | 9002 | 8082 |
| Payment Service | 8083 | 9003 | 8083 |
| Notification | 8084 | 9004 | 8084 |
3. Use Environment Variables in Production
Avoid hardcoding ports in production properties:
# application-prod.yml
server:
port: ${SERVER_PORT} # Required environment variable
Set via deployment platform:
# Kubernetes ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
SERVER_PORT: "8080"
4. Health Check on Custom Ports
When using custom ports, update health check endpoints:
# application.yml
server:
port: 9090
management:
server:
port: 9091 # Separate port for actuator endpoints
endpoints:
web:
exposure:
include: health,info,metrics
Access health endpoint:
curl http://localhost:9091/actuator/health
5. Test Port Conflicts in CI/CD
Include port conflict tests in your pipeline:
#!/bin/bash
# check-port.sh
PORT=8080
if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null ; then
echo "Port $PORT is already in use. Please free it before running tests."
exit 1
fi
echo "Port $PORT is available"
./mvnw clean test
Real-World Example: Microservices Architecture
Let’s see how Netflix-style microservices architecture manages ports across multiple services.
Project Structure
flowchart TD
E[ecommerce-platform] --> G[api-gateway port 8080]
E --> U[user-service port 8081]
E --> PR[product-service port 8082]
E --> O[order-service port 8083]
E --> PA[payment-service port 8084]
E --> N[notification-service port 8085]
E --> D[docker-compose.yml]
Service Configuration
user-service/application.yml:
spring:
application:
name: user-service
server:
port: ${USER_SERVICE_PORT:8081}
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}
order-service/application.yml:
spring:
application:
name: order-service
server:
port: ${ORDER_SERVICE_PORT:8083}
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Docker Compose Configuration
version: '3.8'
services:
eureka-server:
image: eureka-server:latest
ports:
- "8761:8761"
networks:
- microservices-net
api-gateway:
image: api-gateway:latest
ports:
- "8080:8080"
environment:
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
- eureka-server
networks:
- microservices-net
user-service:
image: user-service:latest
ports:
- "8081:8081"
environment:
- SERVER_PORT=8081
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
- eureka-server
networks:
- microservices-net
order-service:
image: order-service:latest
ports:
- "8083:8083"
environment:
- SERVER_PORT=8083
- USER_SERVICE_URL=http://user-service:8081
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
- eureka-server
- user-service
networks:
- microservices-net
payment-service:
image: payment-service:latest
ports:
- "8084:8084"
environment:
- SERVER_PORT=8084
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
- eureka-server
networks:
- microservices-net
networks:
microservices-net:
driver: bridge
Running Multiple Instances
For load balancing, run multiple instances of the same service on different ports:
# Instance 1
java -jar user-service.jar --server.port=8081
# Instance 2
java -jar user-service.jar --server.port=8091
# Instance 3
java -jar user-service.jar --server.port=8101
Or with Docker:
docker run -e SERVER_PORT=8081 -p 8081:8081 user-service
docker run -e SERVER_PORT=8091 -p 8091:8091 user-service
docker run -e SERVER_PORT=8101 -p 8101:8101 user-service
Conclusion
Changing the server port in Spring Boot is a fundamental configuration that every developer should master. This guide covered four distinct methods:
- application.properties - Simple, version-controlled, profile-aware
- application.yml - Better readability, hierarchical structure
- Command-line arguments - Dynamic, perfect for containers and cloud
- Programmatic configuration - Full control, conditional logic support
Choose the method that best fits your deployment model and organizational requirements. For most applications, using application.yml with Spring profiles provides the right balance of simplicity and flexibility. For containerized deployments, command-line arguments or environment variables offer maximum flexibility.
Remember these key takeaways:
- Always document your port assignments
- Use environment-specific profiles
- Test for port conflicts in CI/CD
- Prefer environment variables in production
- Use reverse proxies for privileged ports
- Monitor port availability before startup
With this knowledge, you can confidently manage server ports across development, staging, and production environments, whether you’re running a single monolith or a complex microservices architecture.
References
-
Spring Boot Reference Documentation - Application Properties
https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server -
Spring Boot Server Configuration Guide
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.webserver -
Externalized Configuration in Spring Boot
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config -
Baeldung - Configure Spring Boot Web Server
https://www.baeldung.com/spring-boot-configure-tomcat -
Spring Boot Docker Documentation
https://spring.io/guides/gs/spring-boot/
YouTube Videos
-
“Spring Boot Configuration - Properties vs YAML” by Java Brains
https://www.youtube.com/watch?v=Y6Ev8GIlbxc -
“Spring Boot Profiles Explained” by Amigoscode
https://www.youtube.com/watch?v=xDuwrtwYHu8 -
“Dockerizing Spring Boot Applications” by Daily Code Buffer
https://www.youtube.com/watch?v=NtMvNh0WFVM -
“Spring Boot Microservices with Docker Compose” by Programming Techie
https://www.youtube.com/watch?v=VAmntTPebKE -
“Spring Boot Application Properties Deep Dive” by Telusko
https://www.youtube.com/watch?v=bUHFg8CZFws