# Securing MinIO URL using NGINX

When deploying objects to the MinIO server, one of the potential security concerns is the direct accessibility of the MinIO URL. Generally, we use pre-signed URLs in our application that grant temporary access to private objects. While these URLs have an expiration time and provide a level of security, they can still be accessed by anyone who possesses the link within the specified time window.

This can become a security risk if unauthorized users gain access to these pre-signed URLs then they can misuse or expose the sensitive data stored in the MinIO bucket. Therefore, there is a need to implement an additional layer of security to prevent unauthorized access to the URLs, even within the expiration time.

In this post, I will provide step-by-step instructions on how to set up NGINX as a reverse proxy for MinIO and demonstrate how this configuration enhances the security of the MinIO setup.

## **1\. Setup a MinIO Server**

If you have a problem setting up MinIO server visit [MinIO's Official documentation](https://min.io/docs/minio/container/index.html).

### **Step 1.1) Pulling MinIO Docker Image**

Before we begin, ensure you have Docker installed on your system. Pull the MinIO Docker image using the following command.

```bash
docker pull quay.io/minio/minio
```

*My MinIO Version: RELEASE.2023-07-21T21-12-44Z.*

### **Step 1.2) Spinning up MinIO with Docker**

Next, we will run the MiniIO server with Docker using the pulled image.

```bash
docker run -dt \
-p 9000:9000 -p 9090:9090 \
-v /local/path/data:/mnt/data \
-v /local/path/config.env:/etc/config.env \
-e "MINIO_CONFIG_ENV_FILE=/etc/config.env" \
--name "minio_local" \
quay.io/minio/minio server --console-address ":9090"
```

**config.env (file)**

> *MINIO\_ROOT\_USER=myminioadmin*
> 
> *MINIO\_ROOT\_PASSWORD=minio-secret-key-change-me*
> 
> *MINIO\_VOLUMES="/mnt/data"*

The MinIO server console (Web interface) can be accessed at [http://localhost:9090](http://localhost:9090) and the API will be at http://localhost:9000.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693464244989/d6415a21-4a77-4b6d-bea0-0ec66a9cce17.png align="right")

## **2\. Setup NGINX Proxy server**

### **Step 2.1) Configuring NGINX for console.**

Now, let’s proceed with setting up the NGINX web server as reverse proxy for the MiniIO data

```bash
docker run -d \
-p 8080:80 \
--name nginx_console \
-v /local/path/nginx_console.conf:/etc/nginx/conf.d/default.conf \
nginx:latest
```

This will start NGINX proxy server for MinIO Console which can be accessed at [http://localhost:8080](http://localhost:8080).

**nginx\_console.conf (file)**

```nginx
# nginx_console.conf

server {
      listen 80;
      server_name _;
      
      access_log  /var/log/nginx/minio_console_access.log;  
      error_log   /var/log/nginx/minio_console_error.log;  
      
      location / {
	       proxy_set_header Host $http_host;
           proxy_set_header X-Real-IP $remote_addr;
      	   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      	   proxy_set_header X-Forwarded-Proto $scheme;
           proxy_set_header X-NginX-Proxy true;
           
           # This is necessary to pass the correct IP to be hashed
		   real_ip_header X-Real-IP;
                 
		   proxy_connect_timeout 300;
      		
           # To support websockets in MinIO versions released after January 2023
      	   proxy_http_version 1.1;
      	   proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
		 
		   chunked_transfer_encoding off;
		   
		   proxy_pass http://localhost:9090; 
}
```

### **Step 2.2) Configuring NGINX for API**

Similarly, we will configure NGINX to act as a reverse proxy for the MinIO API to ensure secure access to the MinIO server's RESTful API.

```bash
docker run -d \
-p 8081:80 \
--name nginx_api \
-v /local/path/nginx_api.conf:/etc/nginx/conf.d/default.conf \
nginx:latest
```

This will start another NGINX proxy server for MinIO API which can be accessed at [http://localhost:8081](http://localhost:8081).

**nginx\_api.conf (file)**

```nginx
# nginx_api.conf

server {
      listen 80;
      server_name _;
      
      access_log  /var/log/nginx/minio_api_access.log;  
      error_log   /var/log/nginx/minio_api_error.log;  
      
      location / {
	       proxy_set_header Host $http_host;
           proxy_set_header X-Real-IP $remote_addr;
      	   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      	   proxy_set_header X-Forwarded-Proto $scheme;
                 
		   proxy_connect_timeout 300;
      		 
  		   proxy_http_version 1.1;
      	   proxy_set_header Connection "";
      	   chunked_transfer_encoding off;
		  
		   proxy_pass http://localhost:9000;
}
```

## **3\. Restricting Access to MinIO through NGINX**

To prevent unauthorized access to MinIO URL, we will add a following code in NGINX for MinIO API, which will restrict access based on the application’s referer.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1693465041229/548019a2-f248-4ec1-9fa6-52183bd375fd.png align="center")

```nginx
# nginx_api.conf

map $http_referer $is_valid_referer {
    default                         0;
    "~^http://localhost:8080/"      1;
    "~^https://my-app-domain.com/"  1;
}

server {
   
   //  rest of code
   
   location / {
        if ($is_valid_referer = 0) {
            return 403;
        }
    
    //  rest of code
   
   }
}
```

In the **nginx\_api.conf** file, the '**map**' block is defined outside the '**server**' block. It maps the '**http\_referer**' header to the '**$is\_valid\_referer**' variable. Here, we add all the valid referer URLs that can access the page.

Next, we use the '**if**' condition inside the **'location** **/**' block to check whether the referer is valid or not. If it is not valid, we will return a 403 Forbidden response, effectively denying access to MinIO for unauthorized clients.
