---
name: cloudflare-proxied-domain-npm-subpath
description: Cloudflare-proxied domains without an NPM proxy host have no nginx config — NPM Custom Locations cannot be added; requires a separate subdomain
type: concept
---

# Nginx Proxy Manager — Custom Locations Don't Work for Cloudflare-Only Domains

## The Setup

A typical homelab has two categories of external domains:

1. **NPM-managed domains**: Domain → Cloudflare → NPM → internal service. NPM generates a full nginx vhost config.
2. **Cloudflare-only domains**: Domain → Cloudflare → directly to internal IP (Cloudflare Full/Strict mode, or just DNS). No NPM entry exists.

## The Problem

NPM's "Custom Locations" feature lets you add path-based routing to an existing Proxy Host:

```
nextcloud.ai-impress.com/push/  →  http://localhost:7867
```

But this only works if a Proxy Host entry for `nextcloud.ai-impress.com` exists in NPM. If the domain goes directly through Cloudflare to the Nextcloud server, **NPM has no nginx config file for it**. There is no vhost to attach a Custom Location to.

You cannot add a Custom Location for a domain that has no NPM Proxy Host.

## Real Example — Nextcloud Signaling Server

The `nextcloud.ai-impress.com` domain was accessed via Cloudflare without a matching NPM proxy host. Attempting to add `nextcloud.ai-impress.com/push/` as a custom location to route WebSocket traffic to the `strukturag/nextcloud-spreed-signaling` server failed — there was no NPM entry to attach it to.

### Incorrect Approach

```
Existing NPM host:  (none for nextcloud.ai-impress.com)
Attempt: Add Custom Location → /push/ → localhost:8083
Result: Error — no proxy host to add location to
```

### Correct Approach

Create a **separate subdomain** with its own NPM Proxy Host entry:

```
NPM Proxy Host #39:
  Domain:  signal.ai-impress.com
  Forward: localhost:8083 (signaling server)
  SSL:     Let's Encrypt
  WebSocket support: enabled

Nextcloud config (config.php):
  'signaling_servers' => [
    ['url' => 'wss://signal.ai-impress.com']
  ]
```

## General Rule

| Domain routing | NPM Custom Locations available? |
|---------------|----------------------------------|
| Domain → NPM → service (NPM manages SSL) | Yes |
| Domain → Cloudflare → NPM → service | Yes (NPM has the entry) |
| Domain → Cloudflare → direct IP (no NPM) | **No** — NPM has no vhost for this domain |

## HTTP 404 from Signaling Server (Not an Error)

A related diagnostic: the `strukturag/nextcloud-spreed-signaling` server returns HTTP 404 when accessed without a WebSocket upgrade header. This is normal and expected behavior — the server only handles WebSocket connections, not plain HTTP GET requests. A 404 from a curl to the signaling URL does not indicate misconfiguration.

```bash
curl https://signal.ai-impress.com/spreed
# → 404 Not Found (expected — WebSocket upgrade required)
```

Test the WebSocket connection instead:
```bash
wscat -c wss://signal.ai-impress.com/spreed
```

## Container Config Path Mismatch (strukturag/nextcloud-spreed-signaling)

The signaling server container expects its config at `/config/server.conf`, not `/etc/signaling/server.conf`. Mount accordingly:

```yaml
volumes:
  - ./signaling/server.conf:/config/server.conf:ro
```

**Source:** daily/2026-05-09.md | 2026-05-09
