Fixie Socks Documentation

Fixie Socks is a Heroku add-on that enables users to make TCP connections from a known IP address via a SOCKS proxy. Common use cases are database connections, FTP, SCP, and SSH. By connecting via Fixie Socks, users can integrate with external services and databases that do IP whitelisting. Fixie Socks is language- and framework-agnostic.

Fixie Socks acts as a SOCKS V5 proxy for outbound traffic, tunneling your requests through a known IP address. Each Fixie subscriber is assigned a set of static IP addresses. Through this proxy, subscribers can connect to any database or service that requires a fixed IP range.

Fixie Socks provides customers with a standard SOCKS V5 proxy URL that can be used to establish connections from any server-side language, including Node, Java, and Go. Fixie Socks can also be used by SSH, SCP, cURL, and other command-line tools.

The difference between Fixie Socks and Fixie

Fixie Socks provides a fixed set of IP addresses via a SOCKS V5 proxy. As such, Fixie Socks is capable of proxying any TCP connection. You can make HTTP and HTTPS requests via Fixie Socks, but Fixie (an HTTP proxy) is generally a better fit for that use case. Fixie Socks is perfect for making requests to databases, FTP servers, and other lower-level connections because it allows you to tunnel arbitrary TCP connections.

Provisioning the add-on

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

A list of all plans available can be found here.

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

After you provision Fixie Socks, a FIXIE_SOCKS_HOST config var is available in your app’s configuration. This contains the SOCKSV5 proxy URL through which your application makes outbound requests. This can be confirmed using the heroku config:get command:

$ heroku config:get FIXIE_SOCKS_HOST
user:pass@criterium.usefixie.com:1080

After installing Fixie Socks, the application should be configured to fully integrate with the add-on.

Local setup

Environment setup

For local development, it is necessary to replicate the FIXIE_SOCKS_HOST environment variable.

FIXIE_SOCKS_HOST can be retrieved either from the Fixie Socks dashboard or via the Heroku CLI:

$ heroku config:get FIXIE_SOCKS_HOST -s  >> .env

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

For more information, see the Heroku Local article.

Using with Node.js

With Node.js, the general pattern is to establish a SOCKS connection using a client library like socksjs and then provide this stream to the database driver, request library, or other library of your choosing.

Connecting to MySQL via Fixie Socks with Node.js

MySql2 connects via a SOCKS connection provided as the stream property. Because Fixie Socks terminates idle connections after 60 seconds of inactivity, we suggest using connection pooling (this is a best practice regardless) or manual error handling. The example below uses connection pooling:

'use strict';

const SocksConnection = require('socksjs');
const mysql = require('mysql2');
const fixieUrl = process.env.FIXIE_SOCKS_HOST;
const fixieValues = fixieUrl.split(new RegExp('[/(:\\/@)/]+'));

const mysqlServer = {
  host: 'your-host.example.com',
  port: 3306
};

const dbUser = 'user';
const dbPassword = 'password';
const db = 'database';

const fixieConnection = new SocksConnection(mysqlServer, {
  user: fixieValues[0],
  pass: fixieValues[1],
  host: fixieValues[2],
  port: fixieValues[3],
});

const mysqlConnPool = mysql.createPool({
  user: dbUser,
  password=(redacted)),
  database: db,
  stream: fixieConnection
});

mysqlConnPool.getConnection(function gotConnection(err, connection) {

  if (err) throw err;

  queryVersion(connection);
});

function queryVersion(connection) {
  connection.query('SELECT version();', function (err, rows, fields) {

      if (err) throw err;

      console.log('MySQL/MariaDB version: ', rows);
      connection.release();
      process.exit();
  });
}

Connecting to Postgres or Amazon Redshift via Fixie Socks with Node.js

As with mysql, you can pass a custom stream to the node-postgres library. This will work both for connections to Postgres databases as well as to Amazon Redshift:

'use strict';

const pg = require('pg');
const SocksConnection = require('socksjs');

const fixieUrl = process.env.FIXIE_SOCKS_HOST;
const fixieValues = fixieUrl.split(new RegExp('[/(:\\/@)/]+'));

const pgServer = {
  host: 'YOUR-HOST',
  port: 5432
};

const fixieConnection = new SocksConnection(pgServer, {
  user: fixieValues[0],
  pass: fixieValues[1],
  host: fixieValues[2],
  port: fixieValues[3],
});

const connectionConfig = {
  user: 'YOUR-DB-USERNAME',
  password: 'YOUR-DB-PASSWORD',
  database: 'YOUR-DATABASE',
  stream: fixieConnection,
  ssl: true // Optional, depending on db config
};

var client = new pg.Client(connectionConfig);

client.connect(function (err) {
  if (err) throw err;
  client.query('SELECT 1+1 as test1', function (err, result) {
    if (err) throw err;
    console.log(result.rows[0]);
    client.end(function (err) {
      if (err) throw err;
    });
  });
});

Establishing an SSH connection over Fixie Socks with Node.js

The SSH2 library can be used to establish an SSH connection and execute commands over Fixie Socks.

var socks = require('socksv5'),
    SSHClient = require('ssh2').Client;

const fixieUrl = process.env.FIXIE_SOCKS_HOST;
const fixieValues = fixieUrl.split(new RegExp('[/(:\\/@)/]+'));

socks.connect({
  host: 'ssh.example.org',
  port: 22,
  proxyHost: fixieValues[2],
  proxyPort: fixieValues[3],
  auths: [socks.auth.UserPassword(fixieValues[0], fixieValues[1])]
}, function(socket) {
  var conn = new SSHClient();
  conn.on('ready', function() {
    conn.exec('uptime', function(err, stream) {
      if (err) throw err;
      stream.on('close', function(code, signal) {
      conn.end();
      }).on('data', function(data) {
        console.log('STDOUT: ' + data);
      }).stderr.on('data', function(data) {
        console.log('STDERR: ' + data);
      });
    });
  }).connect({
    sock: socket,
    username: 'ssh-user',
    privateKey: require('fs').readFileSync('/here/is/my/key')
  });
});

Making HTTP or HTTPS requests over Fixie Socks with Node.js

The socks package provides an agent that can be used by the Node’s http and https libraries, as well as by popular higher-level libraries like request.

'use strict';

const http = require('http');
const Socks = require('socks');

const fixieUrl = process.env.FIXIE_SOCKS_HOST;
const fixieValues = fixieUrl.split(new RegExp('[/(:\\/@)/]+'));

const socksAgent = new Socks.Agent({
    proxy: {
        ipaddress: fixieValues[2],
        port: fixieValues[3],
        type: 5,
        authentication: {
            username: fixieValues[0],
            password: fixieValues[1]
        }
    }},
    true, // true HTTPS server, false for HTTP server
    false // rejectUnauthorized option passed to tls.connect()
);

function resHandler(res) {
  let responseBody = '';
  res.on('data', (chunk) => {
    responseBody += chunk;
  });
  res.on('error', () => {
    process.exit(1);
  });
  res.on('end', () => {
    console.log(responseBody);
    socksAgent.encryptedSocket.end();
  });
}


http.get({ hostname: 'example.com', port: '443', agent: socksAgent}, resHandler);

Using with Go

Golang’s net/proxy package provides a Socks5 proxy dialer that can be used with Fixie Socks. This dialer can be used for any TCP connection. The example below uses this to make an HTTP request:

package main

import (
  "fmt"
  "io/ioutil"
  "net/http"
  "os"
  "strings"
  "golang.org/x/net/proxy"
)

const URL = "http://www.example.com"

func main() {
  fixie_data := strings.Split(os.Getenv("FIXIE_SOCKS_HOST"), "@")
  fixie_addr := fixie_data[1]
  auth_data := strings.Split(fixie_data[0], ":")
  auth := proxy.Auth{
    User: auth_data[0],
    Password: auth_data[1],
  }

  dialer, err := proxy.SOCKS5("tcp", fixie_addr, &auth, proxy.Direct)
  if err != nil {
    fmt.Fprintln(os.Stderr, "can't connect to the proxy:", err)
    os.Exit(1)
  }
  httpTransport := &http.Transport{}
  httpClient := &http.Client{Transport: httpTransport}

  httpTransport.Dial = dialer.Dial

  req, err := http.NewRequest("GET", URL, nil)
  if err != nil {
    fmt.Fprintln(os.Stderr, "can't create request:", err)
    os.Exit(2)
  }
  resp, err := httpClient.Do(req)
  if err != nil {
    fmt.Fprintln(os.Stderr, "can't GET page:", err)
    os.Exit(3)
  }
  defer resp.Body.Close()
  b, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    fmt.Fprintln(os.Stderr, "error reading body:", err)
    os.Exit(4)
  }
  fmt.Println(string(b))
}

Using with Java

Java supports a system property socksProxyHost, which can be used to route every outbound request through Fixie Socks. Additionally, Java 7 introduced ProxySelector, which can be used to conditionally proxy requests depending on the hostname.

A simple example that proxies all outbound requests through Fixie Socks:

URL fixie = new URL(System.getenv("FIXIE_SOCKS_HOST"));
String[] fixieUserInfo = fixie.getUserInfo().split(':');
String fixieUser = fixieUserInfo[0];
String fixiePassword = fixieUserInfo[1];
System.setProperty("socksProxyHost", fixie.getHost());
Authenticator.setDefault(new ProxyAuthenticator(fixieUser, fixiePassword));

//...

private class ProxyAuthenticator extends Authenticator {
  private final PasswordAuthentication passwordAuthentication;
  private ProxyAuthenticator(String user, String password) {
    passwordAuthentication = new PasswordAuthentication(user, password.toCharArray());
  }

  @Override
  protected PasswordAuthentication getPasswordAuthentication() {
    return passwordAuthentication;
  }
}

Curl via Fixie Socks

Curl accepts a socks5 argument:

curl --socks5 $FIXIE_SOCKS_HOST http://example.com

SSH and SCP via Fixie Socks

SSH and SCP accept a ProxyCommand option. Using this option, you can pass in an ncat command that establishes a connection via the Fixie Socks proxy. This requires ncat v7 or newer.

Ncat does not accept proxy authentication via the standard proxy url schema, so instead you must provide it as a separate argument:

ssh -o ProxyCommand='ncat --proxy-type socks5 --proxy YOUR-FIXIE-DOMAIN.usefixie.com:1080 --proxy-auth fixie:YOUR-FIXIE-TOKEN %h %p' serveruser@server.ip.address

FTP via Fixie Socks

Making FTP requests via Fixie Socks is straight forward. An example using cURL:

curl -v 'ftp://ftp.us.debian.org/debian/README' -o ./README --socks5-hostname $FIXIE_SOCKS_HOSTNAME

cURL versions prior 7.48 had a bug which left the SOCKS connection open after the FTP transfer completed. We recommend using cURL 7.48 or later.

FTP uses multiple TCP connections (a control connection and a transfer connection). If your FTP server supports “passive promiscuous” connections, connecting through the standard Fixie Socks URL works without issue. If, however, the server does not support “passive promiscuous” connections, both the control and transfer connection must go through the same IP. For this use case, you can proxy directly through a specific Fixie Socks IP instead of through a load-balanced Fixie Socks proxy group. You can find the IP address and credentials in the Fixie Socks dashboard.

Using with languages that don’t support SOCKS proxies

Some languages do not provide native support for SOCKS proxies. Where this is the case, there are other options for using Fixie Socks.

Dashboard

The Fixie Socks dashboard allows you to view your connection logs and account settings.

The dashboard can be accessed via the CLI:

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

or by visiting the Heroku Dashboard and selecting the application in question. Select Fixie Socks from the add-ons menu.

Removing the add-on

Fixie Socks can be removed via the CLI.

This will destroy all associated data and cannot be undone! If your application is configured to make requests through Fixie Socks, those requests will fail after removing the add-on.

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

Support

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