mo8it/oxitraffic

By mo8it

•Updated 4 months ago

Self-hosted, simple and privacy respecting website traffic tracker

Image
0

3.7K

mo8it/oxitraffic repository overview

⁠OxiTraffic

Self-hosted, simple and privacy respecting website traffic tracker 🌐

ā āž”ļø Demo⁠ ā¬…ļøā 

⁠
⁠Source code on Codeberg šŸ”ļøā 

⁠Features

  • āŒ Short visits are not counted
    • āœ… Only meaningful visits are counted
    • šŸ¤– Makes it less likely to count visits by web bots
  • šŸ„·šŸ¼ Respects privacy (no personal data or IP is logged)
  • šŸŖ No cookies
  • šŸ•Šļø Self-hosted
  • šŸ“ˆ Visualization of visits history
  • šŸ’»ļø API for visits history and count
  • šŸ… Low memory usage (about 12 MB)
  • šŸ“¦ļø First class container support
  • šŸ”€ Asynchronous and multithreaded
  • šŸ“œ Informative tracing (logging) to stdout and to a log file
  • šŸ†“ Free & open source (AGPLv3)
  • šŸ¦€ Written in Rust (oxidized)

⁠Demo

Here is a demo⁠ which tracks my own website (mo8it.com).

⁠How it works

You add the following script tag to your website after replacing OXITRAFFIC_BASE_URL with the base URL of your OxiTraffic instance:

<script type="module" src="https://OXITRAFFIC_BASE_URL/count.js"></script>

It runs the tiny script count.js⁠.

The script calls /register?path=PATH to receive a visitor ID. PATH is the path of the page you are on.

This ID is used after the minimum delay (configuration option min_delay_secs) to call /post-sleep/VISITOR_ID which leads to counting that visit.

When the page is left, a request is sent to /page-left/VISITOR_ID to record the total spent time.

⁠Path validation

How does OxiTraffic know if a newly requested path is a valid one for your tracked website?

Only for the first request to a new path, OxiTraffic sends a request to that path prefixed by the configuration option tracked_origin_callback. If the status code is in the range 200-299 (success), the path is added to the database. Otherwise, the request is rejected.

⁠Setup

⁠Containerized

You can use the container image published on Docker Hub⁠.

You can pull that image using Docker:

docker pull mo8it/oxitraffic:latest

Or using Podman:

podman pull docker.io/mo8it/oxitraffic:latest

The container image expects the config file to be mounted as a (read-only) volume at /volumes/config.toml inside the container (a volume doesn't have to be a directory, it can be a file).

You should mount an additional volume at /var/log/oxitraffic if you want to persist the logs.

By default, the container listens on port 80.

⁠Not containerized

You can also host OxiTraffic directly with the binary that you can install with Cargo:

cargo install oxitraffic --locked

Make sure to provide the environment variable OXITRAFFIC_CONFIG_FILE when using the binary directly (see the configuration section below).

⁠Database

In both cases (container or binary), you need a PostgreSQL database. There are many guides in the internet that explain how to host one either in a container or directly on the host. You could use my blog post about hosting PostgreSQL using Podman⁠.

⁠Configuration

The binary expects the environment variable OXITRAFFIC_CONFIG_FILE to point to the TOML configuration file config.toml. This environment variable is set to /volumes/config.toml in the container image.

The table below shows the configuration parameters for the configuration file. You can use environment variables to either set or overwrite parameters from the config file.

ParameterDescriptionDefaultEnvironment variable
socket_addressUse 127.0.0.1:8080 for local testing. 0.0.0.0 is important for usage in a container, but you can pick another port."0.0.0.0:80"OXITRAFFIC_SOCKET_ADDRESS
base_urlThe base URL of your OxiTraffic instance. Used to build the count.js⁠ script.OXITRAFFIC_BASE_URL
tracked_originThe origin⁠ of your tracked website that is used to allow CORS-requests⁠ from the count.js⁠ script to OxiTraffic.OXITRAFFIC_TRACKED_ORIGIN
tracked_origin_callbackThe origin⁠ of your tracked website that is used to verify a newly requested path as explained above. This option exists to be able to make these requests inside a local network.tracked_originOXITRAFFIC_TRACKED_ORIGIN_CALLBACK
logs_dirThe directory where log files will be placed in. You need to change the default value if OxiTraffic doesn't have write permission for the default directory./var/log/oxitrafficOXITRAFFIC_LOGS_DIR
min_delay_secsMinimum delay in seconds between visiting the website and being able to call /post-sleep to count the visit. It is recommended to call /post-sleep one second after this value. A low value not only counts meaningless visits, but also makes it easier for visits by web bots to be counts.19OXITRAFFIC_MIN_DELAY_SECS
db.hostPostgreSQL hostOXITRAFFIC_DB__HOST
db.portPostgreSQL portOXITRAFFIC_DB__PORT
db.usernamePostgreSQL usernameOXITRAFFIC_DB__USERNAME
db.passwordPostgreSQL passwordOXITRAFFIC_DB__PASSWORD
db.databasePostgreSQL databaseOXITRAFFIC_DB__DATABASE
utc_offset.hoursThe hours of your UTC offset0OXITRAFFIC_UTC_OFFSET__HOURS
utc_offset.minutesThe minutes of your UTC offset0OXITRAFFIC_UTC_OFFSET__MINUTES
⁠Example configuration

This is an example of the configuration file config.toml:

# Can be omitted because this is the default value.
socket_address = "0.0.0.0:80"

base_url = "https://oxitraffic.your_domain.com"

tracked_origin = "https://your_domain.com"
# In case both OxiTraffic and your website are in a local network and `website` can be resolved to the local IP address of the your website.
# Omit this option to use the value of `tracked_origin` instead.
tracked_origin_callback = "http://website"

# You should omit this option when using the container image and mount a volume at the default directory `/var/log/oxitraffic` to persist logs.
logs_dir = "/home/USERNAME/oxitraffic_logs"

[db]
host = "127.0.0.1"
port = 5432
username = "postgres"
password = "CHANGE_ME"
database = "postgres"

[utc_offset]
hours = 2
# Can be omitted because 0 is the default.
minutes = 0

⁠Endpoints

⁠Dashboard
EndpointDescriptionReturn
/A list of registered paths to see their visits history.HTML
/stats?path=PATHStatistics of the visits history of a specific path.HTML
⁠JSON API
EndpointDescriptionReturn
/api/countsThe visits count for each registered pathJSON([{"path": String, "count": i64}])
/api/count?path=PATHThe visits count for the specified pathJSON(i64)
/api/history?path=PATHThe visits datetimes for a specific path with the nullable referrer and global UTC offset. You can use this endpoint to make your own analysis and plotsJSON({"utc_offset": String, "visits": [{"registered_at": String, "referrer": Option<String>, "spent_time_seconds": Option<i64>}]})
⁠Script
EndpointDescriptionReturn
/register?path=PATHRegister to receive a VISITOR_ID for the PATH (e.g. / or /blog/rust-vs-julia) of the page you are visiting.JSON(u16)
/post-sleep/VISITOR_IDUse the visitor ID after the minimum delay min_delay_secs for the visit to be counted.Only status code 200 on success
/page-left/VISITOR_IDUse the visitor ID on leaving the page to record the total spent time.Only status code 200 on success

⁠Questions?

Don't hesitate to open an issue ^^

Tag summary

Content type

Image

Digest

sha256:1e884ba6b…

Size

31.6 MB

Last updated

4 months ago

Requires Docker Desktop 4.37.1 or later.