This add-on is operated by Fixie
Static IP addresses for database requests and other TCP connections
Fixie Socks
Last updated November 14, 2022
Table of Contents
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 allowlisting. 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.
Two ways to use Fixie Socks
1.) The easiest way to integrate your application with Fixie Socks is by adding the Fixie-Wrench binary to your project. Fixie-Wrench provides a tunnel on a local port through a Fixie Socks cluster, so that any application can make any TCP request to any remote service without significant code changes. Fixie-Wrench works for all kinds of TCP connections: database connections, HTTP requests, etc. For more information, see Using via Fixie-Wrench.
2.) Many libraries support SOCKSv5 proxies out of the box. If you’re using a language and library that supports SOCKSv5 proxies, you can integrate with Fixie Socks directly in your application code instead of using Fixie-Wrench. For more information, see Using via Native SOCKSv5 Support
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 via Fixie-Wrench
Fixie-Wrench is a command line utility that makes it easy to proxy any TCP connection through Fixie Socks, even if your language or wrenchent library does not natively support SOCKSv5 proxies. By connecting through Fixie Socks, your application with have a stable set of outbound IP addresses, making it possible to address a remote service that performs IP address whitelisting from Heroku or other platforms that provide ephemeral instances.
Fixie-Wrench does port-forwarding, similar to SSH port forwarding, so your remote database, FTP server, or other service will appear to be running locally from the perspective of your application code.
To install Fixie-Wrench into your project: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/usefixie/fixie-wrench/HEAD/install.sh)"
Then, update your Procfile to start Fixie-Wrench:
web: ./bin/fixie-wrench LOCAL_PORT:REMOTE_HOST:REMOTE_PORT & ...
For more information, see the Fixie-Wrench readme and the example app.
Using via native SOCKSv5 support
Many languages and database drivers natively support SOCKSv5 proxies like Fixie Socks. The list below is not exhaustive, but provides examples for many popular use cases. If you do not see your language/library below, you can always use Fixie-Wrench (documented above).
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: dbPassword,
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;
});
});
});
Connecting to MongoDB via Fixie Socks with Node.js
const mongoose = require('mongoose');
const fixieData = process.env.FIXIE_SOCKS_HOST.split(new RegExp('[/(:\\/@/]+'));
mongoose.connect(process.env.DB_CONNECTION,
{
proxyUsername: fixieData[0],
proxyPassword: fixieData[1],
proxyHost: fixieData[2],
proxyPort: fixieData[3]
},
(error) => {
if(error){
console.log(error)
}
console.log('Connected to database')}
)
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;
}
}
Using with Ruby
Out of the box, any Ruby library that accepts Net::SSH::Proxy::SOCKS5
object can use Fixie Socks. Here is a simple example of configuring the object that holds the proxy details:
proxy_uri = URI.parse("socks://#{FIXIE_SOCKS_HOST}")
socks_proxy = Net::SSH::Proxy::SOCKS5.new(
proxy_uri.host,
proxy_uri.port,
user: proxy_uri.user,
password: proxy_uri.password,
)
Leveraging the example above, here is an example of making an SFTP request through Fixie Socks using net-sftp
gem:
Net::SFTP.start(
...
proxy: socks_proxy,
) do |sftp|
sftp.download!("/path/to/file")
end
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, but depending on the configuration of the FTP server, you may need to specify a specific Fixie IP address instead of using your load-balanced Fixie Socks proxy URL.
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.
An example using cURL:
curl -v 'ftp://ftp2.census.gov/robots.txt' --socks5-hostname $FIXIE_SOCKS_IP_SPECIFIC_URL
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.
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.