DSPS server can load YAML based configuration file.
To pass configuration file, use command line argument: ./dsps path-to-config-file.yml
# Configuration file example
storages: # see ./storage/README.md for more info
myRedis1:
redis:
singleNode: 'localhost:6379'
http:
port: 3099
realIpHeader: 'X-Forwarded-For'
trustedProxyRanges:
- 192.168.0.0/16
discloseAuthRejectionDetail: false
logging:
category:
auth: WARN # Set to INFO if you want auth rejection logs
"*": INFO
attributes:
machineID: my-machine-id
channels:
- regex: 'chat-room-(?P<id>\d+)'
expire: 15m
webhooks:
- url: 'http://localhost:3001/you-got-message/room/{{.channel.id}}'
admin:
auth:
bearer:
- 'my-api-key'
regex string
means YAML string that constructs golang compatible regular expression (e.g.'chat-room-(?P<id>\d+)'
)template string
means YAML string that follows golang Template syntax (e.g.'http://localhost:3001/room/{{.channel.id}}'
)duration string
means YAML string that follows golang ParseDuration syntax (e.g.'1h30m'
)
You can configure storages under storages
block.
# ex. Simple (non-Cluster) Redis
storage:
myRedisA: # Keep in mind that this name ("myRedisA") should not be changed, otherwise causes data-loss.
redis:
singleNode: 'my-redis-server-host-1:6379'
myRedisB:
redis:
singleNode: 'my-redis-server-host-2:6379'
Configuration detail depends on type of the storage, see storage document for detail.
Heads Up : DSPS uses on-memory storage if no configuration given, should change it for production use.
Configuration items under http
:
port
(number, default3000
): TCP port to listen for HTTP requests- You can override this value with
--port
command line option
- You can override this value with
listen
(string, optional): Listen string (e.g. ":3000"), this option overridesport
- With some security software, you may need to specify local IP as such as
127.0.0.1:3000
due to MTIM proxy problem.
- With some security software, you may need to specify local IP as such as
pathPrefix
(string, optional): Prefix to add all endpoints- e.g. If
pathPrefix
is/foo/bar
, endpoint/probe/readiness
is served as/foo/bar/probe/readiness
- e.g. If
-
realIpHeader
(string, optional): HTTP header name contains reliable IP address of the client- Note that
admin.auth.networks
rely on this configuration.
- Note that
trustedProxyRanges
(list of string, optional): List of CIDR notation that trusted proxy lives indiscloseAuthRejectionDetail
(boolean, defaultfalse
): Show detail reason of 403 to clients, do not enable on productionidleTimeout
(duration string, default1h30m
): Max duration to keep idle connection, should be larger than keep-alive duration of clients/loadbalancer.readTimeout
(duration string, default10s
): Max duration to read request from clients.writeTimeout
(duration string, default60s
): Max duration since end of request header reading until request processing completion- Note that server automatically add
longPollingMaxTimeout
to this value
- Note that server automatically add
longPollingMaxTimeout
(duration string, default30s
): Max duration of the long-polling requests.gracefulShutdownTimeout
(duration string, default5s
): Timeout to await end of running requests.-
defaultHeaders
(string to string map, optional): Always send those response headers- Server send some headers by default, you can disable them by setting empty string as a value.
Configuration items under logging
:
category
(string to string map, optional) Log level threshold for eachcategory
attribute of the log entries.- Available thresholds are
DEBUG
,INFO
,WARN
"*"
category controls default threshold and it's default isINFO
--debug
command line option overrides this config completely
- Available thresholds are
attributes
(string to string map, optional): Attributes set to every log records- Useful to set machine ID etcetera.
Configure telemetry
block to enable tracing and metrics.
telemetry:
ot:
tracing:
enable: true
sampling: 0.003
batch:
maxQueueSize: 2048
timeout: 5s
batchSize: 512
attributes:
host.name: hostname-of-the-instance
my.attribute: "foo bar"
exporters:
stdout:
enable: true
Configuration items under telemetry.ot.tracing
(OpenTelemetry tracing):
enable
(boolean, defaultfalse
): true to enable OpenTelemetrysampling
(floating number, default1.0
): Sampling ratio to capture or not capture traces- Note that if tracing propagated from upstream, this ratio is not applied
batch.maxQueueSize
(number, default2048
): On-memory buffer size to buffer tracing spansbatch.timeout
(duration string, default5s
): Maximum duration to keep trace in buffer for bulk transmissionbatch.batchSize
(number, default512
): Number of traces to submit at once.attributes
: (string to any map): Attributes of resource to add to traces- See official resource semantic conventions document for standard naming
exporters
: Setup tracing exporters, see below.
Configuration items under telemetry.ot.exporters.stdout
:
enable
(boolean, defaultfalse
): true to output traces to stdoutquantiles
(list of numbers, default0.5, 0.9, 0.99
): quantiles for metrics sampling
Configuration items under telemetry.ot.exporters.gcp
:
enableTrace
(boolean, defaultfalse
): true to output traces to GCP Cloud TraceprojectID
(string, default""
): Set non-empty string to specify GCP Project ID
Configure sentry
block to enable Sentry error monitoring tool.
DSPS server sends events such as outgoing webhook failure to the Sentry when you enable it.
# To enable Sentry, you need to set SENTRY_DSN environment variable.
sentry: # Fine-tuning configuration example
serverName: my-server-name
environment: my-production
tags:
my_tag: value
context:
my_context: value
sampleRate: 1.0
ignoreErrors:
- "something .+"
disableStacktrace: false
hideRequestData: false
flushTimeout: 15s
To enable sentry, you must set SENTRY_DSN
environment variable. It's value should be DSN string of the Sentry server.
Configuration items under telemetry.ot.tracing
(OpenTelemetry tracing):
serverName
(string, default is hostname): Server name attribute to send to sentryenvironment
(string, optional): Environment name send to sentrytags
(string to string map, optional): Set tag valuescontexts
(string to string map, optional): Set context valuessampleRate
(number, default1.0
): Ratio of the sampling, between0.0
to1.0
.ignoreErrors
(list of regex string): If an event matches to one or more of the regex, ignore themdisableStacktrace
(boolean, defaultfalse
): If true, omit stacktrace.hideRequestData
(boolean, defaultfalse
): If true, do not send request body data.flushTimeout
(duration string, default15s
): Timeout to flush sentry events on application shutdown.
You can configure channels under channels
block.
Each channel configuration must have regex
to match with name of a channel.
If multiple configuration match with a channel, server merges them.
If you configure one or more channels
blocks, DSPS server will reject unmatched channel name.
If channels
configuration is empty, DSPS server automatically define .+
channel configuration to accept any channel name.
Configuration items under channels[n]
:
regex
(regex string, required): regex string to match with name of a channel- Must match with entire string of the channel name (no need to write
^
nor$
). - You can use named group/subexp (e.g.
(?P<id>\d+)
). In the channel configuration, captured value of the group is visible to template strings under.channel
(e.g.{{.channel.id}}
).
- Must match with entire string of the channel name (no need to write
expire
(duration string, default30m
): DSPS server may discard inactive subscribers & messages after this duration- Duration counts from last access of the subscriber or sent time of the message.
- DSPS may not resend after this expiration duration, so that this value must be larger than client's polling period if you polling.
- If multiple channel configuration matches to a channel, largest value wins.
- If outgoing webhook is configured, expire value must be larger than maximum webhook time includes webhook timeout and retry interval
You can configure outgoing webhook to send messages from DSPS server to any HTTP(S) services.
DSPS server calls given HTTP(S) endpoint for each incoming message.
See outgoing webhook document for more info.
# Webhook with retry configuration example
channels:
- regex: 'chat-room-(?P<id>\d+)'
# Must be larger than final retry attempt time
expire: 15m
webhooks:
- method: PUT
url: 'http://localhost:3001/you-got-message/room/{{.channel.id}}'
timeout: 30s
connection:
max: 1024
maxIdleTime: 3m
retry:
# Enable 3 retries as below:
# 1st retry: 3 * 1.5^0 ± 1.5 = 3 ± 1.5 [sec] after first webhook attempt
# 2nd retry: 3 * 1.5^1 ± 1.5 = 4.5 ± 1.5 [sec] after 1st retry
# 3rd retry: 3 * 1.5^2 ± 1.5 = 6.75 ± 1.5 [sec] after 1st retry
count: 3
interval: 3s
intervalMultiplier: 1.5
intervalJitter: 1s500ms
headers:
User-Agent: My DSPS server
X-Chat-Room-ID: '{{.channel.id}}'
If there are multiple webhooks, DSPS server calls them concurrently. Configuration order of the webhooks has no meaning.
Configuration item under channels[n].webhooks
:
method
(string, defaultPUT
): HTTP method to send.url
(template string, required): Full URL to send messagetimeout
(duration string, default:30s
): Timeout of the webhook callconnection.max
(integer, default:1024
): Max connections between DSPS server and webhook target- This configuration also controls of
Transport.MaxIdleConnsPerHost
- This configuration also controls of
connection.maxIdleTime
(duration string, default:3m
): Max idle time to keep-alive connectionsretry.force
(boolean, default:false
): true to retry any errors (such as404 Not Found
)retry.count
(integer, default:3
): 0 to disable retry, 1 to retry only once, ...retry.interval
(duration string, default:3s
): Retry base intervalretry.intervalMultiplier
(float, default:1.5
): Exponential backoff factor, multiply to the previous intervalretry.intervalJitter
(duration string, default:1s500ms
): Max range of the retry interval randomization, plus or minus to the resulted intervalheaders
(string to template string map, optional): HTTP headers to set for each outgoing requestsmaxRedirects
(number, default10
): Max count of redirects to follow.
To protect endpoints, can validate signed JSON Web Tokens (JWT, RFC 7519).
channels:
- regex: 'chat-room-(?P<id>\d+)'
jwt:
iss:
- https://issuer.example.com/issuer-url
aud:
- https://my-service.example.com/
keys:
RS256:
- path/to/public-key-file.pem
claims:
chatroom: '{{.channel.id}}'
role:
- 'admin'
- 'user'
clockSkewLeeway: 5m
If this configuration present on the channel, clients must present valid JWT with Authorization: Bearer <jwt>
request header for every API call.
In addition, you can revoke JWT with revocation API if JWTs has jti
(unique ID claim).
Configuration item under channels[n].jwt
:
iss
(list of string, required): List of JWT issuers.iss
claim of the JWT must exactly match with one of this list.aud
(list of string, optional): List of JWT recipients. One or more value of theaud
claim of the JWT must exactly match with one of this list.keys
(map of string to string list, required): Key is JWT signing algorithm name such asRS512
, value is list of file paths of signing key.- For RSA alg or ECDSA alg (such as
RS512
,ES512
), the file should be PEM encoded x509 certificate that contains public key - For HMAC alg such as
HS512
, content of the file should be Base64 encoded key - For
none
alg, empty list is allowed (none: []
)none
alg is easy way for testing purpose, but do NOT usenone
on production.
- For RSA alg or ECDSA alg (such as
claims
(map of string to template string or list of template strings, optional): Validation rule of custom claims- For example,
foo: 'bar'
means JWT must have custom claim namedfoo
with a valuebar
- You can use template string to validate value (e.g.
chatroom: '{{.channel.id}}'
means custom claimchatroom
must match withid
ofchannels.regex
). - If value of JWT claim is boolean or number, validator convert them to string (e.g.
"true"
,"3.14"
)
- For example,
clockSkewLeeway
(duration string, default5m
): When validate time-based claims such asexp
,nbf
, allow clock skew with this tolerance.
admin:
auth:
networks:
- 10.1.2.0/8
bearer:
- 'my-api-key'
Configuration item under admin
:
auth.networks
(list of CIDR string, optional): List of CIDR IP ranges to accept admin API callsauth.bearer
(list of string, optional): List of API keys required to call admin APIs- To call admin APIs, client need to send token as
Authorization: Bearer {token}
header - By default or if empty list given, server automatically generate random string on start.
- To call admin APIs, client need to send token as