Introduction
Using proxies is a common practice to manage network traffic, improve security, and optimize performance in distributed systems. This article explores the types of proxies and provides a practical tutorial to build a system with a reverse proxy and load balancing using NGINX, integrating two web servers built with Spring Boot.
What is a Proxy?
A proxy is an intermediary between a client and a server. It can perform various functions depending on its type and configuration. Proxies help manage connections, implement security, cache content, and balance traffic.
Types of Proxy
1. Forward Proxy
A forward proxy acts as an intermediary between the client and the internet. The client sends requests to the proxy, which forwards them to the destination server on behalf of the client. This type of proxy is commonly used in corporate and home networks.
Characteristics:
- Hides the client’s IP address.
- Can be configured to filter and block content.
- Implements caching to improve performance.
Advantages:
- Privacy: Masks the client’s IP address when accessing external resources.
- Control: Allows restriction of access to certain websites or content.
- Caching: Speeds up access to frequently used resources.
Use Cases:
- Protecting user identity while browsing the web.
- Permitting or blocking access to specific sites in corporate or school networks.
- Improving performance for shared networks using caching.
2. Reverse Proxy
A reverse proxy works in the opposite direction of a forward proxy. It is placed in front of one or more servers, intercepting requests before they reach the final server. It is widely used in modern architectures to enhance scalability, security, and flexibility.
Characteristics:
- Hides the internal details of the infrastructure servers.
- Can distribute traffic across multiple servers (load balancing).
- Supports SSL/TLS for secure connections.
Advantages:
- Security: Protects backend servers from direct attacks, such as DDoS.
- Scalability: Enables load balancing by distributing requests among servers.
- Performance: Allows response caching and content compression.
- Centralization: Simplifies SSL/TLS management since the reverse proxy handles the configurations.
Use Cases:
- Hosting multiple domains with a single entry point.
- Implementing load balancing to distribute requests across servers.
- Adding a web application firewall (WAF) for advanced security.
3. Transparent Proxy
A transparent proxy operates in a way that the client is unaware of its presence. It intercepts traffic automatically without requiring any configuration on the client side. It is often implemented at network gateways.
Characteristics:
- Requires no setup on client devices.
- Can be used to monitor or filter traffic.
Advantages:
- Ease of Use: Does not require user intervention.
- Monitoring: Ideal for capturing traffic statistics in corporate networks.
- Filtering: Allows blocking content without direct user involvement.
Use Cases:
- Monitoring and controlling internet usage in corporate networks.
- Providing caching for frequently accessed resources.
- Blocking or redirecting unwanted traffic.
4. Anonymous Proxy
An anonymous proxy hides the client’s identity (their IP address) while accessing the internet. It enhances user privacy and prevents tracking by websites or third parties.
Characteristics:
- Removes or replaces identifying information from the client.
- Can be configured for partial or full anonymity.
Advantages:
- Privacy: Protects users from being tracked.
- Access Control: Allows bypassing geographically restricted content.
Use Cases:
- Private browsing to avoid data collection.
- Accessing content restricted by region.
5. High Anonymity Proxy (Elite Proxy)
These proxies not only hide the client’s IP address but also do not reveal that the traffic is being routed through a proxy. They are considered the most secure and private proxies.
Characteristics:
- Completely undetectable by destination servers.
- Excellent for secure and discreet browsing.
Advantages:
- Maximum Privacy: Provides the highest level of anonymity.
- Advanced Security: Ideal for avoiding censorship or surveillance.
Use Cases:
- Secure connections on public networks.
- Avoiding censorship in countries with strict internet regulations.
6. SOCKS Proxy
A SOCKS proxy is a more generic type of proxy that works at the transport layer (Layer 5 of the OSI model), allowing forwarding of any type of traffic, such as HTTP, FTP, or even streaming and online gaming applications.
Characteristics:
- Not limited to HTTP/HTTPS protocols.
- Works with any type of traffic (TCP or UDP).
Advantages:
- Versatility: Supports various protocols and applications.
- Broad Reach: Ideal for use cases where traditional HTTP proxies are insufficient.
Use Cases:
- Applications requiring real-time communication, such as VoIP and online gaming.
- Bypassing network blocks relying on packet inspection.
7. Web Proxy
A web proxy is directly accessed through a browser, usually without the need to install additional software. It is commonly used to bypass network restrictions.
Characteristics:
- Used via a web interface.
- Often free but with limited functionality.
Advantages:
- Ease of Use: Requires no configuration on the device.
- Accessibility: Useful for quickly bypassing restrictions.
Use Cases:
- Accessing blocked content in corporate or school networks.
- Anonymous browsing without additional software.
Building a System with a Reverse Proxy and Load Balancer
Let’s build a system where NGINX acts as a reverse proxy and load balancer for two Spring Boot servers.
System Architecture
- The client sends requests to NGINX.
- NGINX distributes the requests across two Spring Boot servers running on different ports.
- The system uses round-robin as the load balancing method, see other methods on the reference.
1. Setting Up the Web Servers with Spring Boot
Create a simple Spring Boot application, with the spring web dependency.
We are going to create a controller like this:
package dev.mspilari.spring_app_server.controllers;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello-world")
public class HelloWorld {
@GetMapping()
public ResponseEntity<Map<String, String>> helloWorld() {
return ResponseEntity.ok().body(Map.of("message", "Hello world from: " + System.getenv("SERVER_NAME")));
}
}
See, we are using a environment variable SERVER_NAME
, this will tell us who is the server that are sending a request to us.
2. Setting Up the Dockerfile for the web servers
FROM eclipse-temurin:21-jdk-alpine
WORKDIR /app
COPY pom.xml .
COPY .mvn .mvn
COPY mvnw .
COPY mvnw.cmd .
RUN chmod +x mvnw
COPY src ./src
RUN ./mvnw clean package -DskipTests
ENV SERVER_NAME="Default Server"
ENTRYPOINT ["java","-jar","target/spring_app_server-0.0.1-SNAPSHOT.jar"]
If you are using another version of java, change the eclipse-temurin version
Configuring the Reverse Proxy and Load Balancer
At the root of your application create a folder called nginx
, inside that, create two files:
-
nginx.conf
http {
upstream spring_servers {
server spring-server-1:8080;
server spring-server-2:8080;
}
server {
listen 8080;
location / {
proxy_pass http://spring_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
events{}
Code explain
Upstream: The name given to the upstream block can be anything. This name is just an identifier that will be used later in the proxy_pass directive
Server names: The name on the server inside the upstream block must match the service name in Docker Compose, because NGINX resolves this name using the internal network created by Compose.
Server ports: The port specified in the upstream block (e.g. 8080) must match the container's internal port, that is, the port that the Spring Boot server is listening on inside the container.
-
Dockerfile
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
Creating the docker compose file
At the project root, create the docker compose file, REMEMBER the names of services NEEDS to be the equals at nginx.conf.
services:
spring-server-1:
build:
context: .
environment:
- SERVER_NAME=Server_1
ports:
- "8081:8080"
networks:
- app_network
spring-server-2:
build:
context: .
environment:
- SERVER_NAME=Server_2
ports:
- "8082:8080"
networks:
- app_network
nginx:
build:
context: ./nginx
ports:
- "8080:8080"
depends_on:
- spring-server-1
- spring-server-2
networks:
- app_network
networks:
app_network:
driver: bridge
Testing the application
Run:
docker compose up -d
This will start the 3 containers, then start sending requests to the proxy
curl http://localhost:8080/hello-world
If everything works fine, you will receive two types of response:
// if the server_1 get the request
{"message":"Hello world from: Server_1"}
// if the server_2 get the request
{"message":"Hello world from: Server_2"}
Conclusion
Proxies are powerful tools to manage traffic and ensure system efficiency. With NGINX configured as a reverse proxy and load balancer, we successfully distributed requests efficiently between our Spring Boot servers.
This setup serves as a foundation for more complex systems, enabling greater scalability and resilience.
Top comments (0)