The general pattern for the long-running SCION services (Router, Control Service, Gateway, Daemon), is to load a .toml configuration file which is specified with a --config option when starting the service. This configuration file specifies all options for running the service, in particular the configuration directory from which all other configuration files are read.

The set of required configuration files differs between the applications. The configuration files are organized specifically to allow sharing the configuration directory between different services.

Configuration .toml

This configuration is a TOML-file.

The following options are implemented by all applications.

log.console.level = "debug"|"info"|"error" (Default: "info")

Log level at startup.

The log level can be changed at runtime via the HTTP API.

log.console.format = "human"|"json" (Default: "human")

Encode the log either in a human oriented form or json.

log.console.disable_caller = <boolean>

If true, disable annotating logs with the calling function’s file name and line number. By default, all logs are annotated.

metrics.prometheus = <string>

Address on which to export the common HTTP API, in the form host:port, ip:port or :port. The eponymous prometheus metrics can be found under /metrics, but other endpoints are always exposed as well.

If not set, the HTTP API is not enabled.

Database Connections

The services use different SQLite database files, with paths and advanced connection options configured individually. The pattern is:

some_db.connection = <string>

File path or SQLite URI for SQLite database.

some_db.max_open_conns = <int> (Default: 1)

Sets sets the maximum number of open connections to the database.

This should be left at 1 for SQLite databases.

some_db.max_idle_conns = <int> (Default: 2)

Sets the maximum number of connections in the idle connection pool. If this value is higher than max_open_conns, then the effective value is the same as max_open_conns.

This should be left > 0 for SQLite databases, in particular if an in-memory database is used.


The topology.json file of an AS specifies all the inter-AS connections to neighboring ASes, and defines the underlay IP/UDP addresses of services and routers running in this AS. The topology information is needed by Router and Control Service instances, and also by end-host applications (including the Gateway) which usually obtain it indirectly from the Daemon running on the same host.


The topology.json configuration file contains information that is not relevant for all consumers of the file.

For the sake of simplicity, you can use the same topology.json file on all SCION components within the SCION AS. In more advanced configurations, an extract of the topology.json file can be presented to each specific component.

The structure of the configuration is presented as a pseudo-JSON with a more detailed explanation of the individual fields below.

Pseudo-JSON description of the structure of the topology.json configuration file.
   "isd_as": <isd-as>,
   "attributes" = [<"core">?]
   "mtu": <int>,
   "border_routers": {
      <router-id>: {
         "internal_addr": <ip|hostname>:<port>,
         "interfaces": {
            # ... interfaces definitions ... (see below)
      # ...
   "control_service": {
      <cs-id>: {
         "addr": <ip|hostname>:<port>
      # ...
   "discovery_service": {
      <ds-id>: {
         "addr": <ip|hostname>:<port>
      # ...
Each interfaces entry defines one inter-domain link to a neighboring AS.
<interface-id>: {
   "isd_as": <neighbor-isd-as>,
   "link_to": <"parent"|"child"|"peer"|"core">,
   "mtu": <int>,
   "underlay": {
      "local": "<ip|hostname>:<port>", # or just ":<port>"
      "remote": "<ip|hostname:port>",
   "bfd": {              # optional
      "disable": <bool>,
      "detect_mult": <uint8>,
      "desired_min_tx_interval": <duration>,
      "required_min_rx_interval": <duration>
isd_as = <isd-as>, required

The ISD-AS of this AS.

attributes = [<"core">?], default []

Role of this AS. ["core"] for core ASes, [] for non-core ASes.


Historical relict; there used to be multiple different attributes (“core”, “issuing”, “authoritative”, “voting”) which could apply a more fine granular role configuration. This functionality has moved into different places, only “core” remains.

mtu = <int>, required

Common Maximum Transmission Unit in bytes for SCION packets (SCION headers and payload) for intra-AS connections. This is the minimum MTU between any two internally connected border router interfaces.


Identifier for a border router instance. Matches the of a router instance.

internal_addr = <ip|hostname:port>, required

UDP address on which the router receives SCION packets from sibling routers and end hosts in this AS.


The interface ID for an inter-domain link.

In this topology.json file, the ID is contained in a string.

isd_as = <isd-as>, required

The ISD-AS of the neighboring AS.

Type of the link relation to the neighbor AS. See Link Types.

remote_interface_id = <int>

The interface ID for the corresponding interface in the neighboring AS.

This is required if, and only if, link_to is peer.

This remote_interface_id is used when announcing peering links as part of AS Entries in PCBs (see Path Exploration (Beaconing)). During path-segment combination, this interface ID, will then be used together with the ISD-AS to match up the peering entries from AS entries in different path segments.

If remote_interface_id is set incorrectly, the peering entries cannot be matched up correctly, resulting in missing or broken end-to-end paths:

  • If the remote_interface_id does not match any interface ID used for peering links in the neighboring AS, the segment combination will not find paths making use of this interface.

  • If two ASes are connected by multiple peering links and remote_interface_id matches the wrong interface ID, an incorrect path may be constructed which will be rejected in the data plane (i.e. the routers will drop all packets).

mtu = <int>, required

Maximum Transmission Unit in bytes for SCION packets (SCION headers and payload) on this link.

underlay, required for "self"

Underlay specifies the local addresses used for the underlay IP/UDP connection to the neighbor router. These addresses are only relevant to the router that operates this link, i.e. the router instance with matching <router-id>.

The underlay.local is the address of this side of the link, while underlay.remote is the address of the remote side of the link.

In the configuration for the corresponding interface in the neighbor AS, these addresses are exactly swapped.

remote = <ip|hostname>:<port>, required

The IP/UDP address of the corresponding router interface in the neighbor AS.

local = [<ip|hostname>]:<port>, required

The IP/UDP address of this router interface. The IP or hostname can be ommitted; in this case the router will just bind to a wildcard address.

public = <ip|hostname>:<port>, deprecated

The IP/UDP address of this router interface.


Replaced by underlay.local.

bind = <ip>, deprecated

IP address of this router interface. Overrides IP of underlay.public.


Replaced by underlay.local.

bfd, optional

Bidirectional Forwarding Detection (BFD) is used to determine the liveness of the link by sending BFD control messages at regular intervals.

These settings are only relevant to the router that operates this link, i.e. the router instance with matching <router-id>.

disable = <bool>, default router.bfd.disable

See router.bfd.disable.

Disable BFD, unconditionally consider the connection alive.

detect_mult = <uint8>, default router.bfd.detect_mult

See router.bfd.detect_mult.

After detect_mult consecutively missing control packets, the BFD session is considered “down” and is reset.

desired_min_tx_interval = <duration>, default router.bfd.desired_min_tx_interval

See router.bfd.disired_min_tx_interval.

Defines the frequency at which this router should send BFD control messages for this inter-domain link. The effective interval is the result of negotiating with the remote router during session establishment; the value will be max(desired_min_tx_interval, remote.required_min_rx_interval).

required_min_rx_interval = <duration>, default router.bfd.required_min_rx_interval
See :option:`router.bfd.required_min_rx_interval <router-conf-toml required_min_rx_interval>`.

Defines an upper bound for the frequency at which this router wants to receive BFD control messages for this inter-domain link. The effective interval at which the remote router will send control messages is the result of negotiating with the remote router during session establishment; the value will be max(remote.desired_min_tx_interval, required_min_rx_interval).


Identifier for a control service instance. Matches the of a control service instance.

addr = <ip|hostname>:<port>, required

The address of the control service. This is both a UDP and TCP address;

  • The UDP address is the underlay address for the control service’s anycast address. This is used when communicating with control services in other SCION ASes, using SCION.

  • The TCP address is used to serve the grpc API to end hosts in the local AS.


Identifier for a discovery service instance.


The implementation of the discovery service is part of the control service. This usually points to a control service instance.

addr = <ip|hostname>:<port>, required

See control_service.addr, above.

Duration Format

Where duration values are loaded from configuration options, the following format is expected:


The unit suffixes have their usual meaning of y year, w week, d day, h hour, m minute, s second, ms millisecond, us or µs microsecond, and ns nanosecond.

Mixed unit durations are not supported (e.g. 1h10m10s is not supported). The long duration units are simple factors, not calendar offsets:

  • d is always 24 hours

  • w is always 7 days

  • y is always 365 days


Known issue. If an unknown route is accessed (e.g., /this-does-not-exist), the HTTP reply will respond as if the / route were used and print an HTML page with links to all exposed APIs. This response will have a 200 (OK) HTTP Status Code.

The following APIs are exposed by most applications:

  • /: (EXPERIMENTAL) - Method GET. Returns an HTML page containing links to exposed APIs.

  • /config: (EXPERIMENTAL)

    • Method GET. Prints the TOML representation of the config the application is currently using.

  • /info: (EXPERIMENTAL)

    • Method GET. Prints a plaintext representation of general information about the application. Amongst others, the information includes version, process ID, and user/group IDs.

  • /log/level: (EXPERIMENTAL)

    • Method GET: Returns the current logging level, in JSON.

    • Method PUT: Sets the current logging level. Either JSON or URL encoded request body is supported.For example, to set the logging level to debug run:

      curl -X PUT "" -d level=debug
      curl -X PUT "" -H "Content-Type: application/json" -d '{"level":"debug"}'

      If the content type is set to application/x-www-form-urlencoded (curl default), the endpoint expects a URL encoded request body. In all other cases, a JSON encoded request body is expected.

  • /metrics:

    • Method GET: Returns the Prometheus metrics exposed by the application.

  • /debug/pprof:

    • Serves runtime profiling data in the format expected by the pprof visualization tool. See net/http/pprof for details on usage.