Created
September 17, 2025 07:42
-
-
Save un4ckn0wl3z/d6c4e85244038b581bedddaabd1891fd to your computer and use it in GitHub Desktop.
iplogger.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ip-logger.js | |
// Simple IP logger using Express | |
// Run: node ip-logger.js | |
// Requires: npm install express | |
const express = require('express'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const PORT = process.env.PORT || 3000; | |
const LOG_FILE = path.join(__dirname, 'visitors.csv'); | |
const app = express(); | |
// If you're behind a proxy (nginx, cloudflare, etc), enable this so req.ip uses X-Forwarded-For | |
app.set('trust proxy', true); | |
// Ensure log file has header | |
if (!fs.existsSync(LOG_FILE)) { | |
fs.writeFileSync(LOG_FILE, 'timestamp,ip,xff,user_agent,method,path,referer\n', { encoding: 'utf8' }); | |
} | |
function getClientIp(req) { | |
// Express's req.ip returns the remote address or the left-most entry in X-Forwarded-For when trust proxy is true | |
return req.ip || req.connection.remoteAddress || ''; | |
} | |
function appendLog(req) { | |
const ts = new Date().toISOString(); | |
const ip = getClientIp(req).replace(/,/g, ''); // avoid commas breaking CSV | |
const xff = (req.headers['x-forwarded-for'] || '').replace(/,/g, ';'); | |
const ua = (req.headers['user-agent'] || '').replace(/,/g, ' '); | |
const method = req.method; | |
const p = req.originalUrl || req.url; | |
const referer = (req.headers.referer || req.headers.referrer || '').replace(/,/g, ''); | |
const line = `${ts},${ip},${xff},${ua},${method},${p},${referer}\n`; | |
fs.appendFile(LOG_FILE, line, (err) => { | |
if (err) console.error('Failed to append log:', err); | |
}); | |
console.log(`${ts} - ${ip} - ${p} - ${ua}`); | |
} | |
// Simple middleware to log every request | |
app.use((req, res, next) => { | |
appendLog(req); | |
next(); | |
}); | |
// A friendly page | |
app.get('/', (req, res) => { | |
res.type('html').send(` | |
<h2>IP Logger Demo</h2> | |
<p>Your visit has been logged (if this server is public-facing).</p> | |
<p>To log visits from other pages/emails, embed this image as a beacon:</p> | |
<pre><img src="${req.protocol}://${req.get('host')}/beacon.png" alt="" /></pre> | |
`); | |
}); | |
// 1x1 transparent PNG (base64) used as a beacon | |
const pixel = Buffer.from( | |
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNgYAAAAAMAASsJTYQAAAAASUVORK5CYII=', | |
'base64' | |
); | |
app.get('/beacon.png', (req, res) => { | |
// We already logged via middleware, return a tiny image | |
res.set({ | |
'Content-Type': 'image/png', | |
'Cache-Control': 'no-cache, no-store, must-revalidate', | |
'Pragma': 'no-cache', | |
'Expires': '0', | |
}); | |
res.send(pixel); | |
}); | |
// Optional: endpoint to download logs (protect in real use!) | |
app.get('/download-logs', (req, res) => { | |
// WARNING: do not expose this in production without auth | |
res.download(LOG_FILE, 'visitors.csv'); | |
}); | |
app.listen(PORT, () => { | |
console.log(`IP logger running on http://localhost:${PORT} (trust proxy: ${app.get('trust proxy')})`); | |
console.log(`Logs append to: ${LOG_FILE}`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment