Access control
Ferron supports several access control patterns. These range from simple IP-based block/allow rules to authenticated areas with HTTP Basic Authentication or an external authentication backend.
Test restrictive rules with a temporary endpoint first to avoid locking yourself out. Prefer location matches when possible. Use conditional matchers only when you need pattern matching.
Restrict a path by client IP (block/allow)#
Use block and allow directives to control access by IP or CIDR range:
# Replace "example.com" with your domain name.
example.com {
location / {
root /var/www/html
}
# Only allow these networks to access /admin; everyone else gets 403.
location /admin {
allow "203.0.113.0/24" "2001:db8:1234::/48"
root /var/www/admin
}
}When you configure allow, only the listed IPs/CIDRs receive permission. All others receive a 403 Forbidden response.
If Ferron is behind a reverse proxy/load balancer, configure client_ip_from_header. This makes sure IP-based rules use the client IP instead of the proxy IP. See HTTP host directives.
Combined block and allow#
When you configure both block and allow:
- If the IP matches an
allowentry and ablockentry → blocked (block takes precedence) - If the IP matches only an
allowentry → allowed - If the IP matches only a
blockentry → blocked - If the IP matches neither → allowed (unless the allow list is non-empty)
example.com {
root /var/www/html
allow "192.168.1.0/24"
block "192.168.1.100"
}In this example: 192.168.1.50 → allowed, 192.168.1.100 → blocked, 10.0.0.1 → denied.
Block sensitive paths globally#
Use a global block to deny access across all hosts:
* {
# Block known abusive addresses globally.
block "198.51.100.10" "203.0.113.0/24"
}Protect an area with Basic Auth#
Use the basic_auth directive to require HTTP Basic Authentication:
# Replace "example.com" with your domain name.
example.com {
location / {
root /var/www/html
}
location /admin {
basic_auth {
realm "Admin Area"
users {
admin "$argon2id$v=19$m=19456,t=2,p=1$..."
}
}
root /var/www/admin
}
}Ferron supports only hashed passwords. Ferron accepts the following hash formats:
| Prefix | Algorithm |
|---|---|
$argon2id$ | Argon2id (recommended) |
$argon2i$ | Argon2i |
$argon2d$ | Argon2d |
$pbkdf2$ | PBKDF2 |
$pbkdf2-sha256$ | PBKDF2-SHA256 |
$scrypt$ | scrypt |
For Basic Auth, always use TLS. The Authorization header sends credentials on every request.
Brute-force protection#
Brute-force protection is enabled by default:
example.com {
location /admin {
basic_auth {
realm "Admin Area"
users {
admin "$argon2id$v=19$m=19456,t=2,p=1$..."
}
brute_force_protection {
max_attempts 5
lockout_duration "15m"
window "5m"
}
}
}
}Conditional access control#
Use named matchers with if/if_not for more complex access control logic:
match internal_network {
request.header.x_forwarded_for ~ "^10\\.0\\.0\\."
}
example.com {
location /admin {
if_not internal_network {
abort
}
root /var/www/admin
}
}This aborts the connection for any request that does not come from the 10.0.0.0/8 network.
Deny access to sensitive files#
Use conditional matching to block access to dotfiles and sensitive paths:
match sensitive_path {
request.uri.path ~ "^/(?:\\.|config|private|backup)"
}
example.com {
root /var/www/html
if sensitive_path {
status 403 {
body "Access denied"
}
}
}Forwarded authentication#
For external authentication, use the auth_to directive to forward each request to an authentication backend:
example.com {
auth_to http://auth.example.com/auth
root /var/www/html
}When the backend returns a success status (2xx), the request continues. On failure (4xx/5xx), Ferron returns the response of the backend to the client. You can copy headers from the auth response to the original request for downstream use:
api.example.com {
auth_to http://auth.example.com/validate {
copy X-Auth-User X-Auth-Roles
}
proxy http://backend:8080
}For full configuration details, see Forwarded authentication.