Skip to content
2 changes: 1 addition & 1 deletion docs/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ It's designed for developers who want to:

## Key Features

- 🔒 **Access Control** — Protect your Signal API with [**token-based authentication**](./usage#auth) and [**endpoint restrictions**](./features#endpoints).
- 🔒 **Access Control** — Protect your Signal API with [**token-based authentication**](./usage#auth), [**endpoint restrictions**](./features#endpoints) and [**IP filters**](./features#ip-filters).
- 🧩 **Full Compatibility** — 100% protocol-compatible; all requests are still handled by your existing Signal CLI REST API.
- ⚙️ **Configurable Proxy Behavior** — Define templates and limits via YAML or environment variables.
- 🧠 **Message Templates** — Use [**variables**](./configuration/variables) and [**placeholders**](./features#placeholders) to standardize common message formats.
Expand Down
7 changes: 4 additions & 3 deletions docs/best-practices/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ Here are some common best practices for running **Secured Signal API**, but thes
## Usage

- Create **separate configs** for each service
- Use [**placeholders**](./usage/advanced#placeholders) extensively _(trust me, they are so useful)_
- Always keep your stack **up-to-date** _(this is why we have Docker)_
- Use [**placeholders**](./usage/advanced#placeholders) extensively
- Always keep your stack **up-to-date**

## Security

- Always use **API tokens** in production
- Run behind a [**tls-enabled reverse proxy**](./reverse-proxy)
- Be cautious when overriding [**blocked endpoints**](./features#endpoints)
- Use per-token overrides to **enforce least privilege**
- Always allow the least possible access points
- Always allow the least possible [**endpoints**](./features#endpoints)
- Only allow access from [**IPs**](./features#ip-filter) **you trust**
20 changes: 15 additions & 5 deletions docs/configuration/endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,18 @@ By default, adding an endpoint explicitly allows access to it, use `!` to block
> [!IMPORTANT]
> When using `!` to block you must enclose the endpoint in quotes, like in the example above

| Config (Allow) | (Block) | Result | | | |
| :------------- | :------------- | :--------: | --- | :---------------: | --- |
| `/v2/send` | `unset` | **all** | 🛑 | **`/v2/send`** | ✅ |
| `unset` | `!/v1/receive` | **all** | ✅ | **`/v1/receive`** | 🛑 |
| `!/v2*` | `/v2/send` | **`/v2*`** | 🛑 | **`/v2/send`** | ✅ |
## Behavior

| Allow | Block | Result |
| ---------- | -------------- | -------------------------------------------- |
| `/v2/send` | — | **Only** `/v2/send` allowed |
| — | `!/v1/receive` | **All** allowed **except** `/v1/receive` |
| `/v2/send` | `!/v2/*` | `/v2*` allowed **except** `/v2/send` blocked |

### Rules

- Default: **allow all**
- Allow rules add explicit access
- Block rules deny matching endpoints
- Explicit allow overrides block
- Mixed allow + block rules keep permissive default
18 changes: 14 additions & 4 deletions docs/configuration/examples/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Example Config (all configurations shown)
service:
port: 8880
hostnames:
- mydomain.com

api:
url: http://signal-api:8080
Expand All @@ -24,12 +26,20 @@ settings:
"@message": [{ field: "msg", score: 100 }]

access:
trustedIPs:
- 192.168.1.10

trustedProxies:
- 172.20.0.100

ipFilter:
- 192.168.1.10
- 192.168.2.0/24
- "!192.168.2.44"

endpoints:
- "!/v1/about"
- /v2/send

fieldPolicies:
"@number": {
value: "+123400003",
action: block
}
"@number": { value: "+123400003", action: block }
21 changes: 21 additions & 0 deletions docs/configuration/hostnames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Hostnames
---

# Hostnames

Hostnames can be set to create isolated realms or to restrict access by limiting to a only a small subset of hostnames.

Add hostnames, that are allowed to be used in `service.hostnames`. (default: all)

```yaml
service:
hostnames:
- mydomain.com
```

## Usage behind Proxy

For clients behind proxies IPs cannot be reliably determined without using the `X-Forwarded-Proto`, `X-Forwarded-Host` and `X-Forwarded-Port` HTTP headers.

For **Secured Signal API** to trust a proxy it must be added to the trusted proxies, read more [here](./trusted-proxies).
63 changes: 63 additions & 0 deletions docs/configuration/ip-filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: IP Filters
---

# IP Filters

Restrict access to your **Secured Signal API** based on client IP addresses.

IP filtering allows you to explicitly **allow** or **block** requests originating from specific IPs or CIDR ranges.

## Default

By default, **all IP addresses are allowed**.

No IP-based restrictions are applied unless `access.ipFilter` is configured.

## Customize

You can modify IP access rules by configuring `access.ipFilter` in your config:

```yaml
settings:
access:
ipFilter:
- "!123.456.78.9"
- "!234.567.89.0/24"
- 192.168.1.10
- 10.0.0.0/24
```

By default, adding an IP or range explicitly allows it, use `!` to block it instead.

> [!IMPORTANT]
> When using `!` to block an IP or range, you must enclose it in quotes

**Supports:**

- Single IPv4 / IPv6 addresses
- CIDR notation (`10.0.0.0/24`, `2001:db8::/32`)

## Behavior

| Allow | Block | Result |
| -------------- | ------------------------ | ----------------------------------------- |
| `192.168.1.10` | — | Only `192.168.1.10` allowed |
| — | `!123.456.78.9` | All allowed, except `123.456.78.9` |
| `10.0.0.0/24` | `!10.0.0.10` | `10.0.0.0/24` allowed, except `10.0.0.10` |
| — | `!0.0.0.0/0`<br/>`!::/0` | All IPv4 & IPv6 blocked |

### Rules

- Default: **allow all**
- Allow rules restrict access **only if no block rules exist**
- Block rules deny matching IPs
- Explicit allow overrides block
- IPv4 and IPv6 rules may be mixed

## Clients behind Proxies

For clients behind proxies, IPs cannot be reliably determined without trusting the `X-Forwarded-For` HTTP header.
In order for **Secured Signal API** to trust the _XFF_ header it has to trust the request's originating proxy.

Read more about trusted proxies [here](./trusted-proxies).
16 changes: 16 additions & 0 deletions docs/configuration/trusted-ips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Trusted IPs
---

# Trusted IPs

Trusted clients can bypass some security features and are often local or internal IPs.

To trust IPs or ranges add them to `access.trustedIPs`.

```yaml
access:
trustedIPs:
- 192.168.1.10
- 192.168.2.0/24
```
26 changes: 26 additions & 0 deletions docs/configuration/trusted-proxies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: Trusted Proxies
---

# Trusted Proxies

Proxies can be marked as trusted.

Add proxies to be trusted in `access.trustedProxies`.

```yaml
access:
trustedProxies:
- 172.20.0.100
```

## `X-Forwarded-*` Headers

HTTP listeners only get the `proto://host:port/uri` from the incoming request, but proxies often redirect requests causing modified request URLs
`http://sec-signal-api:8880`.

To get the origin URL you have to use the `X-Forwarded-*` headers, but as you might know anyone can set headers (spoofing possible).
This means you should only trust _XF_ headers from trusted sources,
otherwise, malicious actors can change any `X-Forwarded-*` headers to be able to bypass block list, rate limits, hostname restrictions, … .

This also applies to determining the IP of a client behind a proxy, so it is extremely important to allow for using the _XF_ headers when a proxy is trusted.
11 changes: 9 additions & 2 deletions docs/features/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Features

# Features

Here are some of the highlights of using **Secured Signal API**
Here are some of the highlights of using **Secured Signal API**.

## Message Template

Expand All @@ -21,7 +21,7 @@ Look at this complex template for example:
It can extract needed data from the body and headers to then process them using Go's templating library
and finally output a message packed with so much information.

Head to [configuration](./configuration/message-template) to see how-to use.
Head to [Configuration](./configuration/message-template) to see how-to use.

## Placeholders

Expand Down Expand Up @@ -53,4 +53,11 @@ Find more about this feature [here](./configuration/field-policies).
> _Block unwanted access_

**Endpoints** are used for restricting unauthorized access and for ensuring least privilege.

[Let's start blocking then!](./configuration/endpoints)

## IP Filters

**IP Filters** are used for restricting access to **Secured Signal API** by blocking or specifically allowing IPs and CIDR ranges.

Configure your _mini firewall_ [here](./configuration/ip-filters).
13 changes: 13 additions & 0 deletions docs/reverse-proxy/caddy/caddy.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,25 @@ Add Caddy to your `docker-compose.yaml` file.
{{{ #://./examples/caddy.docker-compose.yaml }}}
```

## Setup

Create a `Caddyfile` in your `docker-compose.yaml` folder and mount it to `/etc/caddy/Caddyfile` in your Caddy container.

```apacheconf
{{{ #://./examples/Caddyfile }}}
```

## Configuration

Now you can switch over to **Secured Signal API** and add Caddy to your [trusted proxies](../../configuration/trusted-proxies.md):

```yaml
settings:
access:
trustedProxies:
- 172.20.0.100
```

Then spin up your stack:

```bash
Expand Down
4 changes: 4 additions & 0 deletions docs/reverse-proxy/caddy/examples/caddy.docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ services:
- data:/data
depends_on:
- secured-signal
restart: unless-stopped
networks:
backend:
ipv4_address: 172.20.0.100

networks:
backend:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ services:
restart: unless-stopped
networks:
backend:
ipv4_address: 172.20.0.100

networks:
backend:
13 changes: 13 additions & 0 deletions docs/reverse-proxy/nginx/nginx.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ To implement Nginx in front of **Secured Signal API** you need to update your `d

To include the needed mounts for your certificates and your config.

## Setup

Create a `nginx.conf` file in the `docker-compose.yaml` folder and mount it to `/etc/nginx/conf.d/default.conf` in your Nginx container.

```apacheconf
Expand All @@ -32,6 +34,17 @@ Create a `nginx.conf` file in the `docker-compose.yaml` folder and mount it to `

Add your `cert.key` and `cert.crt` into your `certs/` folder and mount it to `/etc/nginx/ssl`.

## Configuration

Now you can switch over to **Secured Signal API** and add Nginx to your [trusted proxies](../../configuration/trusted-proxies.md):

```yaml
settings:
access:
trustedProxies:
- 172.20.0.100
```

Lastly spin up your stack:

```bash
Expand Down
17 changes: 16 additions & 1 deletion docs/reverse-proxy/traefik/examples/traefik.docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,22 @@ services:
aliases:
- secured-signal-api

traefik:
image: traefik:latest
container_name: traefik
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./config/traefik.yaml:/etc/traefik/traefik.yaml:ro
- certs:/var/traefik/certs/:rw
- logs:/var/log/traefik
restart: unless-stopped
networks:
proxy:
ipv4_address: 172.20.0.100

networks:
backend:
proxy:
external: true
13 changes: 13 additions & 0 deletions docs/reverse-proxy/traefik/traefik.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,21 @@ To implement Traefik in front of **Secured Signal API** you need to update your

To include the Traefik router and service labels.

## Configuration

Now you can switch over to **Secured Signal API** and add Traefik to your [trusted proxies](../../configuration/trusted-proxies.md):

```yaml
settings:
access:
trustedProxies:
- 172.20.0.100
```

Then restart **Secured Signal API**:

```bash
docker compose down && docker compose up -d
```

That's it, have fun!