# Collect your first flows

In this tutorial, you install *Akvorado* on your own server and connect one
router to it. At the end, the graphs you learned to read in the [first
tutorial](explore) show your own traffic.

Count about half an hour, most of it waiting for the containers to start.

Before you begin, you need:

- a Linux machine with [Docker](https://docs.docker.com/engine/install/) Engine
  v23 or later and [Docker Compose
  v2](https://docs.docker.com/compose/install/), with at least 16 GB of RAM and
  50 GB of free disk (see the [requirements](install#requirements)),
- one router you can configure, able to export NetFlow, IPFIX or sFlow, and to
  answer SNMP requests coming from that machine.

On Debian, the package to install is `docker-compose`. On Ubuntu, it is
`docker-compose-v2`. On macOS, install the `docker-compose` formula from
Homebrew.

> [!TIP]
> Check your version of Docker with `docker version -f '{{ .Server.Version }}'`.
> Anything older than v23 fails in ways that are hard to diagnose.

## Start Akvorado

Download the *Docker Compose* setup and start it:

```console
# mkdir akvorado
# cd akvorado
# curl -sL https://github.com/akvorado/akvorado/releases/latest/download/docker-compose-quickstart.tar.gz | tar zxvf -
# docker compose up --wait
```

The first start takes a few minutes: the images are downloaded and started. The
command returns when every service is healthy.

Open `http://127.0.0.1:8081` in a browser (or replace `127.0.0.1` with the IP
address of your server). You should get the same interface as the demo site,
with empty graphs. This is expected: no router sends anything yet.

## Let Akvorado talk to your router

Flows contain interface indexes, not interface names. *Akvorado* polls your
router with SNMP to translate them. Open `config/outlet.yaml` and set your read
community:

```yaml
metadata:
  providers:
    - type: snmp
      credentials:
        ::/0:
          communities: your-community
```

`::/0` means “every exporter”. If your routers use different communities, use
one entry per subnet instead. SNMPv3 is also supported, with the keys described
in the [configuration reference](configuration#snmp-provider).

## Describe your interfaces

This step decides whether the console shows anything at all, so do not skip it.

*Akvorado* needs to know which interfaces face the outside world. It marks each
one as external or internal, and by default the console only counts the traffic
entering through an external interface. Without this, the home page and the
graphs will be empty.

The rules are in the same file, under `core`. The shipped ones expect interface
descriptions that start with the type of connection, like `Transit: Cogent` or
`IX: FranceIX`:

```yaml
core:
  interface-classifiers:
    - |
      ClassifyConnectivityRegex(Interface.Description, "^(?i)(transit|pni|ppni|ix):? ", "$1") &&
      ClassifyProviderRegex(Interface.Description, "^\\S+?\\s(\\S+)", "$1") &&
      ClassifyExternal()
    - ClassifyInternal()
```

If your descriptions follow another convention, you need to adapt the regular
expressions. The first one match `transit`, `pni`, `ppni`, `ix` regardless of
case. So your interface descriptions should start with one of these. The second
regular expression skip the first word and use the second word as the provider
name. If both succeed, the interface is classified as external. Any interface
failing these checks get classified as internal.

Rules are tried in order. Once an interface is classified, a later rule cannot
change it, so the catch-all rule goes last. The [configuration
reference](configuration#classification) describes the complete language.

To write your own, start from the descriptions your router advertises. On most
equipment, these are the `ifAlias` values:

```console
$ snmpwalk -v 2c -c your-community 203.0.113.1 ifAlias
IF-MIB::ifAlias.10 = STRING: Transit: Cogent 1-3834938493
IF-MIB::ifAlias.11 = STRING: PNI: Netflix (WL6-1190)
IF-MIB::ifAlias.20 = STRING: core
```

Some routers do not implement `ifAlias`. *Akvorado* then uses `ifDescr`, so walk
that one instead to see what the rules receive.

Copy one of them into [regex101](https://regex101.com/), and build your pattern
there. Set the flavor to “Golang” in the left panel: *Akvorado* uses the [Go
syntax](https://github.com/google/re2/wiki/Syntax). Put the value you want to
keep inside a group, then select the “List” function and type `$1` in its box.
You get one line per description, holding what the third argument of the rule
computes. This is the value stored in `InIfConnectivity` or in `InIfProvider`,
after being converted to lower case.

The two rules above are ready to be edited, [the connectivity
one](https://regex101.com/r/KeBpV7/2/list-substitution) and [the provider
one](https://regex101.com/r/sx7aAB/2/list-substitution).

> [!TIP]
> When you copy a pattern into the rule, double the backslashes: write `\\d` for
> a digit and `\\s` for a space. As the rule is a string in a YAML file, a single
> backslash does not reach the regular expression engine.

Regular expressions are easy to get wrong. An LLM can write the whole block for
you. Give it the reference documentation and your own descriptions. In the
example below, they do not follow the convention of the shipped rules: the
provider comes first and the type of connection is in brackets.

```
Read this page about the classification language of Akvorado:
https://demo.akvorado.net/api/v0/console/docs/configuration

Here are the descriptions of the interfaces of my router:

Cogent [TRANSIT] AS174 / 1-3834938493
Netflix [PNI] AS2906 / WL6-1190
FranceIX [IX] AS51706
dc3-edge1 [BACKBONE]
dc3-edge2 [BACKBONE]

Write the interface-classifiers block for config/outlet.yaml. External
interfaces get their connectivity type and their provider, everything else is
internal. Answer with the YAML block only to paste in my configuration.
```

Paste the answer under `core` in `config/outlet.yaml`. You can check the regular
expressions it wrote with the two links above.

After applying a change, you need to restart the outlet:

```console
# docker compose restart outlet
```

## Send flows from your router

Configure your router to sample its traffic and to send it to the machine that
runs *Akvorado*. The ports are:

- 2055 for NetFlow,
- 4739 for IPFIX,
- 6343 for sFlow.

The exact commands depend on the platform. Take the snippet for yours in the
[exporters guide](exporters) and adapt the addresses. Sample on ingress,
on every interface, and use active and inactive timeouts of 10 seconds.

If you have no router at hand, a Linux machine can also export flows with
[pmacct or ipfixprobe](exporters#gnulinux).

## Check that the flows arrive

> [!NOTE]
> Run the `curl` commands below on the server itself. Port 8080 exposes the
> metrics and the configuration without authentication, so it is only published
> on the loopback interface. Only port 8081, the console, is reachable from
> outside.

The inlet counts the packets it receives, per exporter:

```console
$ curl -s http://127.0.0.1:8080/api/v0/inlet/metrics | grep 'akvorado_inlet_flow_input_udp_packets'
akvorado_inlet_flow_input_udp_packets_total{exporter="203.0.113.1",listener=":2055",worker="0"} 128
```

If your router is not in the list, it does not reach the inlet. If it is, ask
the outlet for one processed flow:

```console
$ curl -s http://127.0.0.1:8080/api/v0/outlet/flows\?limit\=1
{"TimeReceived":1753631373,"SamplingRate":1000,"ExporterAddress":"::ffff:203.0.113.1","InIf":10,[...]}
```

A flow with an `InIfName` and an `InIfBoundary` means the whole chain works: the
router exports, the inlet receives, the outlet enriches. When something is
missing, the [troubleshooting guide](troubleshooting) goes through each
component in order.

## Look at your traffic

Wait a few minutes for the data to pile up, then open
`http://127.0.0.1:8081` again. The home page counts your flows and lists your
exporter. In the “Visualize” tab, the default graph shows your top source AS
numbers.

You now have a working collector. From here:

- add your other routers, one at a time,
- give *Akvorado* your BGP routes over BMP to get AS paths and communities, as
  described in the [configuration reference](configuration#routing),
- read the [operating guide](operating) before you rely on this setup.
