Skip to content

Usage Examples

DenAV edited this page Mar 19, 2026 · 4 revisions

Usage Examples

How the role works

The npm-management role connects to the NPM REST API from your local machine (Ansible control node) and manages proxy hosts remotely. The target NPM server only needs Docker — Ansible is never installed on it.

There are two ways to manage proxy hosts:

Mode When to use How
Single host One domain at a time Set npm_api_domain_name and npm_api_host
Batch Multiple domains in one run Provide a list in npm_api_hosts

Both modes are used through the role — you typically don't need to call the npm_proxy module directly (see Advanced usage if you do).


Single host

Edit the main playbook pl_npm-management.yml with the desired variables, or pass them via --extra-vars.

HTTP only (no SSL)

The simplest case — create a reverse proxy without a certificate.

Option A — edit the playbook directly:

# pl_npm-management.yml
- name: NPM - create proxy host (HTTP)
  hosts: localhost
  gather_facts: no
  roles:
    - role: npm-management
      npm_api_domain_name: "site.example.com"
      npm_api_host: "172.16.1.10"
ansible-playbook pl_npm-management.yml --ask-vault-pass

Option B — keep the playbook generic, pass variables at runtime:

ansible-playbook pl_npm-management.yml --ask-vault-pass \
  -e "npm_api_domain_name=site.example.com" \
  -e "npm_api_host=172.16.1.10"

Result: site.example.com172.16.1.10:80 over HTTP.

With SSL (Let's Encrypt)

To enable HTTPS with an auto-provisioned Let's Encrypt certificate, set ssl_forced and provide an email:

# pl_npm-management.yml
- name: NPM - create proxy host with SSL
  hosts: localhost
  gather_facts: no
  roles:
    - role: npm-management
      npm_api_domain_name: "secure.example.com"
      npm_api_host: "172.16.1.20"
      npm_api_ssl_forced: true
      npm_api_letsencrypt_email: "admin@example.com"

Important: letsencrypt_email is required when ssl_forced: true. Without it, the certificate request will fail. DNS must already point to the server, and ports 80/443 must be open.

Custom forward port

If the backend service runs on a non-standard port:

# pl_npm-management.yml
- name: NPM - proxy to custom port
  hosts: localhost
  gather_facts: no
  roles:
    - role: npm-management
      npm_api_domain_name: "app.example.com"
      npm_api_host: "172.16.1.30"
      npm_api_host_port: 8080
      npm_api_ssl_forced: true
      npm_api_letsencrypt_email: "admin@example.com"

Result: app.example.com172.16.1.30:8080.

Delete a proxy host

Set state: absent to remove a proxy host. If the host has an SSL certificate, it is deleted automatically:

# pl_npm-management.yml
- name: NPM - delete proxy host
  hosts: localhost
  gather_facts: no
  roles:
    - role: npm-management
      npm_api_domain_name: "old-site.example.com"
      npm_api_host: "172.16.1.10"
      npm_api_state: absent

Or via --extra-vars:

ansible-playbook pl_npm-management.yml --ask-vault-pass \
  -e "npm_api_domain_name=old-site.example.com" \
  -e "npm_api_host=172.16.1.10" \
  -e "npm_api_state=absent"

Batch operations

To manage multiple proxy hosts in a single playbook run, use npm_api_hosts instead of individual variables. Define the list in a separate file (group_vars/, host_vars/) or pass it via --extra-vars.

When npm_api_hosts is set, the role ignores npm_api_domain_name / npm_api_host and processes the list instead.

Example: mixed SSL and non-SSL hosts

Create a variables file with the host list:

# group_vars/npm.yml
npm_api_letsencrypt_email: "admin@example.com"

npm_api_hosts:
  - domain_name: "internal.example.com"
    host: "172.16.1.10"
    ssl_forced: false

  - domain_name: "public.example.com"
    host: "172.16.1.20"
    ssl_forced: true

  - domain_name: "app.example.com"
    host: "172.16.1.30"
    host_port: 3000
    ssl_forced: true

The playbook itself stays simple — no changes needed:

# pl_npm-management.yml
- name: NPM - batch manage proxy hosts
  hosts: localhost
  gather_facts: no
  roles:
    - role: npm-management

The role detects that npm_api_hosts is not empty and switches to batch mode automatically.

How the two-phase split works

The role automatically separates the list into two execution phases:

npm_api_hosts list
       │
       ├─── ssl_forced: false ──► Phase 1: WITHOUT SSL
       │                          • Runs in parallel (no throttle)
       │                          • Timeout: 30 seconds
       │                          • Fast — no certificate needed
       │
       └─── ssl_forced: true ───► Phase 2: WITH SSL
                                  • Runs sequentially (throttle: 1)
                                  • Timeout: 120 seconds
                                  • Each host triggers certbot (10-30s)

Why sequential for SSL? Each Let's Encrypt certificate request runs certbot inside NPM, which takes 10-30 seconds. Running multiple SSL requests in parallel causes timeouts or Let's Encrypt rate-limit errors.

You do not need to split the list manually — the role filters automatically based on each item's ssl_forced value (falling back to the global npm_api_ssl_forced default).

Example: all hosts with SSL

If every host needs SSL, set the global defaults and keep the list simple:

# group_vars/npm.yml
npm_api_ssl_forced: true
npm_api_letsencrypt_email: "admin@example.com"

npm_api_hosts:
  - domain_name: "site-a.example.com"
    host: "172.16.1.10"
  - domain_name: "site-b.example.com"
    host: "172.16.1.20"
  - domain_name: "site-c.example.com"
    host: "172.16.1.30"

All hosts inherit ssl_forced: true → all run sequentially in phase 2.

Example: batch delete

npm_api_hosts:
  - domain_name: "old-a.example.com"
    host: "172.16.1.10"
    state: absent
  - domain_name: "old-b.example.com"
    host: "172.16.1.20"
    state: absent

Batch item properties

Property Required Default Description
domain_name yes Domain name for the proxy host
host yes Forward hostname / IP
host_port no 80 Forward port
ssl_forced no npm_api_ssl_forced Enable SSL (determines execution phase)
letsencrypt_email no npm_api_letsencrypt_email Email for Let's Encrypt
state no npm_api_state present or absent

Ansible Vault

Store NPM credentials in an encrypted vault file:

# Create the vault file
ansible-vault create roles/npm-management/vars/api_secret.yml

Add:

---
npm_user: admin@example.com
npm_password: your-npm-password

Run the playbook with vault:

# Interactive password prompt
ansible-playbook pl_npm-management.yml --ask-vault-pass

# Password file (for CI/CD)
ansible-playbook pl_npm-management.yml --vault-password-file .vault-pass

Advanced: using the module directly

For edge cases where the role doesn't fit (custom task flow, conditional logic, dynamic inventory), you can call the npm_proxy module directly. You are responsible for obtaining the API token yourself.

- name: Get NPM access token
  uri:
    url: "http://npm.example.com:81/api/tokens"
    method: POST
    body_format: json
    body:
      identity: "{{ npm_user }}"
      secret: "{{ npm_password }}"
  register: npm_access_token
  delegate_to: localhost

- name: Create proxy host directly
  npm_proxy:
    url: "http://npm.example.com:81/api"
    token: "{{ npm_access_token.json.token }}"
    domain: "custom.example.com"
    host: "172.16.1.50"
    host_port: 9090
    ssl_forced: true
    letsencrypt_email: "admin@example.com"
    state: present
  delegate_to: localhost

Recommendation: Use the role for standard operations. It handles credential validation, API health checks, token management, and the SSL/non-SSL execution split automatically.


Reference

What the role does on each run

  1. Loads credentials from vars/api_secret.yml (Ansible Vault)
  2. Validates that npm_user and npm_password are set
  3. Checks NPM API health (retries 6×, 10s delay)
  4. Obtains an API token (POST /api/tokens) — token is not persisted
  5. Executes proxy host operations (single or batch)

Module return values

Scenario msg changed
Host created Proxy-host site.example.com created true
Host already exists Proxy Host site.example.com already exists false
Host deleted Proxy-host: site.example.com removed. true
Error Failed to create proxy_host ... (HTTP 500): ... — (failed: true)