Pushpin has two primary configuration files: pushpin.conf
and routes
. The pushpin.conf
file refers to the routes
file via the routesfile
field:
[proxy]
routesfile=routes
If a relative path is used, then the file is looked up relative to the location of pushpin.conf
.
It is generally not necessary to edit pushpin.conf
. You’ll spend more time with the routes file. However, if you need to change bind addresses or ports, or global settings that affect all routes, then this is the file to work with.
The pushpin.conf
file is an INI-style formatted config file with four sections: global
, runner
, proxy
, and handler
. Below are descriptions of the public fields:
Global:
libdir={path}
: Path to pushpin library files (e.g. /usr/lib/pushpin). If unspecified, the libdir will be derived relatively (to allow launching Pushpin from within the source tree without installation).rundir={path}
: Where the runner should place runtime files such as pid files.include=internal.conf
: Tells Pushpin to find additional configuration in a separate file called internal.conf. These contain “private” settings used by Pushpin components that may change between releases. You can override them in pushpin.conf at your own risk.ipc_prefix={string}
: Prefix all ZeroMQ IPC filenames. Normally not used directly. Pass --id
to the runner instead.port_offset={N}
: Increment all ZeroMQ TCP ports and the HTTP control server port. Normally not used directly. Pass --id
to the runner instead.stats_connection_ttl={N}
: TTL (seconds) to use in connection stats messages.stats_connection_send={true|false}
: Whether to send individual connection stats.Runner:
When you run the pushpin
executable, you’re invoking a runner that simply runs other programs. The runner program uses the runner section of pushpin.conf to know what to launch and how.
services={stringlist}
: Comma-delimited list of services to run. If you want to run any of the services independently from the runner, you can remove them from this list. For example, if you are debugging pushpin-proxy
, you can remove it from the services list, run pushpin
to launch everything except pushpin-proxy
, and then run the pushpin-proxy
executable manually (perhaps with gdb or valgrind or such). Technically you can run each process manually and not use the runner at all!http_port={port}
: Port to listen on for non-SSL HTTP/WebSocket client connections. Prefix with {address}:
to bind to a specific interface, e.g. http_port=127.0.0.1:7999
.https_ports={ports}
: Comma-delimited list of ports to listen on for SSL HTTP/WebSocket client connections. Prefix with {address}:
to bind a specific interface. See the SSL section.local_ports={ports}
: Unix paths to listen on for HTTP/WebSocket client connections. Each port may contain parameters user
, group
, and mode
for setting the permissions of the socket file, for example: local_ports=/tmp/pushpin.sock?user=pushpin&mode=777
.configdir={path}
: Path to runner config dir. This is where service config template files live, among other things.logdir={path}
: Where the runner should write logfiles.log_level={N}
: Comma-separate list of log levels. Entries can be either a number by itself (to specify the default log level) or using the form name:level
(to specify the level of a specific process). For example, log_level=2
means set the default log level to 2, which would be used by all processes, whereas log_level=2,pushpin-handler:3
would mean use log level 3 for the pushpin-handler
process and log level 2 for all other processes.client_buffer_size={N}
: Buffer size for each client connection. The full request header from the client must fit in this buffer. Default is 8192.client_maxconn={N}
: Maximum number of client connections. Default is 50000.allow_compression={true|false}
: Whether connections can use compression.mongrel2_bin={path}
: Full path of mongrel2 executable to use. Useful if you want the runner to launch a development version, e.g. mongrel2_bin=/home/user/dev/mongrel2/bin/mongrel2
.m2sh_bin={path}
: Full path of m2sh executable to use.zurl_bin={path}
: Full path of zurl executable to use.Proxy:
Configuration used by the pushpin-proxy
program.
workers={N}
: Number of worker threads to run. Default is 1.routesfile={path}
: Path to the “routes” file. If a relative path is used, then the file is looked up relative to the location of pushpin.conf.debug={true|false}
: Pushpin error responses are normally vague, in order to not leak any internal information. However this can make debugging difficult. If debug mode is enabled, then error responses will be more informative.auto_cross_origin={true|false}
: If true, enable auto cross-origin mode, which provides automatic CORS and JSONP wrapping as-needed. See Auto Cross-Origin.accept_x_forwarded_protocol={true|false}
: If true, then process X-Forwarded-Proto
or X-Forwarded-Protocol
on incoming requests.set_x_forwarded_protocol={proto-only|true|false}
: If proto-only
, set the X-Forwarded-Proto
header when proxying. If true (deprecated), set the X-Forwarded-Proto
header and the non-standard X-Forwarded-Protocol
header.x_forwarded_for={instructions}
: Comma-delimited list of instructions for handling X-Forwarded-For
headers. See the X-Forwarded headers section.x_forwarded_for_trusted={instructions}
: Comma-delimited list of instructions for handling X-Forwarded-For
headers from senders verified with upstream_key
. See the X-Forwarded headers section.orig_headers_need_mark={header list}
: Magic parameter to help enable perfect header preservation across proxying. You almost certainly don’t need this, but if you think you do, then ask about it on the mailing list. Used by WebhookInbox.accept_pushpin_route={true|false}
: If true, then allow route selection via the Pushpin-Route
header. For example, if a request contains Pushpin-Route: foo
, and there is a route with id=foo
in the routes file, then that route should be selected.cdn_loop={value}
: Value to append to the CDN-Loop header.log_from={true|false}
: Include client IP address in request logs.log_user_agent={true|false}
: Include client User-Agent header in request logs.sig_iss={issuer}
: When signing outbound requests, use as the JWT iss
claim field. Default is “pushpin”.sig_key={key}
: When signing outbound requests, use as the JWT key. Prepend value with base64:
to use a Base64-encoded binary key. Prepend value with file:
to read the key from a file.upstream_key={key}
: Used to chain multiple Pushpin instances on a network path, which enables subscription forwarding. Set to the key used by the instance in front of this one. Prepend value with base64:
to use a Base64-encoded binary key.sockjs_url={url}
: URL of SockJS client. Needed for the SockJS iframe transport to work. This only applies to routes with SockJS capability enabled.updates_check={report|check|off}
: Periodically check the updates.fanout.io server for a new version of Pushpin, and log a message when a new version is available. If set to report
, also pass along anonymous usage information. No personally identifiable information is sent.organization_name={string}
: A voluntary way to send identifying information during the updates check. This helps the Pushpin developers understand who is using the software. If you enjoy this software, set this field to your company name! :)Handler:
Configuration used by the pushpin-handler
program.
push_in_spec={spec}
: ZeroMQ spec (bind PULL) for receiving publish commands.push_in_sub_specs={specs}
: Comma-separated list of ZeroMQ specs (bind SUB) for receiving published messages.push_in_sub_connect={true|false}
: Whether the above SUB socket should connect instead of bind. Default is false.push_in_http_addr={addr}
: TCP address to bind on for receiving publish commands via HTTP.push_in_http_port={port}
: TCP port to bind on for receiving publish commands via HTTP.push_in_http_max_headers_size={N}
: Maximum headers size in bytes when receiving publish commands via HTTP. Default is 10000.push_in_http_max_body_size={N}
: Maximum body size in bytes when receiving publish commands via HTTP. Default is 1000000.stats_spec={spec}
: ZeroMQ spec (bind PUB) for sending stats.command_spec={spec}
: ZeroMQ spec (bind REP) for receiving commands.message_rate={N}
: Max messages-per-second to deliver. If omitted, don’t rate limit at all.message_hwm={N}
: Don’t buffer more than this many published messages. Only has effect when message_rate
is also set.message_block_size={N}
: Specify the number of bytes of content in a message that shall constitute a content “block”. Partial blocks count as a full block. For example, if this parameter set to 1024
, and a message with 2500 bytes of content is being processed, then the message will be considered to have 3 blocks of content.message_wait={N}
: If a sequenced message is received out of order, wait this many milliseconds before going ahead and dispatching the message anyway.id_cache_ttl={N}
: Number of seconds to remember each message ID in order to discard duplicate messages. Set to 0 to disable de-duping.connection_subscription_max={N}
: Maximum number of subscriptions allowed per connection.subscription_linger={N}
: When an HTTP response
subscription finishes, linger the forwarded subscription (via stats and SUB
socket) for this many seconds. This way, forwarded subscriptions persist across long-polling requests.stats_subscription_ttl={N}
: TTL (seconds) to use in subscription stats messages.stats_report_interval={N}
: Interval (seconds) to send report stats.stats_format={tnetstring|json}
: Output format for stats socket. Default is tnetstring.prometheus_port={port}
: Port to listen on for serving Prometheus metrics. Prefix with {address}:
to bind to a specific interface, e.g. prometheus_port=127.0.0.1:9000
. Prefix with ipc://
to bind to a Unix path, e.g. prometheus_port=ipc:///tmp/pushpin-metrics
.prometheus_prefix={string}
: String to prefix Prometheus metric names with. For example: prometheus_prefix=pushpin_
. Default is no prefix, i.e. an empty string.Spec templating:
For IPC specs, you can use template parameter {rundir}
to be substituted with the Pushpin run directory. For example, if the run directory is /var/run/pushpin
, and you specify an IPC spec as ipc://{rundir}/foo
, then it will be resolved to ipc:///var/run/pushpin/foo
during use.
The routes
file is a text file where each line specifies a proxying route. Here is an example file with three routes defined:
example.com 192.168.1.100:80
example.net 192.168.1.101:80
* 192.168.1.102:80
The first part of each route is the route condition, which may be a full domain or an asterisk to indicate any domain.
Using the above routes, if an incoming request’s Host
parameter matches example.com
or example.net
, then one of the domain-specific routes will be used. Otherwise, the last route will be used as a catch-all. Partial wildcards (e.g. example.*
) are not supported. Note that the ordering of the lines does not matter. The following file would produce the same results:
example.com 192.168.1.100:80
* 192.168.1.102:80
example.net 192.168.1.101:80
Further, there is only ever one possible route for a given incoming request, and Pushpin will prefer more-specific routes over less-specific routes. If two or more routes conflict with each other, then only the first will be used and the rest will be ignored.
To understand how to write routes, see Routes.
The format of a Pushpin route is a condition and then one or more routing targets, all separated by spaces.
For example, here’s a simple routes file containing one line:
* localhost:8000
This single route means proxy any incoming HTTP request or WebSocket connection to a server running on port 8000 of the same machine. The route condition may be a full domain or an asterisk to indicate any domain.
You can also specify more than one target. In that case, the later targets will be attempted for delivery if the earlier ones fail.
* target1:8000 target2:8000 target3:8000
Routing conditions and targets may contain optional parameters. For example:
example.com,ssl=yes target1:443,ssl,insecure
* target2:80
The above line would mean to route incoming HTTPS or WSS requests for example.com
to target1
, and the proxying should be done with SSL as well, but the certificate of the target server should not be checked. Requests for domains other than example.com
, or non-SSL requests for example.com
, would route to target2
. For further details about parameters, see the Condition Parameters and Target Parameters sections below.
Below are some more route examples.
Route HTTP traffic to port 8000 and WebSocket traffic to port 9000:
*,proto=ws localhost:9000
* localhost:8000
Since the most specific route is always preferred, every incoming WebSocket connection will use the first route.
Route non-SSL traffic to port 8000 and SSL traffic to port 8001:
*,ssl=yes localhost:8001
* localhost:8000
Route HTTP/HTTPS traffic to ports 8000/8001 and WebSocket (WS/WSS) traffic to ports 9000/9001:
*,proto=ws,ssl=yes localhost:9001,ssl
*,proto=ws localhost:9000
*,ssl=yes localhost:8001,ssl
* localhost:8000
Same as above, but more verbose:
*,proto=ws,ssl=yes localhost:9001,ssl
*,proto=ws,ssl=no localhost:9000
*,proto=http,ssl=yes localhost:8001,ssl
*,proto=http,ssl=no localhost:8000
Same as above, but don’t use SSL to communicate with the targets:
*,proto=ws,ssl=yes localhost:9001
*,proto=ws localhost:9000
*,ssl=yes localhost:8001
* localhost:8000
In addition to normal HTTP/WebSocket targets (indicated using the form host:port
), Pushpin can route to ZeroMQ targets as well. The protocol used is ZHTTP, which supports PULL/SUB and REQ/REP modes. Use a target of the form zhttp/spec
for PULL/SUB and zhttpreq/spec
for REQ/REP.
For example, here’s how to route via REQ/REP:
* zhttpreq/ipc://httphandler
Pushpin binds to the address spec. Handlers connect to it. ZeroMQ targets can be useful if you want to implement a push service without a web server.
proto={http|ws}
: Match only if the incoming connection uses a specific protocol.ssl={yes|no}
: Match only if the incoming connection uses SSL or not.path_beg={string}
: Match only if the first part of the request URI path matches this value. E.g. path_beg=/mypath
.path_rem={N}
: Remove N bytes from the beginning of the request URI before proxying. For example, if you want requests to /mypath
to route to the target server’s root, then you could do path_beg=/mypath,path_rem=7
.replace_beg={string}
: Replace the beginning part of the request URI matched by path_beg
. If path_beg
is not specified, then prepend the value to the request URI. If replace_beg
is set to an empty value, then remove the matched part.as_host={hostname}
: Override the Host header of the incoming request.sig_iss={issuer}
: When signing outbound requests, use as the JWT iss
claim field. Overrides sig_iss
in pushpin.conf.sig_key={key}
: When signing outbound requests, use as the JWT key. Prepend value with base64:
to use a Base64-encoded binary key. Prepend value with file:
to read the key from a file. Overrides sig_key
in pushpin.conf.id
: Set an optional identifier for the route. The id will be included in data emitted from Pushpin’s stats socket.prefix
: Prepend this value to all subscribed channel names. For example, if prefix=app1-
is set for a route, and the target server uses a GRIP instruction to subscribe a client to channel “foo”, then the client becomes subscribed to “app1-foo” instead.debug
: Enable debug mode. Requests to this route that result in an error will receive more informative error responses.aco
: Enable auto cross-origin mode, which provides automatic CORS and JSONP wrapping as-needed. See Auto Cross-Origin. Overrides auto_cross_origin=false
in pushpin.conf.jsonp_mode={basic|extended}
: In basic mode, the HTTP response body is wrapped in the JSONP callback. In extended mode, the entire HTTP response (headers and all) are encoded in JSON and then wrapped in the JSONP callback. The extended format is the same as expected by Pollymer. Default is extended.json_cb={param}
: Specify the query parameter that specifies the JSONP callback to use. Default is “callback”.json_body={param}
: Specify a query parameter that contains a JSON body for a JSONP request. If a client provides this query parameter, then the request body will be the query parameter’s value with Content-Type application/json. The presence of this parameter is enough for the request to be considered a JSONP request, as long as json_defcb
is also specified for the route. Otherwise, the client will need to supply a callback query parameter.json_defcb={name}
: The default JSONP callback name to used. This only comes into play if the query parameter specified by json_body
is detected in a request but without a callback parameter.orig_headers
: Magic parameter to help enable perfect header preservation across proxying. You almost certainly don’t need this, but if you think you do, then ask about it on the mailing list. Used by WebhookInbox.sockjs={string}
: Enable SockJS protocol compatibility at the specified path. SockJS may only be supported at one path location per route. If you want it to work from multiple paths, create additional routes with different path_beg
values.sockjs_as_path={string}
: Destination WebSocket path to use when proxying to the target. By default, this is the same as the sockjs
value.header={name}:{value}
: Header to add to all proxied requests.no_grip
: Disable GRIP capability. Proxying acts like a passthrough, and GRIP instructions are ignored.ssl
: Connect to target using SSL.insecure
: When connecting using SSL, don’t fail if the certificate is invalid.untrusted
: Don’t allow proxying to the internal network (specifically, the policies allowed by Zurl).host={hostname}
: Override the Host header when proxying. Similar to the Condition Parameter as_host
, except per-target.trust_connect_host
: Check certificate against the target host without having to change the host being requested.sub={channel}
: Automatically (and forcibly) subscribe connections to this channel. The channel cannot be unsubscribed. This parameter can be specified more than once. The route prefix
is not applied to the channel.over_http
: For WebSocket connections, use HTTP to communicate with the target server. (WebSocket only)one_event
: When over_http
is used, send only one event at a time to the target.ipc_file_mode={mode}
: For ZeroMQ targets using an ipc spec, set the permissions of the FIFO object using octal. E.g. ipc_file_mode=777
.Pushpin lets you manipulate the X-Forwarded-For
header using instructions specified in the x_forwarded_for
and x_forwarded_for_trusted
fields in the proxy section of pushpin.conf. Each field contains a comma-delimited list of instructions. If the request is determined to be from a trusted client (because the request’s Grip-Sig
header validates with the configured upstream_key
) then the x_forwarded_for_trusted
field is used for the request. Otherwise, the x_forwarded_for
field is used.
There are two instructions available. The order they appear doesn’t matter.
truncate:{N}
: Keep the rightmost N IP addresses of X-Forwarded-For
.append
: Append the IP address of the current request to X-Forwarded-For
.For example, if you set up Pushpin so that clients can directly access it, but you want to know the IP addresses of incoming clients, then you might want to use a configuration like this:
[proxy]
x_forwarded_for=truncate:0,append
This will completely replace the X-Forwarded-For
header to contain just the requesting client’s true IP address. The reason for the truncate is because we cannot trust this header if the client provides it.
On the other hand, if you set up Pushpin behind a layer 7 load balancer (such as HAProxy) that already manipulates the X-Forwarded-For
header in a similar fashion, then you can trust its value and simply append to it:
[proxy]
x_forwarded_for=append
You could also not bother appending to it, since usually only the leftmost IP address is interesting to backends anyway.
Pushpin can also interpret X-Forwarded-Proto
as well as set it when proxying, depending on the accept_x_forwarded_protocol
and set_x_forwarded_protocol
settings.
When Pushpin receives a WebSocket connection, it can proxy to the backend using a WebSocket connection, or it can send a series of HTTP requests that wrap WebSocket events. When using WebSockets, it is recommended to convert to HTTP so that the backend can service the connection statelessly. This is activated using the over_http
target parameter.
Also see the WebSocket-over-HTTP spec.
Incoming client connections are handled by Condure (or Mongrel2 in older setups). To listen for SSL connections, set the https_ports
field in the runner section of pushpin.conf
. For example:
[runner]
http_port=8000
https_ports=4430
The above configuration will instruct Pushpin to configure Condure to use two ports, one for SSL and one for non-SSL. Additionally, you need to provide default certificate files for each SSL port being listened on. In the above case, Condure will expect the files default_4430.crt
and default_4430.key
to exist in the runner/certs
directory. Both files should use PEM format, with the first file containing a concatenation of all certificates in the chain (minus the root cert) and the second file containing the private key of the primary certificate.
Server Name Indication (SNI) is supported. You can add additional certs named after the domains of the certs. For example, to support “example.com” via SNI, you’d want to put example.com.crt
and example.com.key
in the runner/certs
directory. For wildcard subdomains, put files named _.example.com.crt
and _.example.com.key
in the directory.
When proxying to targets, Pushpin will connect using SSL if the route has the ssl
target parameter set.