Fixie Documentation

Fixie is an add-on that provides Heroku applications with a fixed set of static IP addresses for outbound requests. Fixie is language- and framework-agnostic.

Without Fixie, your Heroku application makes requests from an unpredictable and impermanent set of IP addresses. Because Heroku IPs are dynamic, it can be difficult to integrate Heroku applications with services that whitelist a fixed IP range, including certain APIs and services that operate behind a corporate firewall.

Fixie acts as a proxy for outbound traffic, tunneling your requests through a known IP address. Each Fixie subscriber is assigned a set of static IP addresses. These addresses can be used anywhere you need a fixed IP range: API providers, firewall configurations, etc.

Fixie provides customers with a standard proxy URL that can be used to make requests from any server-side language, including Ruby, Python, Node, Java, and Go. Fixie can also be used by CURL and other command-line tools. Fixie can proxy both HTTP traffic and HTTPS traffic.

Provisioning the add-on

Fixie can be attached to a Heroku application via the CLI:

A list of all plans available can be found here.

To add our free plan (the default):

$ heroku addons:add fixie
-----> Adding fixie to sharp-mountain-4005... done, v18 (free)

Once Fixie has been added, a FIXIE_URL setting will be available in the app configuration and will contain the outbound proxy URL. This can be confirmed using the heroku config:get command.

$ heroku config:get FIXIE_URL
http://fixie:your-token@your-subdomain.usefixie.com:80

Your static IP addresses

You can retrieve your static IP addresses in the “Account” tab of the Fixie Dashboard. Your IP adresses are listed under “Account Details.”

Your static IP addresses are also shown in the command line when you enable Fixie using the Heroku CLI:

$ heroku addons:add fixie
Adding fixie to sharp-mountain-4005… done, v18 (free)
Your static IP addresses are 54.174.229.200, 54.176.231.252

Dashboard

The Fixie dashboard can be used to monitor your Fixie usage, retrieve your Fixie URL, and retrieve your outbound static IPs.

The dashboard can be accessed by visiting the Heroku Dashboard and selecting the application in question. Select Fixie from the Add-ons menu.

The dashboard can also be accessed via the CLI:

$ heroku addons:open fixie
Opening fixie for sharp-mountain-4005…

Local setup

Environment setup

If you wish to use Fixie to proxy requests while developing locally, it is necessary to locally replicate the FIXIE_URL environment variable.

Though less portable, it is also possible to set local environment variables using export FIXIE_URL=value.

Use Foreman to configure, run and manage process types specified in your app’s Procfile. Foreman reads configuration variables from an .env file. Use the following command to add the FIXIE_URL values retrieved from heroku config to .env.

$ heroku config -s | grep FIXIE_URL >> .env
$ more .env

Credentials and other sensitive configuration values should not be committed to source-control. In Git, exclude the .env file with: echo .env >> .gitignore.

Using with Node

Fixie works with both the standard http module and with higher-level http clients, including the popular request NPM module.

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

If you use the request module, you can use Fixie for specific requests:

const request = require('request')
const fixieRequest = request.defaults({'proxy': process.env.FIXIE_URL});

fixieRequest('http://www.example.com', (err, res, body) => {
  console.log(`Got response: ${res.statusCode}`);
});

Or, if you prefer, you can use the standard library’s lower-level http package directly:

const http = require('http');
const url = require('url');
const fixieUrl = url.parse(process.env.FIXIE_URL);
const requestUrl = url.parse('http://www.example.com');

http.get({
    host: fixieUrl.hostname,
    port: fixieUrl.port,
    path: requestUrl.href,
    headers: {
      Host: requestUrl.host,
      'Proxy-Authorization': `Basic ${new Buffer(fixieUrl.auth).toString('base64')}`,
    }
}, res => {
  console.log(`Got response: ${res.statusCode}`);
});

Using with Ruby

You can use Fixie with any Ruby http client. Included are example of using it with Net::HTTP from the standard library and with popular rest-client or faraday gems.

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

Using rest-client:

require 'rest-client'
RestClient.proxy = ENV["FIXIE_URL"]
response = RestClient.get("http://welcome.usefixie.com")

Using faraday:

require 'faraday'
conn = Faraday.new(:url => "http://welcome.usefixie.com", :proxy => ENV["FIXIE_URL"])
response = conn.get

Using with httparty:

fixie = URI.parse ENV['FIXIE_URL']

HTTParty.get(
  "http://welcome.usefixie.com",
  http_proxyaddr: fixie.host,
  http_proxyport: fixie.port,
  http_proxyuser: fixie.user,
  http_proxypass: fixie.password
)

Using Net::HTTP from the standard library:

require 'net/http'
_, username, password, host, port = ENV["FIXIE_URL"].gsub(/(:|\/|@)/,' ').squeeze(' ').split
uri       = URI("http://welcome.usefixie.com")
request   = Net::HTTP.new(uri.host, uri.port, host, port, username, password)
response  = request.get(uri)

Using with Python

Fixie works with any http client library, including urllib2 from the standard library and third-party packages including the popular requests package.

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

To route a specific request through Fixie using requests:

import os, requests
proxyDict = {
              "http"  : os.environ.get('FIXIE_URL', ''),
              "https" : os.environ.get('FIXIE_URL', '')
            }
r = requests.get('http://www.example.com', proxies=proxyDict)

Using urllib2 to send a specific request through Fixie:

import os, urllib2
proxy  = urllib2.ProxyHandler({'http': os.environ.get('FIXIE_URL', '')})
auth   = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, urllib2.HTTPHandler)
response = opener.open('http://www.example.com')
html = response.read()

The urllib2 API is significantly more verbose than that of the requests package. The requests package is a better choice for most applications.

If you intend to route all outbound traffic through Fixie, a simpler option is to set the http_proxy and https_proxy environment variables. Both urllib2 and requests honor the http_proxy and https_proxy environment variables, so you can route all outbound requests through Fixie using these environment variables:

import os, requests
os.environ['http_proxy'] = os.environ.get('FIXIE_URL', '')
os.environ['https_proxy'] = os.environ.get('FIXIE_URL', '')
requests.get("http://www.example.com")

Using with Java

You can use Fixie with any HTTP library. Popular options include Apache HttpClient and OkHttp.

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

A simple example using HttpClient:

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class FixieExample
{
    public static void main(String[] args) throws Exception {
        String fixieUrl = System.getenv("FIXIE_URL");

        String[] fixieValues = fixieUrl.split("[/(:\\/@)/]+");
        String fixieUser = fixieValues[1];
        String fixiePassword = fixieValues[2];
        String fixieHost = fixieValues[3];
        int fixiePort = Integer.parseInt(fixieValues[4]);

        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope(fixieHost, fixiePort),
                new UsernamePasswordCredentials(fixieUser, fixiePassword));
        CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider).build();
        try {
            HttpHost proxy = new HttpHost(fixieHost, fixiePort);
            RequestConfig config = RequestConfig.custom()
                .setProxy(proxy)
                .build();

            HttpHost target = new HttpHost("www.example.com", 80, "http");
            HttpGet httpget = new HttpGet("/");
            httpget.setConfig(config);

            CloseableHttpResponse response = httpclient.execute(target, httpget);
            try {
                System.out.println(EntityUtils.toString(response.getEntity()));
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

Or, for projects that use OkHttp:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import okhttp3.OkHttpClient;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.Route;

public class FixieExample
{
    public static void main(String[] args) throws Exception {
        String fixieUrl = System.getenv("FIXIE_URL");
        String[] fixieValues = fixieUrl.split("[/(:\\/@)/]+");
        String fixieUser = fixieValues[1];
        String fixiePassword = fixieValues[2];
        String fixieHost = fixieValues[3];
        int fixiePort = Integer.parseInt(fixieValues[4]);

        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        Authenticator proxyAuthenticator = new Authenticator() {
          @Override public Request authenticate(Route route, Response response) throws IOException {
               String credential = Credentials.basic(fixieUser, fixiePassword);
               return response.request().newBuilder()
                   .header("Proxy-Authorization", credential)
                   .build();
          }
        };
        clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(fixieHost, fixiePort)))
        .proxyAuthenticator(proxyAuthenticator);

        OkHttpClient client = clientBuilder.build();
        Request request = new Request.Builder().url("http://www.example.com").build();
        Response response = client.newCall(request).execute();

        System.out.println(response.body().string());
    }
}

Using with Go

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

To use Fixie for specific http requests, you can create a custom http.Client:

package main

import (
  "net/url"
  "net/http"
  "os"
  "io/ioutil"
)
func main () {
  fixieUrl, err := url.Parse(os.Getenv("FIXIE_URL"))
  customClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(fixieUrl)}}
  resp, err := customClient.Get("http://welcome.usefixie.com")
  if (err != nil) {
    println(err.Error())
    return
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  println(string(body))
}

If you intend to use Fixie for all outbound requests, an alternative is to use the HTTP_PROXY and HTTPS_PROXY environment variables. Go honors these environment variables by default. You can set HTTP_PROXY and HTTPS_PROXY in your application, typically in main.go:

package main

import (
  "net/http"
  "os"
  "io/ioutil"
)
func main () {
  os.Setenv("HTTP_PROXY", os.Getenv("FIXIE_URL"))
  os.Setenv("HTTPS_PROXY", os.Getenv("FIXIE_URL"))
  resp, err := http.Get("http://welcome.usefixie.com")
  if (err != nil) {
    println(err.Error())
    return
  }
  defer resp.Body.Close()
  body, err := ioutil.ReadAll(resp.Body)
  println(string(body))
}

Using with PHP

These examples assume the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

PHP cURL is the easiest way to get your PHP application working correctly with Fixie. Here’s how:

<?php
  function proxyRequest() {
    $fixieUrl = getenv("FIXIE_URL");
    $parsedFixieUrl = parse_url($fixieUrl);

    $proxy = $parsedFixieUrl['host'].":".$parsedFixieUrl['port'];
    $proxyAuth = $parsedFixieUrl['user'].":".$parsedFixieUrl['pass'];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_PROXY, $proxy);
    curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyAuth);
    curl_close($ch);
  }

  $response = proxyRequest();
  print_r($response);
?>

Using with other languages

The FIXIE_URL environment variable is a standard proxy URL that can be used by request libraries in any language. You can also use Fixie directly in cURL and other command-line tools:

curl http://welcome.usefixie.com --proxy $FIXIE_URL

This example assumes the FIXIE_URL environment variable is set. For instructions on setting this variable on your local machine, see the Local Setup section.

End-to-end encryption of HTTPS requests

When your application makes a request to an HTTPS resource via Fixie, your application sends a CONNECT request to Fixie. This request instructs Fixie to open a TCP connection to the remote host. Once this connection has been established, Fixie transparently tunnels this connection. Neither Fixie nor any other party has the ability to decrypt this traffic. The proxy negotiation (the initial CONNECT request to Fixie) happens in the clear, but the connection with the remote host remains encrypted end-to-end.

For more information, see Wikipedia’s article on HTTP tunnels

Migrating between plans

Use the heroku addons:upgrade command to migrate to a new plan.

$ heroku addons:upgrade fixie:newplan
-----> Upgrading fixie:newplan to sharp-mountain-4005... done, v18 ($49/mo)
       Your plan has been updated to: fixie:newplan

Removing the add-on

Fixie can be removed via the CLI.

This will destroy all associated data and cannot be undone!

$ heroku addons:remove fixie
-----> Removing fixie from sharp-mountain-4005... done, v20 (free)

Support

All Fixie support and runtime issues should be submitted via one of the Heroku Support channels. Any non-support related issues or product feedback is welcome at team@usefixie.com.