Wire the anonymous form to a VPS Python endpoint that notifies Telegram, persists submissions locally, and stops faking success on failure. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .. | ||
| .env.example | ||
| contact_server.py | ||
| README.md | ||
Contact API → Telegram
Small Python 3 (stdlib only) service that accepts POST /api/contact and forwards the message to Telegram.
Setup (once)
- Create a bot with @BotFather → copy the token.
- Open a chat with the bot and press Start.
- Get your numeric chat id (
@userinfobot, or callgetUpdatesafter messaging the bot). - On the VPS:
cd /path/to/site/api
cp .env.example .env
# edit .env — set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID
Local smoke test
cd api
cp .env.example .env # fill tokens
python3 contact_server.py
curl -sS -X POST http://127.0.0.1:8787/api/contact \
-H 'Content-Type: application/json' \
-d '{"name":"Test","contact":"@you","message":"hello"}'
Health check: GET /api/health → {"ok":true,"configured":true}.
systemd
/etc/systemd/system/428th-contact.service:
[Unit]
Description=428th contact form → Telegram
After=network.target
[Service]
Type=simple
WorkingDirectory=/var/www/428th.com/api
EnvironmentFile=/var/www/428th.com/api/.env
ExecStart=/usr/bin/python3 /var/www/428th.com/api/contact_server.py
Restart=always
RestartSec=3
User=www-data
Group=www-data
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now 428th-contact
sudo systemctl status 428th-contact
Adjust WorkingDirectory, EnvironmentFile, User, and paths to match your VPS layout.
nginx
Inside the HTTPS server block for 428th.com:
location /api/contact {
proxy_pass http://127.0.0.1:8787/api/contact;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 16k;
}
# optional
location /api/health {
proxy_pass http://127.0.0.1:8787/api/health;
proxy_set_header Host $host;
}
Then:
sudo nginx -t && sudo systemctl reload nginx
Deploy updated static files (common.js, built HTML) as usual so the form shows real errors and includes the honeypot field.
Message backup
Every valid submission is appended to messages.jsonl (override with MESSAGES_FILE in .env), one JSON object per line:
{"ts":"2026-07-26T16:40:00Z","name":"…","contact":"…","message":"…","ip":"1.2.3.4","telegram_ok":true,"telegram_error":null}
Backup is written even if Telegram fails (telegram_ok: false), so you still have the text on disk. Honeypot hits are not stored. Keep this file private (same permissions as .env); it is gitignored.
Behaviour notes
- Honeypot field
website: if filled, returns200without notifying Telegram or writing a backup. - In-memory rate limit: 5 POSTs per IP per 60 seconds →
429. - Field limits: name/contact ≤ 200 chars, message ≤ 4000.