add systemd service unit and rate limit headers

Systemd deployment:
- examples/flaskpaste.service with security hardening
- examples/flaskpaste.env with all config options
- README deployment section updated

Rate limit headers (X-RateLimit-*):
- Limit, Remaining, Reset on 201 and 429 responses
- Per-IP tracking with auth multiplier
- api.md documented
This commit is contained in:
Username
2025-12-24 17:51:14 +01:00
parent cb6eebee59
commit cf458347ef
7 changed files with 265 additions and 22 deletions

48
examples/flaskpaste.env Normal file
View File

@@ -0,0 +1,48 @@
# FlaskPaste environment configuration
# Install: sudo mkdir -p /etc/flaskpaste && sudo cp flaskpaste.env /etc/flaskpaste/env
# Permissions: sudo chmod 600 /etc/flaskpaste/env
# Flask environment
FLASK_ENV=production
# Database path
FLASKPASTE_DB=/opt/flaskpaste/data/pastes.db
# Paste limits
FLASKPASTE_MAX_ANON=3145728
FLASKPASTE_MAX_AUTH=52428800
# Expiry (tiered by authentication level)
FLASKPASTE_EXPIRY_ANON=86400
FLASKPASTE_EXPIRY_UNTRUSTED=604800
FLASKPASTE_EXPIRY_TRUSTED=2592000
# Proof-of-work (set to 0 to disable)
FLASKPASTE_POW_DIFFICULTY=20
FLASKPASTE_POW_TTL=300
# Anti-flood
FLASKPASTE_ANTIFLOOD=1
FLASKPASTE_ANTIFLOOD_THRESHOLD=5
FLASKPASTE_ANTIFLOOD_MAX=28
# Rate limiting
FLASKPASTE_RATE_LIMIT=1
FLASKPASTE_RATE_WINDOW=60
FLASKPASTE_RATE_MAX=10
FLASKPASTE_RATE_AUTH_MULT=5
# Content deduplication
FLASKPASTE_DEDUP_WINDOW=3600
FLASKPASTE_DEDUP_MAX=3
# URL prefix (for reverse proxy path-based routing)
# FLASKPASTE_URL_PREFIX=/paste
# Proxy trust (set shared secret for header validation)
# FLASKPASTE_PROXY_SECRET=your-secret-here
# PKI (uncomment to enable certificate authority)
# FLASKPASTE_PKI_ENABLED=1
# FLASKPASTE_PKI_CA_PASSWORD=change-this-secure-password
# FLASKPASTE_PKI_CERT_DAYS=365

View File

@@ -0,0 +1,83 @@
# FlaskPaste systemd service unit
# Install: sudo cp flaskpaste.service /etc/systemd/system/
# Enable: sudo systemctl daemon-reload && sudo systemctl enable --now flaskpaste
#
# Configuration via environment file: /etc/flaskpaste/env
# See README.md for all available environment variables
[Unit]
Description=FlaskPaste REST API pastebin
Documentation=https://github.com/username/flaskpaste
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=flaskpaste
Group=flaskpaste
WorkingDirectory=/opt/flaskpaste
# Environment configuration
EnvironmentFile=-/etc/flaskpaste/env
# Gunicorn WSGI server
# Workers = 2 * CPU cores + 1 (adjust based on load)
ExecStart=/opt/flaskpaste/venv/bin/gunicorn \
--bind 127.0.0.1:5000 \
--workers 4 \
--worker-class sync \
--timeout 30 \
--keep-alive 5 \
--max-requests 1000 \
--max-requests-jitter 50 \
--access-logfile - \
--error-logfile - \
--capture-output \
wsgi:app
# Restart policy
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60
StartLimitBurst=3
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
# Security hardening (systemd v232+)
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
LockPersonality=yes
MemoryDenyWriteExecute=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
# Read-write paths (database, data directory)
ReadWritePaths=/opt/flaskpaste/data
# Capabilities
CapabilityBoundingSet=
AmbientCapabilities=
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=flaskpaste
[Install]
WantedBy=multi-user.target