Home/Blog/Mobile Proxy for Go
Developer Guide

Mobile Proxy for Go

Go's net/http client routes through a proxy when you set Transport.Proxy. For SOCKS5 you reach for golang.org/x/net/proxy. This guide wires both to a mobile proxy and triggers IP rotation against the switch API.

7 min read·Go / golang·Last updated: May 2026

Prerequisites

  • Go 1.21+ installed (go version).
  • A mobile proxy slot, HTTP/SOCKS5 ports, username, password and API key from mobileproxies.org.
  • For SOCKS5: go get golang.org/x/net/proxy.

Step-by-Step Configuration

STEP 01

Read credentials from the environment

# .env or your shell — never hard-code secrets
export MP_HOST=proxy.mobileproxies.org
export MP_HTTP_PORT=8000
export MP_SOCKS_PORT=1080
export MP_USER=u_4a9c
export MP_PASS=p_2X7q
export MP_API_KEY=YOUR_API_KEY
export MP_SLOT=us-mob-01
STEP 02

HTTP proxy with net/http

package main

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"
)

// httpProxyClient builds an *http.Client that tunnels every request
// through the authenticated mobile proxy.
func httpProxyClient() (*http.Client, error) {
	proxyURL, err := url.Parse(fmt.Sprintf(
		"http://%s:%s@%s:%s",
		url.QueryEscape(os.Getenv("MP_USER")),
		url.QueryEscape(os.Getenv("MP_PASS")),
		os.Getenv("MP_HOST"),
		os.Getenv("MP_HTTP_PORT"),
	))
	if err != nil {
		return nil, err
	}

	transport := &http.Transport{
		Proxy:               http.ProxyURL(proxyURL),
		MaxIdleConns:        10,
		IdleConnTimeout:     30 * time.Second,
		TLSHandshakeTimeout: 15 * time.Second,
	}
	return &http.Client{
		Transport: transport,
		Timeout:   30 * time.Second,
	}, nil
}
STEP 03

SOCKS5 proxy with golang.org/x/net/proxy

package main

import (
	"context"
	"net"
	"net/http"
	"os"
	"time"

	"golang.org/x/net/proxy"
)

// socks5ProxyClient routes traffic through the SOCKS5 port using an
// authenticated dialer wired into http.Transport.DialContext.
func socks5ProxyClient() (*http.Client, error) {
	auth := &proxy.Auth{
		User:     os.Getenv("MP_USER"),
		Password: os.Getenv("MP_PASS"),
	}
	addr := net.JoinHostPort(os.Getenv("MP_HOST"), os.Getenv("MP_SOCKS_PORT"))

	dialer, err := proxy.SOCKS5("tcp", addr, auth, proxy.Direct)
	if err != nil {
		return nil, err
	}
	ctxDialer := dialer.(proxy.ContextDialer)

	transport := &http.Transport{
		DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
			return ctxDialer.DialContext(ctx, network, address)
		},
	}
	return &http.Client{Transport: transport, Timeout: 30 * time.Second}, nil
}
STEP 04

Make a request through the proxy

func main() {
	client, err := httpProxyClient() // or socks5ProxyClient()
	if err != nil {
		panic(err)
	}

	resp, err := client.Get("https://example.com")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	fmt.Println("status:", resp.Status)
}

Verify It Works

Hit api.ipify.org through the client and print the egress IP. It should be a carrier-owned mobile IP, never your machine's real address.

func checkIP(client *http.Client) string {
	resp, err := client.Get("https://api.ipify.org?format=text")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	return string(body) // e.g. 100.42.x.x on a mobile ASN
}

Rotate the IP

Ask the carrier for a fresh IP with a POST to the switch endpoint. The request goes direct (not through the proxy) and authenticates with your API key:

func rotate() error {
	url := fmt.Sprintf(
		"https://buy.mobileproxies.org/api/v1/proxies/%s/switch",
		os.Getenv("MP_SLOT"),
	)
	req, err := http.NewRequest(http.MethodPost, url, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("MP_API_KEY"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		return fmt.Errorf("switch failed: %s", resp.Status)
	}
	time.Sleep(4 * time.Second) // let the new IP bind
	return nil
}

Troubleshooting

"Proxy Authentication Required" (407)

The credentials never reached the proxy. Embed them in the url.Parse URL as user:pass@host, and url.QueryEscape any special characters in the password.

SOCKS5 panics on the type assertion

The proxy.ContextDialer assertion only works with recent golang.org/x/net. Run go get -u golang.org/x/net, or fall back to dialer.Dial inside a plain Dial field.

IP doesn't change after rotate()

Go reuses keep-alive connections. After a switch, call transport.CloseIdleConnections() so the next request opens a fresh tunnel on the new IP.

Related Guides

Run Go Through Mobile IPs

$5 trial. Drop in the http.Transport, point it at a carrier IP, and rotate on the API.