Heads up! - Restriction for some API functions - if you pull data, read this.

  • Simomax
  • Simomax's Avatar Topic Author
  • Offline
  • Moderator
  • Moderator
  • Nuts about radioactive everything!
More
1 week 6 hours ago - 1 week 4 hours ago #7582 by Simomax
Hello everyone,

It became apparent today that some users have automated the use of the CSV/graph drawing and other API functions, which has been having an impact on server performance. It was this thread that prompted me to have a bit of a dig through the radmon logs and found a lot of requests from external devices that have been using CPU intensive API functions. I have now restricted these functions for the time being until Dan and I find a suitable solution.

For now the following functions have been restricted:
  • forcegraphrefresh
  • drawall
  • graphtoday
  • graphweek
  • graphmonth
  • graphquarter
  • drawgraph24hr
  • drawsmallgraph
I am also looking at other API functions that are currently being abused but are having a lesser impact than the graph generation.

Feel free to discuss/throw in any ideas.

Cheers
Last edit: 1 week 4 hours ago by Simomax.

Please Log in or Create an account to join the conversation.

  • Simomax
  • Simomax's Avatar Topic Author
  • Offline
  • Moderator
  • Moderator
  • Nuts about radioactive everything!
More
1 week 4 hours ago - 1 week 4 hours ago #7584 by Simomax
I have made another two changes to the API. The functions lastreading and lastreadingusv were being heavily spammed, over and over. It is now a requirement to use the station's data sending password with the function. Yes, this does mean that only the station owner can request this data now, unless they share their password. It's not ideal, but the best I can come up with for now.

Anyone that is pulling their station CPM or uSv/h should update their code to include their station's data sending password.

Function: lastreading
*Updated 24/05/2026 - added in password requirement
Parameters: user, password
Description: Displays the last reading of a station in CPM.
Example: https://radmon.org/radmon.php?function=lastreading&user=Simomax&password=datasendingpassword
Returns: '18 CPM on 2022-12-03 17:49:31UTC at Blackpool, Lancashire, United Kingdom'

Function: lastreadingusv
*Updated 24/05/2026 - added in password requirement
Parameters: user, password
Description: Displays the last reading of a station in uSv/hr.
Example: https://radmon.org/radmon.php?function=lastreadingusv&user=Simomax&password=datasendingpassword
Returns: '0.225 uSv/hr on 2022-12-03 17:45:31UTC at Blackpool, Lancashire, United Kingdom'

This is just an example of what I found whilst digging, which I consider completely unacceptable:
77.87.#.# - - [24/May/2026:14:48:59 +0100] "GET /radmon.php?function=showuserlist HTTP/1.1" 200 13832 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:48:59 +0100] "GET /radmon.php?function=lastreadingusv&user=Michelbach HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Bihor HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Bertiolo HTTP/1.1" 200 3971 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=NW8R HTTP/1.1" 200 233 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Hampshire HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Hersfeld HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Rosenhof HTTP/1.1" 200 3971 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=sbodnar HTTP/1.1" 200 233 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Kaliningradskaya HTTP/1.1" 200 3971 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Gene99 HTTP/1.1" 200 224 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Radium88b HTTP/1.1" 200 239 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Matthias HTTP/1.1" 200 4096 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=VAR HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Alpes HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=fell HTTP/1.1" 200 315 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=tag2015 HTTP/1.1" 200 240 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Brunovce HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=sp3tlu HTTP/1.1" 200 226 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Westergellersen HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=republic HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=bRAD HTTP/1.1" 200 312 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=bengos HTTP/1.1" 200 317 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Czech HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Wexican HTTP/1.1" 200 320 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Newcastle HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=radspod_one HTTP/1.1" 200 310 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=8mi HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Finning HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Provincie HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=lt904 HTTP/1.1" 200 236 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Corbetta HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Suldrup HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=appu HTTP/1.1" 200 321 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=Bad HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=saimre HTTP/1.1" 200 234 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:00 +0100] "GET /radmon.php?function=lastreadingusv&user=southofhobart1 HTTP/1.1" 200 238 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Don HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Zaltbommel HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=fredriknb HTTP/1.1" 200 310 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Sladkovicovo HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=5.6 HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Ebikon HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=22.5 HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=merat HTTP/1.1" 200 236 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Zhiniukas HTTP/1.1" 200 240 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Vladimirovo HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=19.5 HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Orange HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=Italia HTTP/1.1" 200 195 "-" "MonsterNode/2026.64"
77.87.#.# - - [24/May/2026:14:49:01 +0100] "GET /radmon.php?function=lastreadingusv&user=MiH HTTP/1.1" 200 236 "-" "MonsterNode/2026.64"
Last edit: 1 week 4 hours ago by Simomax.
The following user(s) said Thank You: nu3e

Please Log in or Create an account to join the conversation.

More
6 days 4 hours ago #7586 by mw0uzo
Thank you Simomax for monitoring it and spending time on it when he should be enjoying himself.

radmon.org is all about sharing data and supporting new projects personal and beyond.

There are one and a half rules to stick to
1) if you are running a project that is making money from radmon.org data or services, *you are expected to regularly donate to our project*
2) if you're not making money, then you're welcome to create, just try not to consume a ton of cpu. Best thing to do is chat about it on the forum and we can come up with a slimline way of providing what is necessary.

Please Log in or Create an account to join the conversation.

More
5 days 10 hours ago - 5 days 10 hours ago #7587 by Fanko
Hi, I saw the changes to the endpoints above. I agree that we should implement some form of rate limiting. I also use the lastreading endpoint to display values on my Home Assistant dashboard at home, but I only call it once per minute.

Maybe we should consider for rate limiting by IP address (or user) and allow the execution of the same request only after a certain period has passed since the last one.
For example, when /radmon.php?function=lastreadingusv&user=user123 is called, it could save the request timestamp for that user (or IP) in memory (in a Key-Value Map). If the same request is made again before a specific time has passed (e.g., 15 seconds), it should immediately fail with an HTTP 429 error. This way, the server will quickly terminate the invalid request, leaving the CPU free for other tasks.

As for those who use the data for commercial purposes, it might be a good idea to create a separate endpoint. They could use a POST method to send all the station names they are interested in at once and receive a single, combined JSON response with their data. This would significantly reduce the number of redundant requests to the same endpoint.
Last edit: 5 days 10 hours ago by Fanko.

Please Log in or Create an account to join the conversation.

  • Simomax
  • Simomax's Avatar Topic Author
  • Offline
  • Moderator
  • Moderator
  • Nuts about radioactive everything!
More
4 days 22 hours ago #7588 by Simomax
Agreed Fanko, rate limiting would work well for the most part, however after 5-6 hours of going through the logs with a fine tooth comb and arranging/cross referencing the data, it appears it is a minority that are taking the largest slice of the pie. At first I thought a few radmon users were pulling data for themselves, that's at least what I expected, but my findings show a more targeted, data harvesting thing going on. Here are my findings:

First of all I am not going to name and shame anyone on radmon.org, simply because I don't believe this to be coming from any radmon.org users. This appears to be bots/AI/data harvesting services for the main part. There are a good handful of radmon users that I can see are querying the site for their personal use. I can't say for sure if every query/request to the station details/cpm etc are from a radmon user, but for the most part it does look like regular radmon users. And they are just using it normally, like Fanko. So my apologies for abruptly changing the API without notice to those stations/users. All you need to do is update your code, or YAML, or python, whatever, to include your station password and then you can use the two functions for getting the cpm and usv.~

The rest of queries, and I am talking maybe two orders of magnitude more than the regular radmon users, are from just 5 IP addresses. None of the IP addresses submits to radmon.org, by the look of it. Dan is looking into getting me full access to the apache logs so I'll know for sure then.

These 5 IP addresses go into three categories - 1, monitoring within a certain area, 2, harvesting and serving to another web service, and 3, literally hoovering up every single station graph, over and over.

Three IP addresses are querying 5/6 stations for their current cpm/usv. This is category 1. These appear to be say 5 or 6 stations in a country, or area. My guess is they are simply gathering local records, for something. What that something is, I don't know. None of these three IP addresses appear to submit to a station at radmon.org

One IP address keep hoovering up the station list. Over and over and over, every 5-10 minutes. Not real bad really, except the data is being published on a website warlens.net and published as though it is their own, on the face of it. I haven't looked much into that yet. Their user agent is WarLens/1.0 (radmon-watch). So warlens is just raking up the whole station list, the cpm and locations and serving them up on it's own site. I can't see any attribution or anything, just radmon stations and their cpm. Building the station list each time has a small impact on the server as it is a large query. It takes less time direct using the API than re-writing it through joomla, thankfully!

Then we come down to the 5th IP address.   (I don't think I have ever used that emoji on this site before...) This is category 3, literally hoovering up tones of data/graphs and chewing up many cpu cycles and IOs. This IP is constantly getting the station list (station list = user list = https://radmon.org/radmon.php?function=showuserlist) and also getting station pages (such as https://radmon.org/radmon.php?function=showuserpage&user=radspod_one). It's not so much bandwidth that is an issue. The server sits on a gigabit fibre connection. I suspect it's upload is around 100mbps, so no issues with bandwidth. IO becomes a big part. Serving up the graphs over and over, querying the database over and over with queries that create large amounts of results uses a lot of IO on the RPi.

A couple that I forgot (from this 8 hours log) - there are a couple of IP's that are pulling the station page for a couple of stations. This could be users pulling their graphs to another location, I don't know. Hard to say right now. Less than ideal though as it is over and over every 5 and 10 minutes. What bothers me about these kinds of automated processes is, is anyone looking at them? Or are they just being pulled to some web server's drive somewhere, overwriting the last one, then the next is requested, overwrites the old one, and so on. It's a highly inefficient use, unless someone is actually looking at them, 24/7.... I doubt that. It's just a bit rude IMHO. I pull the graph images to my radmon page, but only when someone looks at it. It's less wasteful.

That's about it for what I have found so far, and this comes on top of restricting the CSV/graph generation. Now sadly, and again, my apologies for this, but category one has been fixed by implementing the station password with the request, so people using this will need to update their code to include the password. Categories two and three are still ongoing. So I do feel a bit shitty about changing the API and only stopping the cat 1 stuff. I will get on to the other bits soon, in one way or another. I'm (trying to) speaking with Dan, but seems he is offline right now. He's going to hate the barrage of messages I have left him.    I don't know if anyone else has noticed, I certainly have, that the website seems a lot snappier now. It still has it's hanging/waiting times, but generally I think it feels noticeably faster. Hopefully I can claw some more back soon, but I need to speak with Dan, and think of better ways for people to access the data that hopefully benefits everyone, except those data-sucking leaches. 

Please Log in or Create an account to join the conversation.

  • Simomax
  • Simomax's Avatar Topic Author
  • Offline
  • Moderator
  • Moderator
  • Nuts about radioactive everything!
More
4 days 22 hours ago #7589 by Simomax
Something I forgot to mention about rate limiting is how do you make the limit function cost less than the data or query requested? Lets say the data requested is cpm, that's one quick fast lookup - one request, one db query, one result. About as simple as it comes. Now for rate limiting we have to store the last request time and on the next request lookup that last request time, so instead of request, look, serve, we now have request, read from db, calculate, store to db, then either serve or drop. So three steps become 5 steps, every time. It's easier and more lightweight to just serve the cpm, every time. If memory could be used to store and read the IP's and times then it may be beneficial, but I'm not sure of that is possible.

However, for the large process requests, such as serving the station page/graphs etc, then yes, this would be massively beneficial.

I really need to speak with Dan before anything else. One thing that springs to mind is that any API user has to be a registered user with radmon.org. Doesn't necessarily have to have a station, but that way we keep the keys at all times and keeps most doors closed. It would allow for users to use all the API features with a password. Anything gets out of hand and the account gets terminated or whatever. Essentially it would stop a lot of bots and harvesters from even getting started, and with some additional logging in place things like AI agents could be detected and then stopped, without affecting the rest of the users' API functionality. We'll see, but I am far from finished with this.

Please Log in or Create an account to join the conversation.

Moderators: Gamma-Man
Time to create page: 0.280 seconds
Powered by Kunena Forum
Everything's free. Please support us by considering a donation. Log in first!
Solar powered Raspberry Pi 4 server stats: CPU 73% Memory 15% Swap 18% CPU temp=64.2'C Uptime 2 Days