Over the past couple of weeks, I have come across a huge number of articles with headlines “We raise our VPN” or “Configuring OpenVPN in N steps”. On this wave, I also decided to try to make a VPN for myself and loved ones – such an experience is superfluous (and the VPN itself) definitely won’t. To do this, I bought one of the cheapest VPS with a foreign IP and minimal characteristics. This pleasure cost me ~ 250r per month.
It was decided to deploy the private network itself through OpenVPN. At that time, I had not heard anything about other services, and there were more than enough instructions for setting up OpenVPN (as I found out later, everything can be deployed literally in a couple of lines).
After a couple of hours of fiddling with configs and certificates and fully configuring the VPN, I found in the server control panel that the maximum channel speed is 10Mbps (this was written on the order page, but I overlooked this moment). The technical support explained that this limitation becomes active when the traffic speed exceeds 10Mbps per hour (means that you need to drive about 4.5 GB during this time). It turned out awkward, of course, but I did not plan to use a VPN even to such an extent. However, I became interested in the task of monitoring traffic and the ability to warn myself if suddenly the traffic speed through the VPN approaches the threshold value.
What is already there
First of all, I tried to find ready-made solutions for monitoring OpenVPN, after all, this is a fairly popular implementation, around which there should be a large community.
I have identified 2 solutions for myself:
OpenVPN-Admin – a whole combine that serves not only for monitoring, but also for managing certificates and the OpenVPN server itself
OpenVPN-Monitor – simple live-time monitoring with a geographic map showing connected clients
The first solution in my case would be too redundant, I would never need 80% of the functionality. In the second case, it turned out that monitoring is carried out only on this momentwhile statistics are not collected – there is no way to see how much the client has downloaded / uploaded in the last hour, and that’s why I was looking for a solution.
Besides these two options, I could not find anything that would meet my requirements or that I could remake to fit my needs.
So I decided to sketch out my solution over the weekend and practice a few things along the way. What exactly I wanted:
Collect VPN usage statistics for each user
Track total traffic consumption
Warn if traffic exceeds 8-9Mbps in the last hour
And also watch all this business in the web interface (for aesthetic purposes) and try to pack everything in Docker (for educational purposes)
parsim, parsim, parsim
To analyze statistics, you must first collect statistics. OpenVPN provides a fairly user-friendly interface for getting traffic usage statistics. The corresponding directive is already included in the default server configuration:
It allows you to specify a file to which statistics on traffic usage by connected clients will be written. After the file name, you can additionally specify a number – the interval in seconds after which the file will be automatically updated (60 seconds by default).
For an integrated approach and, in my opinion, more humane than file parsing, you can use management-server, for this you need to specify the following directive in the config:
management localhost 7505
Additionally, you can specify a password to connect to the interface (more).
After that, it will be possible to connect to the OpenVPN server via telnet:
We collect statistics
OpenVPN kindly gives real-time statistics, but, alas, does not collect or store them. You can only get connected clients and the amount of their traffic in the last session, so you will have to take responsibility for the collection.
To collect statistics, I chose the option using management-interface and for this I wrote small python script. Once every N seconds, it accesses the management interface, requests the status, and creates/updates records in MongoDB for each user:
Can be better
Already when writing the article, I noticed some of my mistakes. Yes, it was possible to store data much more optimally and get by with just one collection – only segments. You can use it to carry out the entire analysis, practically without adding new fields, and fields with a difference (d_received and d_send) can be calculated dynamically if you do not plan to analyze too long periods of time
To get the total traffic consumption per hour, it is enough to simply select all the records whose time falls within this interval and sum up the traffic for them (or rather, their differences in traffic compared to previous records). For clients, you need the same thing, but with filtering by name.
Now the statistics are being collected, it remains to increase the functionality! In my case, it was only necessary to display it on the web and issue warnings if the traffic speed was exceeded!
We make it convenient
To display on the web, I did a simple web application on Vue and API for it on Flask. There is nothing unusual in it – one page that displays general statistics and cards for each of the users:
The web interface is great, but what about the traffic speeding notification? Initially, I had thoughts about sending notifications directly to the browser, but I never got to them, because another solution came to my mind – to make a bot in the TG and send messages from it!
Packing in Docker
As a practice, I decided to package everything in Docker. Since I already had MongoDB deployed on another server, I did not deploy it and managed with two Dockerfiles – one for the web and one for the parser. Since both of the microservices are made in Python, their Dockerfiles do not differ much.
# Dockerfile для веба # Билдим фронтенд FROM node:16.14-alpine3.14 AS builder WORKDIR /usr/app/client COPY ./client /usr/app/client RUN npm i RUN npm run build # Собираем фронтенд и сервер FROM python:3.10.4-alpine3.14 COPY app.py app.py COPY requirements.txt requirements.txt COPY --from=builder /usr/app/client/dist /client/dist RUN pip install -r requirements.txt EXPOSE 5000 CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0" ]
# Dockerfile для парсера FROM python:3.8.13-buster COPY main.py main.py COPY OVPNInterface.py OVPNInterface.py COPY requirements.txt requirements.txt RUN pip install -r requirements.txt EXPOSE 5555 CMD [ "python3", "-m", "main" ]
Thanks for reading! In this article, I just wanted to share my experience in collecting traffic statistics and “integrating” OpenVPN into real life. It is unlikely that my particular solution can be used by someone else, but the possibilities of the same management-interface are much wider, and therefore, there is where to roam!