# Complete Guide: Secure Application Deployment with Pangolin and NPM

**URL:** <https://forum.hhf.technology/t/complete-guide-secure-application-deployment-with-pangolin-and-npm/475>\
**Category:** Guides & Tutorials\
**Tags:** tunnels, nginx-proxy-manager, pangolin\
**Created:** [February 12, 2025, 2:37pm UTC](https://forum.hhf.technology/t/complete-guide-secure-application-deployment-with-pangolin-and-npm/475 "2025-02-12T14:37:20Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [February 12, 2025, 2:37pm UTC](https://forum.hhf.technology/t/complete-guide-secure-application-deployment-with-pangolin-and-npm/475/1 "2025-02-12T14:37:20Z")

</div>

# Complete Guide: Secure Application Deployment with Pangolin(Cloud VPS) and NPM(Home Deployment)

This comprehensive guide will walk you through setting up a secure application infrastructure using Pangolin for tunneling and Nginx Proxy Manager (NPM) for reverse proxying.

We’ll break this into two main parts.

## Part 1: Pangolin Configuration

Let’s start by setting up the Pangolin side of our infrastructure.

### Initial Pangolin Setup

First, we need to create a site and set up the proper resources in Pangolin.

#### Creating a Site

1. Log into your Pangolin dashboard
2. Navigate to Sites and select “Add Site”
3. Fill in the following details:

```auto
Name: Internal Applications
Description: Hosts internal services behind NPM
Connection Method: Newt (recommended for better stability)

```

4. After creation, you’ll receive Newt credentials. Save these securely:

```auto
PANGOLIN_ENDPOINT=your-pangolin-instance.com
NEWT_ID=generated-id
NEWT_SECRET=generated-secret

```

#### Setting Up Resources

For each application, we need to create a corresponding resource in Pangolin. Let’s set up resources for common applications:

##### Uptime Kuma

1. Go to Resources → Add Resource
2. Configure:

```auto
Name: Uptime Kuma
Subdomain: uptime (will create uptime.yourdomain.com)
Site: Internal Applications

Under Connectivity:
- Enable SSL: Yes
- Method: HTTP
- IP/Hostname: 10.24.7.96
- Port: 89

```

 ![image](https://forum-cdn.hhf.technology/original/1X/8362310c47b9336a701b9f43ccb30b54a36947f9.jpeg)

# Read down for explanation.

##### Nextcloud Resource

1. Go to Resources → Add Resource
2. Configure:

```auto
Name: Nextcloud
Subdomain: cloud (will create cloud.yourdomain.com)
Site: Internal Applications

Under Connectivity:
- Enable SSL: Yes
- Method: HTTP
- IP/Hostname: nginx-proxy-manager
- Port: 80

```

 ![image](https://forum-cdn.hhf.technology/original/1X/ac266e5c57c1ef06b37956d7bd61589b900c4e70.jpeg)

##### Gitea Resource

1. Add another resource:

```auto
Name: Gitea
Subdomain: git
Site: Internal Applications

Under Connectivity:
- Enable SSL: Yes
- Method: HTTP
- IP/Hostname: nginx-proxy-manager
- Port: 80

```

 ![image](https://forum-cdn.hhf.technology/original/1X/7d2399e0156b34cb29645fd1fdb626b599db1c00.jpeg)

##### WordPress Resource

1. Add resource:

```auto
Name: WordPress
Subdomain: blog
Site: Internal Applications

Under Connectivity:
- Enable SSL: Yes
- Method: HTTP
- IP/Hostname: nginx-proxy-manager
- Port: 80

```

 ![image](https://forum-cdn.hhf.technology/original/1X/7d2399e0156b34cb29645fd1fdb626b599db1c00.jpeg)

### Authentication Configuration

For each resource, configure authentication under the Authentication tab:

1. Platform SSO:

2. Additional Authentication (optional):

### SSL Configuration

In Pangolin’s Traefik configuration, ensure proper SSL handling:

1. Edit `traefik_config.yml`:

```yaml
certificatesResolvers:
  letsencrypt:
    acme:
      email: your-email@domain.com
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letsencrypt

```

## Part 2: NPM and Application Deployment

Now let’s set up the local infrastructure with NPM and our applications.

### Network and Base Infrastructure

First, create the required Docker network:

```bash
docker network create npm_network --external

```

### External Application Compose Configuration

Create a Uptime Kuma `docker-compose.yml` file:

```yaml
services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: always
    ports:
      - "3010:3001"
    volumes:
      - ./uptime-kuma:/app/data
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - npm_network

volumes:
  uptime-kuma:

networks:
  npm_network:
    name: npm_network

```

### Docker Compose Configuration

Create a `docker-compose.yml` file:

```yaml
networks:
  npm_network:
    external: true 

volumes:
  npm_data:
  npm_letsencrypt:
  nextcloud_data:
  gitea_data:
  wordpress_data:
  wordpress_db:

services:
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '89:80'
      - '449:443'
      - '81:81'
    environment:
      DISABLE_DEFAULT_SERVER: "true"
      LE_EMAIL: "your-email@domain.com"
    volumes:
      - npm_data:/data
      - npm_letsencrypt:/etc/letsencrypt
    networks:
      - npm_network

  newt:
    image: fosrl/newt:latest
    container_name: newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=your-pangolin-instance.com
      - NEWT_ID=your-newt-id
      - NEWT_SECRET=your-newt-secret
    networks:
      - npm_network

  # Application Services
  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    restart: unless-stopped
    volumes:
      - nextcloud_data:/var/www/html
    networks:
      - npm_network

  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    restart: unless-stopped
    volumes:
      - gitea_data:/data
    networks:
      - npm_network

  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: secure_password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
    networks:
      - npm_network

  wordpress-db:
    image: mariadb:latest
    container_name: wordpress-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: secure_password
      MYSQL_ROOT_PASSWORD: very_secure_root_password
    volumes:
      - wordpress_db:/var/lib/mysql
    networks:
      - npm_network

```

### NPM Proxy Host Configuration

Access NPM’s admin interface (port 81) and configure each application:

#### Uptime Kuma Proxy Host

```auto
Domain Names: uptime.yourdomain.com
Scheme: http
Forward Hostname: 10.24.7.96
Forward Port: 3010
Advanced: Enable WebSocket Support

```

 ![image](https://forum-cdn.hhf.technology/original/1X/92f696cb6dbb3fc785da44d9f43e1d164a2446d8.png)

#### Nextcloud Proxy Host

```auto
Domain Names: cloud.yourdomain.com
Scheme: http
Forward Hostname: nextcloud
Forward Port: 80
Advanced: Enable WebSocket Support

```

 ![image](https://forum-cdn.hhf.technology/original/1X/81a1f0a10a1d343721617bdef7832c3dce68a11b.png)

 ![image](https://forum-cdn.hhf.technology/original/1X/b6706e6c4bd5409a6815e5b381d0db3c045012fc.png)

##### Nextcloud Configuration

```nginx
location / {
    proxy_pass http://nextcloud:80;
    proxy_set_header Host $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;
    
    # Nextcloud-specific headers
    proxy_set_header X-Forwarded-Host $host;
    client_max_body_size 512M;
    
    # WebDAV support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

```

#### Gitea Proxy Host

```auto
Domain Names: git.yourdomain.com
Scheme: http
Forward Hostname: gitea
Forward Port: 3000
Advanced: Enable WebSocket Support

```

 ![image](https://forum-cdn.hhf.technology/original/1X/cfc3821d12ae4391aa23ed3feaccd9ae7987742f.png)  
 ![image](https://forum-cdn.hhf.technology/original/1X/c8ea87e7ce72edc69cb8ed3c08feede6e9f8ed83.png)

#### Gitea Configuration

```nginx
location / {
    proxy_pass http://gitea:3000;
    proxy_set_header Host $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;
    
    # Git-specific settings
    proxy_set_header X-Forwarded-Host $host;
    client_max_body_size 512M;
    
    # WebSocket support for Gitea
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

```

#### WordPress Proxy Host

```auto
Domain Names: blog.yourdomain.com
Scheme: http
Forward Hostname: wordpress
Forward Port: 80

```

 ![image](https://forum-cdn.hhf.technology/original/1X/5cd681a5923380f4f406ccb294ad4b2a103e7da6.png)

 ![image](https://forum-cdn.hhf.technology/original/1X/e0385caf602cc770bd7bc8a17de2aafa07d79a32.png)

#### WordPress Configuration

```nginx
location / {
    proxy_pass http://wordpress:80;
    proxy_set_header Host $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;
    
    # WordPress-specific settings
    client_max_body_size 128M;
    proxy_read_timeout 90;
}

```

 ![image](https://forum-cdn.hhf.technology/original/1X/6383161eb266cc9b8a92610bcbc29abe96b8cc65.png)  
 ![image](https://forum-cdn.hhf.technology/original/1X/6a34998ed1b35984a2677c91d02d4d74c7254f1f.png)

### Starting the Infrastructure

1. Launch the stack:

2. Verify services:

3. Check Newt connection:

## Imp-- Pangolin and NPM Integration - Understanding Network Architecture

When connecting services through Pangolin and NPM, we need to consider two distinct scenarios: services that run inside our Docker network stack and services that run outside of it. Let’s understand both approaches.

## Internal Services (Within Docker Network)

When your applications run inside the same Docker network as NPM, they communicate using Docker’s internal networking. In this case:

```yaml
networks:
  npm_network:
    external: true 

services:
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    ports:
      - '89:80' # External mapping
      - '449:443' # External mapping
      - '81:81' # Admin interface
    networks:
      - npm_network

  nextcloud:
    image: nextcloud:latest
    container_name: nextcloud
    networks:
      - npm_network # Same network as NPM

```

In Pangolin, configure your resource like this:

```auto
Name: Nextcloud
Target Configuration:
- Method: HTTP
- IP/Hostname: nginx-proxy-manager
- Port: 80 # Internal Docker port, not the mapped port

```

This works because both containers can communicate directly through Docker’s internal network, where NPM listens on its default port 80.

## External Services (Outside Docker Network)

For services running outside the Docker network (like on your local network or another server), we need to use the external mapped ports:

```yaml
services:
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    ports:
      - '89:80' # This mapping becomes important

```

In Pangolin, configure your resource like this:

```auto
Name: External Service
Target Configuration:
- Method: HTTP
- IP/Hostname: 10.24.7.96 # Actual IP of the server
- Port: 89 # External mapped port

```

Here, we use port 89 because the service must connect through NPM’s external interface, not through Docker’s internal networking.

## Understanding the Difference

Let’s break down why this matters:

1. Internal Services:

2. External Services:

Here’s a practical example combining both approaches:

```yaml
services:
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    ports:
      - '89:80'
      - '449:443'
    networks:
      - npm_network

  # Internal service example
  wordpress:
    image: wordpress:latest
    networks:
      - npm_network

# Pangolin configurations:

# For WordPress (internal)
Resource 1:
  Name: WordPress
  Target: nginx-proxy-manager:80

# For External App(Uptime Kuma)
Resource 2:
  Name: UPTIME
  Target: 10.24.7.96:89

```

 ![image](https://forum-cdn.hhf.technology/original/1X/a8302bdd09242a139b4a291b4f2d85fb091805f5.png)

This understanding helps you properly configure your resources in Pangolin based on where your services are located relative to your NPM installation. Remember: internal services use port 80, external services use port 89.

The key is remembering that Docker’s internal networking operates independently of the port mappings we create for external access. This is why internal services can use the default ports while external services must use the mapped ports.

### Post-Deployment Verification

1. Access each application through its domain
2. Verify SSL certificates are working
3. Test Pangolin authentication
4. Confirm application functionality

### Maintenance Procedures

Regular maintenance tasks:

1. Update containers:

2. Backup volumes:

3. Monitor logs:

This setup provides a secure, maintainable infrastructure for hosting multiple applications behind Pangolin’s secure tunnel and NPM’s reverse proxy. The configuration can be extended to add more applications as needed, with each benefiting from the central authentication and SSL termination provided by Pangolin.

---

<div class="post-metadata">

**Author:** ![arneym8](https://forum.hhf.technology/letter_avatar_proxy/v4/letter/a/59ef9b/32.png) [@arneym8](https://forum.hhf.technology/u/arneym8)\
**Post date:** [March 27, 2025, 9:07pm UTC](https://forum.hhf.technology/t/complete-guide-secure-application-deployment-with-pangolin-and-npm/475/2 "2025-03-27T21:07:34Z")

</div>

This looks great. Can I do this with Traefik instead of NPM or does that conflict with the Traefik instance that lives in Pangolin on the VPS? Mind that I’d setup Traefik on Unraid (Newt is also on Unraid, rest of Pangolin on the VPS).

---

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [March 28, 2025, 12:11am UTC](https://forum.hhf.technology/t/complete-guide-secure-application-deployment-with-pangolin-and-npm/475/3 "2025-03-28T00:11:50Z")

</div>

yes you can do that, or with any proxy. remember ssl termination matters the most and you will have to handles your domains accordingly.
