Skip to content
Back to skills

Nginx Swag Proxy Config

ASecurity

Use when: creating NGINX reverse proxy configurations for SWAG, deploying subdomain proxy templates, checking LinuxServer reverse-proxy-confs for pre-built configs, or configuring proxy pass rules for Docker services behind SWAG internal proxy.

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 1, 2026
devopsdockergitapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 28, 2026

npx -y skills add jimmybish/homelab --skill nginx-swag-proxy-config --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nginx Swag Proxy Config?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Nginx Swag Proxy Config
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jimmybish-nginx-swag-proxy-config/badge)](https://www.skillsdirectory.com/skills/jimmybish-nginx-swag-proxy-config)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: nginx-swag-proxy-config
description: 'Use when: creating NGINX reverse proxy configurations for SWAG, deploying subdomain proxy templates, checking LinuxServer reverse-proxy-confs for pre-built configs, or configuring proxy pass rules for Docker services behind SWAG internal proxy.'
---

# NGINX / SWAG Reverse Proxy Configuration

Patterns for creating and deploying NGINX reverse proxy configurations via SWAG (Secure Web Application Gateway) for Docker services.

## Environment Overview

This environment runs **two SWAG reverse proxy instances** on the same host (`proxy_host`):

| Instance | Container Name | Config Folder | Purpose |
|----------|---------------|---------------|---------|
| **Internal** | `swag_internal` | `{{ proxy_folder }}/internal/` | LAN traffic — services accessed via `<service>.{{ internal_domain }}` |
| **External** | `swag_external` | `{{ proxy_folder }}/external/` | Externally incoming traffic from the internet |

- NGINX proxy configs are placed under `<folder>/nginx/proxy-confs/`
- Most services only need an internal proxy config
- External configs are only added for services that need public internet access. Ask the user if unsure whether external access is needed, never assume it is.

## When to Use

- A service has a web interface that needs to be accessible via `<service>.{{ internal_domain }}`
- Creating a `<service>.subdomain.conf.j2` template for an Ansible role
- Deploying a proxy config to the SWAG internal or external instance
- Adapting a LinuxServer pre-built NGINX config for your environment

## Check for Existing Configs First

**IMPORTANT: Always check LinuxServer before writing a custom config!**

- Visit: `https://github.com/linuxserver/reverse-proxy-confs`
- Search for your application name (e.g., "grafana", "sonarr", "uptime-kuma")
- If a configuration exists, use it as the basis for your template (may need minor adjustments)
- These configs are battle-tested and include proper headers, websocket support, and security settings

**Example:** For Grafana, a pre-built config exists at:
`https://github.com/linuxserver/reverse-proxy-confs/blob/master/grafana.subdomain.conf.sample`

## Subdomain Config Template

If no pre-built configuration exists, create `templates/<service>.subdomain.conf.j2`:

```nginx
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name <service>.{{ internal_domain }};

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app {{ <service>_proxy_ip }};
        set $upstream_port {{ <service>_port }};
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
```

## Tips for Adapting LinuxServer Configs

- Replace hardcoded IPs with `{{ <service>_proxy_ip }}`
- Replace hardcoded ports with `{{ <service>_port }}`
- Keep all the special headers and proxy settings (they're there for a reason!)
- Maintain websocket support blocks if present (required for real-time features)
- Keep security headers and authentication blocks

## Ansible Deployment Tasks

Add these to `tasks/main.yaml` after the health check.

### Internal Proxy (most services)

```yaml
# Configure SWAG Internal Proxy (REQUIRED for web interfaces)
- name: Resolve service host IP for proxy configuration
  ansible.builtin.set_fact:
    <service>_proxy_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"

- name: Deploy service nginx config to SWAG Internal
  ansible.builtin.template:
    src: <service>.subdomain.conf.j2
    dest: "{{ proxy_folder }}/internal/nginx/proxy-confs/<service>.subdomain.conf"
    mode: '0664'
  delegate_to: "{{ groups['proxy_host'][0] }}"
  notify:
    - Restart Swag Internal
```

### External Proxy (only if public internet access is needed)

```yaml
- name: Deploy service nginx config to SWAG External
  ansible.builtin.template:
    src: <service>.subdomain.conf.j2
    dest: "{{ proxy_folder }}/external/nginx/proxy-confs/<service>.subdomain.conf"
    mode: '0664'
  delegate_to: "{{ groups['proxy_host'][0] }}"
  notify:
    - Restart Swag External
```

### Cloudflare DNS record type migrations

`community.general.cloudflare_dns` with `solo: true` only removes records that
have the same name **and type**. It cannot replace an existing `A` record with
a `CNAME` in one task because Cloudflare rejects the conflicting record types.
Before creating the CNAME, query Cloudflare for same-name `A` records and
delete their record IDs with authenticated `ansible.builtin.uri` tasks. Mark
all API tasks `no_log: true`, delegate them to localhost, and assert that the
zone lookup returned exactly one zone before deleting anything.

SWAG normalizes files in its proxy-confs directories to mode `0664` at startup. Set
that mode in Ansible templates to prevent a mode-only change and container restart on
every deployment.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.