Cheap and dirty: how to collect logs from remote clients over HTTP
Published on 2025-11-12
Do you have an application spread across hundreds of client devices? Or a fleet of IoT sensors sending telemetry? Sooner or later the question arises: “What’s actually happening over there?” And right after it — “How do I collect logs without bankrupting myself on Splunk or Datadog?”
If your clients can send HTTP requests, you already have ninety percent of the solution. HTTP(S) is a universal and firewall-friendly protocol. All we need is a listener (endpoint) that will accept these logs.
In this article we’ll examine three budget ways to organize log collection over HTTP — from “fast, simple, and works” to “scalable and almost free”.
Why HTTP
- Universality — every programming language and platform has an HTTP client.
- Simplicity — a POST request with a JSON body is intuitive.
- Availability — port 443 (HTTPS) is almost never blocked, unlike specific ports for syslog or GELF.
Golden rule: always use HTTPS. Free Let’s Encrypt certificates can be set up in ten minutes and protect your data from interception.
Option 1. Script on a VPS (fast and very cheap)
The simplest, “hacky”, but also the fastest to deploy method. Suitable for pet projects or collecting logs from a small number of clients.
What you’ll need
- A cheap VPS (Vultr, DigitalOcean, Hetzner, etc.) costing around five dollars a month.
- Stack: Nginx + any backend script (Python/Flask, Node.js/Express, PHP).
How it works
Rent a virtual server.
Bring up Nginx as a reverse proxy and for SSL termination.
Write a tiny web application (twenty lines of code) that:
- accepts POST requests to
/log; - if necessary, checks a secret key in the
X-API-Keyheader; - writes the JSON log to a file.
- accepts POST requests to
Example in Python (Flask)
from flask import Flask, request, abort
import os
import json
app = Flask(__name__)
API_KEY = os.environ.get("LOG_API_KEY", "super-secret-key")
@app.route('/log', methods=['POST'])
def receive_log():
if request.headers.get('X-API-Key') != API_KEY:
abort(401)
data = request.get_json(silent=True)
if not data:
abort(400)
try:
with open("/var/log/my-app/events.log", "a") as f:
f.write(json.dumps(data) + "\n")
except Exception as e:
print(f"Failed to write log: {e}")
abort(500)
return "OK", 200
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)
Advantages
- Minimal costs (around five dollars a month).
- Simplicity and control over storage.
- Deployment in thirty minutes.
Disadvantages
- Poor scalability: writing to a single file quickly becomes a bottleneck.
- Maintenance required (log rotation, disk monitoring, security).
- Analysis — manually via SSH and
grep.
Option 2. Server-side collector (reliable and flexible)
An evolution of the first approach — using a ready optimized open-source stack.
What you’ll need
- VPS for $5–10/month.
- Stack: Vector, Loki, Grafana.
How this works
- Vector — an HTTP server that accepts logs.
- Loki — Grafana’s log database, which indexes only labels, making storage cheap.
- Grafana — a convenient interface for searching and analyzing logs using LogQL.
Example Vector configuration (vector.yaml)
sources:
http_logs:
type: "http"
address: "0.0.0.0:8080"
decoding:
codec: "json"
auth:
strategy: "header"
header_key: "X-API-Key"
api_keys: ["super-secret-key"]
transforms:
my_transform:
type: "remap"
inputs: ["http_logs"]
source: |
.app = "my_mobile_app"
.level = get!(.level, default: "info")
sinks:
loki:
type: "loki"
inputs: ["my_transform"]
endpoint: "http://localhost:3100"
labels:
app: "{{ app }}"
level: "{{ level }}"
encoding:
codec: "json"
Advantages
- High performance (thousands of logs per second).
- Convenient search and filtering via Grafana.
- Vector can send logs not only to Loki, but also to S3, ClickHouse, and other storages.
Disadvantages
- More complex setup: three components that require Docker or systemd.
Option 3. Serverless (almost free and virtually infinitely scalable)
The most modern and flexible option. No servers — you pay only for the number of requests and the amount of data.
What you’ll need
- A cloud account (AWS, Google Cloud, or Yandex Cloud).
- Stack (example on AWS): API Gateway + Lambda + S3 or CloudWatch Logs.
How it works
The client sends a POST request.
API Gateway receives the request as a managed HTTP endpoint.
It invokes Lambda.
Lambda:
- saves the JSON to S3 by date;
- sends the log to CloudWatch Logs.
Example Lambda in Python (writing to S3)
import json
import boto3
import time
import os
s3 = boto3.client('s3')
BUCKET_NAME = os.environ['LOG_BUCKET_NAME']
def lambda_handler(event, context):
body = event.get('body')
if not body:
return {'statusCode': 400, 'body': 'No data'}
try:
log_data = json.loads(body)
except json.JSONDecodeError:
return {'statusCode': 400, 'body': 'Invalid JSON'}
now = time.strftime('%Y/%m/%d/%H', time.gmtime())
file_name = f"{context.aws_request_id}.json"
s3_key = f"logs/{now}/{file_name}"
try:
s3.put_object(
Bucket=BUCKET_NAME,
Key=s3_key,
Body=json.dumps(log_data),
ContentType='application/json'
)
return {'statusCode': 200, 'body': 'OK'}
except Exception as e:
print(e)
return {'statusCode': 500, 'body': 'Error saving log'}
Advantages
- Free tiers of AWS/Google/Yandex cover millions of logs per month.
- Automatic scalability.
- No servers or updates — minimal maintenance.
Disadvantages
- Analysis requires setup (for example, AWS Athena or BigQuery).
- Vendor lock-in to a specific cloud provider.
Client-side best practices
- Asynchronous sending — don’t block the main thread of the application.
- Batch transfer — collect logs into an array and send in batches (every 30 seconds or after 50 events).
- Retries — store offline logs locally (for example, in SQLite) and send them later.
- Filtering — send only important levels (INFO, WARN, ERROR).
Conclusion
Collecting logs from remote clients cheaply is entirely feasible. The main thing is to choose the approach that fits your needs.
| Scenario | Recommendation |
|---|---|
| Starting a project | Serverless |
You already have a VPS and need grep | Script on a VPS |
| Need a powerful self-hosted solution | Vector + Loki |
Related reviews
There were several issues concerning both the technical side and overall understanding. Mikhail responded quickly, resolved the technical problems, and helped me understand them — many thanks. I'm satisfied with the result.
abazawolf · VPS setup, server setup
2026-02-18 · ⭐ 5/5
There were several issues concerning both the technical side and overall understanding. Mikhail responded quickly to the request, helped sort things out and resolved the technical problems and helped clarify understanding, for which a special thank you. I am satisfied with the result.
Everything was done quickly and efficiently. I recommend.
Akelebra · VPS setup, server setup
2026-01-17 · ⭐ 5/5
Everything was done quickly and efficiently. I recommend.
Everything went well; the contractor responded quickly to questions and helped resolve the issue. Thanks!
visupSTUDIO · VPS setup, server setup
2025-12-16 · ⭐ 5/5
Everything went well, the contractor responded quickly to questions and helped resolve the issue. Thank you!
Everything was done promptly. We'll use them again. Highly recommend!
rotant · VPS setup, server setup
2025-12-10 · ⭐ 5/5
Everything was done promptly. We'll continue to use their services. I recommend!
Everything was done promptly. Mikhail is always available. We'll continue to contact him.
samstiray · VPS setup, server setup
2025-12-10 · ⭐ 5/5
Everything was done promptly. Mikhail is always available. We'll continue to reach out
Mikhail is a professional! He's shown this in practice more than once.
Vadim_U · VPS setup, server configuration
A settled customer2025-12-03 · ⭐ 5/5
Mikhail, a professional! Not the first time he's demonstrated this in practice.