VPNs let your computer join a Freestyle VPC with WireGuard. Create an ephemeral WireGuard session for a VPC, bring the generated config up with the WireGuard CLI, then connect to VMs by their private VPC IPs.
Terms
- A VPN is a temporary network connection from your computer into a private network.
- WireGuard is the VPN tool Freestyle uses. It creates an encrypted tunnel between your computer and the VPC.
- A tunnel is the private path that carries VPC traffic from your computer to Freestyle.
- A peer is the other side of the WireGuard connection. Your computer is one peer; Freestyle is the other peer.
- A WireGuard config is the small file
wg-quickuses to create the tunnel. It includes a private key, so treat it like a credential.
Install WireGuard Tools
Install the WireGuard CLI on your computer:
brew install wireguard-toolssudo apt-get update
sudo apt-get install -y wireguard-toolssudo dnf install -y wireguard-tools Create A VPN Session
Create a VPC, attach a VM, and bring the tunnel up with wg-quick:
import { freestyle } from "freestyle";
import { spawn } from "node:child_process";
import { rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
const { vpcId, vpc } = await freestyle.vpc.create({
name: "workspace-network",
cidr: "192.168.10.0/24",
});
const { vmId } = await freestyle.vms.create({
nics: [
{
default: true,
vpc: vpcId,
mode: "routed",
ipv4: "192.168.10.10",
},
],
});
const connection = await vpc.wireguard.createEphemeral();
const configPath = join(tmpdir(), `wg-${connection.sessionId}.conf`);
await writeFile(configPath, connection.clientConfig, { mode: 0o600 });
await new Promise<void>((resolve, reject) => {
const child = spawn("sudo", ["wg-quick", "up", configPath], {
stdio: "inherit",
});
child.once("error", reject);
child.once("exit", (code) =>
code === 0 ? resolve() : reject(new Error(`wg-quick up failed with ${code}`)),
);
});
// Keep the tunnel tied to this script: when the process exits from Ctrl-C or
// SIGTERM, bring WireGuard down and release the ephemeral Freestyle session.
const close = async (code = 0) => {
await new Promise<void>((resolve) => {
spawn("sudo", ["-n", "wg-quick", "down", configPath], {
stdio: "ignore",
}).once("exit", () => resolve());
});
await connection.close().catch(() => undefined);
await rm(configPath, { force: true });
process.exit(code);
};
process.once("SIGINT", () => void close(130));
process.once("SIGTERM", () => void close(143));
console.log(`Created VM ${vmId} in VPC ${vpcId}`);
console.log("Try: ping -c 3 192.168.10.10");
console.log("Press Ctrl-C to disconnect.");
await new Promise(() => {});
Run the script:
export FREESTYLE_API_KEY="your-api-key"
bun run vpn.ts
The generated WireGuard config contains a client private key. This script writes it to your OS temp directory, removes it on shutdown, and closes the ephemeral Freestyle VPN session when you press Ctrl-C.
While the script is running, your computer has a route to the VPC CIDR. Traffic to 192.168.10.10 goes through WireGuard; normal internet traffic keeps using your regular network.
Verify that WireGuard has a peer and has sent traffic:
sudo wg show
Connect to a VM by its VPC IP:
ping 192.168.10.10
When you are done, press Ctrl-C in the script terminal. The script runs wg-quick down, removes the temp config file, and closes the ephemeral Freestyle VPN session.
Use A System Config Path
For repeated local testing, you can save connection.clientConfig as freestyle-vpc.conf, install it under /etc/wireguard, and refer to it by name:
sudo mkdir -p /etc/wireguard
sudo install -m 600 freestyle-vpc.conf /etc/wireguard/freestyle-vpc.conf
sudo wg-quick up freestyle-vpc
sudo wg show freestyle-vpc
sudo wg-quick down freestyle-vpc
What The Config Contains
vpc.wireguard.createEphemeral() returns a standard WireGuard config in clientConfig:
[Interface]
Address = 100.96.0.2/32
PrivateKey = generated-client-private-key
[Peer]
PublicKey = freestyle-server-public-key
AllowedIPs = 192.168.10.0/24
Endpoint = vpn-endpoint.example.com:51820
PersistentKeepalive = 25
AllowedIPs is the VPC CIDR, so only VPC traffic is routed through the tunnel.
Close The Session
Ephemeral sessions are meant to be short lived. Close the session from your app when the user disconnects:
await connection.close();
If your process exits before it can close the session, Freestyle eventually expires the VPN resources.