Advanced Topics
Access Control
Configure access control for GoDoxy
GoDoxy implements access control at two distinct network layers, each operating at different points in the request lifecycle:
| Layer | Description | Blocking Behavior |
|---|
| Layer 4 (TCP/UDP) | IP filtering when connection is established | Connection dropped immediately |
| Layer 7 (HTTP) | IP filtering when HTTP request is fully received | HTTP error response returned |
Transport-layer filtering before HTTP data exchange. Blocked IPs see immediate connection drop with no response.
| Use Case |
|---|
| Blocking scanners early |
| Type | Example | MaxMind Credentials Required |
|---|
| IP address | ip:1.2.3.4 | No |
| CIDR | cidr:1.2.3.4/32 | No |
| ISO country code | country:US | Yes |
| Timezone | tz:Asia/Shanghai | Yes |
| Key | Type | Description | Default |
|---|
default | allow or deny | Default action | allow |
allow_local | bool | Allow local addresses | true |
allow | Filter List | Allow list | [] |
deny | Filter List | Deny list | [] |
log | object | Log configuration with extra log_allowed field | {} |
notify | object | Periodically send access summary to notification provider | {} |
| Key | Type | Description | Required | Default |
|---|
to | string list | List of notification provider names | No | [] |
interval | duration | Interval between notifications | No | 1m |
include_allowed | bool | Include allowed connections in notification | No | false |
# config.yml
acl:
default: allow # or deny (default: allow)
allow_local: true # or false (default: true)
allow:
- ip:1.2.3.4
- cidr:1.2.3.4/32
- country:US
- tz:Asia/Shanghai
deny:
- ip:1.2.3.4
- cidr:1.2.3.4/32
- country:US
- tz:Asia/Shanghai
log:
buffer_size: 65536 # (default: 64KB)
path: /app/logs/acl.log # (default: none)
stdout: false # (default: false)
keep: last 10 # (default: none)
log_allowed: true # (default: false)
notify:
to: [discord]
interval: 1h
include_allowed: true
providers:
maxmind:
account_id: 123456
license_key: your-license-key
database: geolite # or geoip2 if you have subscription
notification:
- name: discord
provider: discord
url: https://discord.com/api/webhooks/1234567890/abcdefghijklmnopqrstuvwxyz
token: your-token
HTTP-level filtering after request headers/body received. Blocked IPs see HTTP 403 error response.
| Use Case |
|---|
| Traffic that requires feedback |
HTTP Access loggers can be configured - in config.yml under entrypoint
section - per route in docker labels or route files
| Key | Type | Description | Required | Default |
|---|
allow | IP/CIDR list | Allow list | No | [] |
status_code | int | Status code | No | 403 |
message | string | Error message | No | IP not allowed |
# config.yml
entrypoint:
middlewares: # allow only local (private) ips
- use: CIDRWhiteList
allow:
- 127.0.0.1/32
- 172.16.0.0/12
- 192.168.0.0/16
- 10.0.0.0/8
status_code: 403
message: Forbidden
access_log:
format: json
path: /app/logs/access.json.log
filters: # skip logging requests from local (private) ips
cidr:
negative: true
values:
- 127.0.0.1/32
- 172.16.0.0/12
- 192.168.0.0/16
- 10.0.0.0/8
fields:
headers:
default: drop # drop app headers in log
config: # keep only these
X-Real-Ip: keep
CF-Connecting-Ip: keep
X-Forwarded-For: keep
# docker labels
proxy.#1.middlewares.cidr_whitelist: |
allow:
- 10.0.0.0/8
- 192.168.0.0/16
status_code: 403
message: "IP not allowed"
| Key | Type | Description | Allowed Values | Default |
|---|
path | string | Path to the access log file | /var/log/access.log | required |
stdout | bool | Enable stdout logging (can be used with path) | true or false | false |
keep or retention | See below | Retention policy | | 30 days |
rotate_interval | duration | Log rotation interval | Duration | 1h |
To enable log rotation, you may set keep or retention to a retention policy.
Default: 30 days
Format:
{N} days|weeks|months (e.g. 30 days)
{N} KB|MB|GB|kb|mb|gb (e.g. 100 MB for 100 Megabytes, 100 mb for 100 Megabits)
last {N} (e.g. last 10 for last 10 lines)
| Field | Type | Description | Allowed values | Default |
|---|
format | string | access log format | common, combined, json | combined |
filters | object | access log filters (optional) | | |
filters.*.negative | bool | negative filters | true or false | false |
filters.status_codes.values | integer or integer range | status code filters | | |
filters.method.values | string | method filters | GET, POST, ... | |
filters.host.values | string | host filters | hostname | |
filters.headers.values | string | headers filters | case-sensitive key or key=value | |
filters.cidr.values | string | CIDR filters | see below | |
fields | object | access log fields | see below | |
fields.*.default | string (field mode) | default field behavior | keep, drop, redact | See below |
fields.*.config | key:value mapping (key is case-sensitive) | headers fields | key: field_mode | |
fields.headers.config.* | string | headers fields | header: field_mode | |
fields.query.config.* | string | query fields | query: field_mode | |
fields.cookies.config.* | string | cookies fields | cookie: field_mode | |
format affects file logging only.
| Setting | Behavior |
|---|
keep | Field is logged as-is |
drop | Field is excluded from logs |
redact | Field value replaced with REDACTED |
- Multiple access loggers can share the same log file
- Negative filters (
filters.*.negative: true) exclude matching requests from logging
- Query redaction format:
?key=REDACTED
- Redaction for non-query fields requires
format: json
- Default field config:
query.default: keep
cookies.default: drop
headers.default: drop
| Field | Type | Description | Required | Allowed values | Default |
|---|
log_allowed | bool | log when IP is allowed | bool | true or false | false |
# config.yml
entrypoint:
access_log:
format: json
path: /var/log/example.log
filters:
status_codes:
values:
- 200-299
- 101
method:
values:
- GET
host:
values:
- example.y.z
headers:
negative: true
values:
- foo=bar # when key "foo" is present and value is `bar`
- baz # when key "baz" is present
cidr:
values:
- 192.168.10.0/24
fields:
headers:
default: keep
config:
foo: redact
query:
default: drop
config:
foo: keep
cookies:
default: redact
config:
foo: keep
# route file
# same as above, but under your app config, e.g.
app1:
access_log:
format: json
...
# docker labels - string as inline mapping
proxy.app1.access_log: |
format: json
...
# docker labels - full label
proxy.app1.access_log.format: json
proxy.app1.access_log.filters.status_codes.values: 200-299,300
proxy.app1.access_log.fields.headers.config.foo: redact