Graylog on a VPS: Centralized Log Management with Full-Text Search and Alerting
Graylog is an open-source log management platform with a more operator-friendly interface than the ELK stack — it provides centralized log collection via GELF, syslog, and Beats, full-text search across all logs, stream-based routing, alerting on patterns, dashboards, and built-in user management. While Loki is lighter-weight, Graylog provides richer search capabilities and is better suited for teams that need to search logs extensively.
Step 1: Docker Compose Setup
<code">mkdir -p /opt/graylog && cd /opt/graylog nano docker-compose.yml
<code">version: '3.8'
services:
# MongoDB for Graylog metadata
mongo:
image: mongo:7.0
restart: always
volumes:
- mongo_data:/data/db
# OpenSearch for log storage
opensearch:
image: opensearchproject/opensearch:2.11.0
restart: always
environment:
OPENSEARCH_JAVA_OPTS: "-Xms2g -Xmx2g" # Adjust to your VPS RAM
bootstrap.memory_lock: "true"
discovery.type: single-node
plugins.security.disabled: "true" # Disable for internal-only
ulimits:
memlock:
hard: -1
soft: -1
volumes:
- opensearch_data:/usr/share/opensearch/data
# Graylog server
graylog:
image: graylog/graylog:6.0
restart: always
depends_on:
- mongo
- opensearch
ports:
- "127.0.0.1:9000:9000" # Web UI
- "0.0.0.0:12201:12201/udp" # GELF UDP input (for log shipping)
- "0.0.0.0:12201:12201/tcp" # GELF TCP input
- "0.0.0.0:514:5140/udp" # Syslog UDP (high port, map to 514)
environment:
GRAYLOG_NODE_ID_FILE: /usr/share/graylog/data/config/node-id
GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
GRAYLOG_HTTP_EXTERNAL_URI: "https://logs.yourdomain.com/"
GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200"
GRAYLOG_MONGODB_URI: "mongodb://mongo/graylog"
GRAYLOG_PASSWORD_SECRET: ${GRAYLOG_SECRET}
GRAYLOG_ROOT_PASSWORD_SHA2: ${GRAYLOG_ROOT_PASSWORD_SHA2}
volumes:
- graylog_data:/usr/share/graylog/data
volumes:
mongo_data:
opensearch_data:
graylog_data:
<code"># Generate password hash: echo -n "YourAdminPassword!" | sha256sum | cut -d" " -f1 cat > .env << 'EOF' GRAYLOG_SECRET=$(openssl rand -hex 32) GRAYLOG_ROOT_PASSWORD_SHA2=PASTE_SHA256_HASH_HERE EOF chmod 600 .env docker compose up -d # Wait 2-3 minutes for OpenSearch to initialize docker compose logs -f graylog | grep "Graylog server up"
Step 2: Nginx Reverse Proxy
<code">sudo nano /etc/nginx/sites-available/graylog
<code">server {
listen 443 ssl http2;
server_name logs.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/logs.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/logs.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
}
}
<code">sudo certbot --nginx -d logs.yourdomain.com sudo systemctl reload nginx
Step 3: Configure Inputs
<code"># Graylog UI → System → Inputs → Launch new input # GELF UDP Input (recommended — for application logs): # Type: GELF UDP # Title: GELF UDP # Port: 12201 # Bind address: 0.0.0.0 # Syslog UDP Input (for OS-level logs): # Type: Syslog UDP # Title: Syslog # Port: 5140 (mapped to 514 in docker-compose) # Bind address: 0.0.0.0
Step 4: Ship Logs to Graylog
<code"># Method 1: rsyslog → Graylog (GELF over UDP) sudo nano /etc/rsyslog.d/90-graylog.conf
<code">module(load="mmjsonparse")
template(name="GELF" type="list") {
constant(value="{\"version\":\"1.1\",")
constant(value="\"host\":\"")
property(name="hostname")
constant(value="\",\"short_message\":\"")
property(name="msg" format="json")
constant(value="\",\"timestamp\":")
property(name="timegenerated" dateformat="unixtimestamp")
constant(value=",\"level\":")
property(name="syslogseverity")
constant(value="}")
}
*.* action(type="omfwd" Target="YOUR_GRAYLOG_VPS_IP" Port="12201" Protocol="udp" Template="GELF")
<code">sudo systemctl restart rsyslog
<code"># Method 2: Application code → GELF (Python):
pip install graypy
import logging, graypy
logger = logging.getLogger('myapp')
handler = graypy.GELFUDPHandler('graylog.yourdomain.com', 12201)
logger.addHandler(handler)
logger.warning('High memory usage detected', extra={
'service': 'api-server',
'memory_percent': 87.5,
'host': 'vps-01',
})
# Method 3: Node.js → GELF:
npm install winston-gelf-transporter
const { createLogger } = require('winston');
const GelfTransport = require('winston-gelf-transporter');
const logger = createLogger({
transports: [new GelfTransport({ host: 'graylog.yourdomain.com', port: 12201 })]
});
Step 5: Search and Streams
<code"># Graylog search syntax (Lucene-based): # Search all error logs: level:<=3 # Find logs from specific service: service:api-server AND level:<=4 # Full-text search: "database connection failed" # Time range + filter: source:web-server AND short_message:/nginx.*502/ # Field-based queries: http_status:500 AND NOT source:health-checker # Streams = saved filters that route logs: # System → Streams → Create Stream # Rule: field "service" matches "api-server" # Use streams for: team-specific log views, alert targets
Step 6: Configure Alerts
<code"># Alerts → Alert Definitions → Create # Alert: High error rate # Condition: Message count > 100 in 5 minutes # Stream: API Server logs # Filter: level:<=3 (errors only) # Action: Email team@yourdomain.com # Alert: Specific pattern (e.g., "OutOfMemoryError") # Condition: Message count > 1 in 1 minute # Filter: message_text:"OutOfMemoryError" # Action: PagerDuty or Slack webhook
Getting Started
Graylog with OpenSearch needs 4+ GB RAM — deploy on a dedicated 4 GB Ubuntu VPS at VPS.DO. OpenSearch’s JVM heap is the main consumer (set to 2 GB in the config above). For log retention, plan for 1–5 GB per day per server being monitored, depending on verbosity. SSD or NVMe storage is essential for OpenSearch performance — HDD-backed VPS instances make log search painfully slow.
Conclusion
Graylog provides team-friendly centralized log management with full-text search, stream-based routing, and pattern alerting. The GELF protocol makes it easy to ship structured logs from any application (Python, Node.js, Java, Go) alongside system syslog, with all logs searchable from one interface. For teams that find Loki’s label-based approach limiting and need richer full-text search capabilities, Graylog is the right middle ground between Loki’s simplicity and Elasticsearch’s complexity.
KlaroNail nail support
October 17, 2026Thanks for explaining when to consult a dermatologist as part of a regular routine.
nail fungus treatment options
October 17, 2026Helpful explanation of foods that support general wellness in a balanced way.
Memo Honey product information
October 17, 2026Good points about long-term cognitive wellness and everyday wellbeing.
Nerve function support
October 17, 2026A clear and helpful article. This is worth bookmarking.