Skip to main content
Ayase Quart includes comprehensive moderation features for archive administrators. The [moderation] section controls user reporting, post filtering, and content management.

Basic moderation settings

enabled
boolean
default:"true"
Enable moderation features including post hiding, reporting, and admin interface
api
boolean
default:"false"
Enable moderation API endpoints for programmatic access
admin_user
string
default:"admin"
required
Administrator username for login
Change the default username in production
admin_password
string
default:"admin"
required
Administrator password for login
Change the default password in production. Use a strong, unique password.
[moderation]
enabled = true
api = false
admin_user = 'admin'
admin_password = 'admin'

Post reporting and hiding

hide_post_if_reported
boolean
default:"true"
Hide posts immediately when reported by users. Takes precedence over n_reports_then_hide.
n_reports_then_hide
integer
default:"1"
Number of reports from different IP addresses required to automatically hide a post. Only applies if hide_post_if_reported is false.
hide_upstream_deleted_posts
boolean
default:"true"
Hide posts that were deleted by upstream staff (e.g., 4chan moderators) in the live archive
remove_replies_to_hidden_op
boolean
default:"true"
When an OP (original post/thread starter) is hidden, also hide all replies to that thread
[moderation]
hide_post_if_reported = true
n_reports_then_hide = 1
hide_upstream_deleted_posts = true
remove_replies_to_hidden_op = true
Immediate hiding:
hide_post_if_reported = true
n_reports_then_hide = 1
First report immediately hides the post.Threshold-based hiding:
hide_post_if_reported = false
n_reports_then_hide = 3
Requires 3 reports from different IPs before hiding.Manual review only:
hide_post_if_reported = false
n_reports_then_hide = 999999
Reports are tracked but posts are never auto-hidden. Admin must manually review and hide.

Content filtering

regex_filter
string
default:""
Regular expression pattern for filtering posts. Posts matching this pattern will never be served.Example: 'gentoo|based' blocks posts containing “gentoo” or “based”Leave empty ('') to disable regex filtering.
path_to_regex_so
string
default:""
Path to sqlite-regex shared object file for regex filtering support. Download from sqlite-regex releases.Required only when using SQLite as filter cache and regex_filter is not empty.
[moderation]
regex_filter = 'spam|scam|phishing'
path_to_regex_so = '/usr/local/lib/regex0.so'
Test regex patterns carefully. Overly broad patterns may hide legitimate content.

Filter cache storage

The filter cache stores information about reported and hidden posts. Choose between SQLite and Redis.
filter_cache_type
string
default:"sqlite"
Storage backend for filter cacheOptions:
  • sqlite - File-based storage, simpler setup
  • redis - In-memory storage, better performance

SQLite filter cache

[moderation]
filter_cache_type = 'sqlite'

[moderation.sqlite]
database = 'path/to/moderation.db'
database
string
default:"path/to/moderation.db"
required
Path to the SQLite moderation database file. Can be relative or absolute.

Redis filter cache

[moderation]
filter_cache_type = 'redis'

[moderation.redis]
db = 4
fc_key_prefix = 'filter_cache:'
fc_dump_dir = './data/filter_cache/'
bloom_err_rate = 0.01
bloom_init_size = 4_000_000
bloom_resize_mult = 2
cuckoo_capacity = 10_000
cuckoo_bucket = 2000
cuckoo_iter_max = 5
db
integer
default:"4"
Redis database number for filter cache data
fc_key_prefix
string
default:"filter_cache:"
Key prefix for filter cache entries in Redis
fc_dump_dir
string
default:"./data/filter_cache/"
Directory for filter cache persistence/dumps
bloom_err_rate
float
default:"0.01"
Bloom filter false positive rate (1% default). Lower values use more memory but have fewer false positives.
bloom_init_size
integer
default:"4000000"
Initial bloom filter capacity per board. Set based on expected number of hidden posts.
bloom_resize_mult
integer
default:"2"
Growth factor when bloom filter capacity is reached (doubles by default)
cuckoo_capacity
integer
default:"10000"
Total cuckoo filter capacity per board
cuckoo_bucket
integer
default:"2000"
Capacity per cuckoo filter bucket
cuckoo_iter_max
integer
default:"5"
Maximum bucket swaps per (board, num) in cuckoo filter
Bloom filter:
  • Space-efficient probabilistic data structure
  • Fast membership tests
  • May have false positives (controlled by bloom_err_rate)
  • Cannot remove items
Cuckoo filter:
  • Supports deletions
  • More memory efficient at larger sizes
  • Better worst-case lookup performance
  • Used for smaller, more dynamic sets

Hidden images

hidden_images_path
string
default:""
Directory where images from hidden posts should be moved. If empty, images remain accessible via their URLs even when posts are hidden.Example: /home/garbage/disposal
[moderation]
hidden_images_path = '/var/ayase/hidden_media'
Moving images to a hidden directory prevents them from being served, even if users have direct links.

Authentication settings

The [moderation.auth] section controls authentication cookies and bearer tokens for moderation access.
SameSite cookie attribute for CSRF protectionOptions:
  • Strict - Cookies only sent for same-site requests
  • Lax - Cookies sent for top-level navigation
  • None - Cookies sent with all requests (requires cookie_secure = true)
Require HTTPS for auth cookies. Set to true in production with HTTPS.
Always set to true when using HTTPS in production
Prevent JavaScript access to auth cookies (security best practice)
Name of the authentication cookie
Salt for cookie token generation. Change to a random value.
Use a unique, random salt in production
bearer_salt
string
default:"api salt"
required
Salt for API bearer token generation. Change to a random value.
Use a unique, random salt in production
Cookie validity duration in seconds (default: 604800 = 1 week)
bearer_duration
integer
default:"604800"
Bearer token validity duration in seconds (default: 604800 = 1 week)
[moderation.auth]
cookie_samesite = 'Strict'
cookie_secure = true
cookie_http_only = true
cookie_name = 'aq_auth'
cookie_salt = 'random-salt-change-me-12345'
bearer_salt = 'different-random-salt-67890'
cookie_duration = 604_800  # 1 week
bearer_duration = 604_800  # 1 week
Generate random salts using Python:
python -c "import secrets; print(secrets.token_hex(32))"
Or use OpenSSL:
openssl rand -hex 32

Configuration examples

[moderation]
enabled = true
api = true
admin_user = 'admin'
admin_password = 'admin'

hide_post_if_reported = false
n_reports_then_hide = 5
hide_upstream_deleted_posts = false
remove_replies_to_hidden_op = false

filter_cache_type = 'sqlite'
regex_filter = ''
hidden_images_path = ''

[moderation.sqlite]
database = './data/moderation.db'

[moderation.auth]
cookie_samesite = 'Lax'
cookie_secure = false
cookie_http_only = true
cookie_name = 'aq'
cookie_salt = 'dev-salt'
bearer_salt = 'dev-bearer-salt'
cookie_duration = 86400
bearer_duration = 86400

Security best practices

Never use default admin/admin credentials in production.
admin_user = 'unique_admin_username'
admin_password = 'StrongP@ssw0rd!Random123'
Always enable secure cookies when using HTTPS:
[moderation.auth]
cookie_secure = true
cookie_samesite = 'Strict'
Use cryptographically random salts:
python -c "import secrets; print(secrets.token_hex(32))"
Different salt for cookies vs bearer tokens.
Change the login URL to reduce automated attacks:
[app]
login_endpoint = '/secret-admin-login-path'
Periodically update:
  • Admin password
  • Cookie salt
  • Bearer salt
  • Login endpoint path

Troubleshooting

  • Verify admin_user and admin_password are correct
  • Check moderation.enabled = true
  • Confirm login endpoint path (default /login, or custom in [app])
  • Review browser cookies (may need to clear old cookies)
  • Check application logs for authentication errors
  • Verify hide_post_if_reported or n_reports_then_hide settings
  • Check filter cache is working (SQLite file exists or Redis is connected)
  • Review moderation logs for errors
  • Ensure reports are coming from different IP addresses
  • Verify regex_filter pattern is valid
  • For SQLite: ensure path_to_regex_so points to valid sqlite-regex library
  • Test regex pattern separately before deploying
  • Check application logs for regex compilation errors
  • Verify hidden_images_path is set
  • Check directory exists and has write permissions
  • Ensure application user can move files to the directory
  • Images remain at original path until explicitly moved

Build docs developers (and LLMs) love