← All guides
networkingNATIPv4REST API

Do You Need a Public IPv4 on a LiteVPS VM?

How LiteVPS VMs get outbound internet, managed SSH, and HTTPS proxy access without a public address, and when the dedicated sticky public IPv4 add-on is worth its price.

Published · LiteVPS Engineering

Most LiteVPS workloads do not need the dedicated public IPv4 add-on. Every VM comes with outbound internet through host-level source NAT, a managed SSH port on the host's public address, and HTTPS proxy rules for inbound web traffic, all included in the plan price. Order the sticky public IPv4 add-on only when you need direct inbound access on arbitrary ports or UDP, a TLS certificate on your own domain, or one stable address that survives VM deletion and recreation. Deleting a VM with a sticky address holds that address until you cancel its slot, and held slots are not billed.

This guide maps the current LiteVPS networking model to the questions people actually hit: how a VM with no public IP reaches the internet, how you reach it, when the add-on earns its price, and how to verify every layer with one script.

What networking does a LiteVPS VM get by default?

Every VM receives a private address from 10.0.0.0/16 in the customer_ip field. This is the address the VM's own operating system uses on its interface. It is not the address your controller uses to connect.

Three access paths are configured for you automatically:

  1. Outbound internet — the VM can reach public hosts through host-level source NAT. No extra setup, no per-VM firewall rules.
  2. Inbound SSH — the platform maps a dedicated TCP port on the KVM host's public address to the VM's port 22. The port is returned as ssh_port.
  3. Inbound HTTP/HTTPS — the platform runs an HTTPS proxy under *.proxy.litevps.dev that forwards to ports inside the VM. A default subdomain (the VM's proxy_subdomain field) is preconfigured to forward to port 80, and you can add up to five custom rules.

The current platform guide describes this model in the network section. VMs without the add-on do not receive a dedicated public IPv4; inbound access uses the managed SSH port mapping and the managed HTTPS proxy.

How does outbound internet work without a public IP?

The KVM host routes each VM through a per-VM virtual interface whose default gateway is the link-local address 169.254.1.1. Outbound packets are rewritten by source NAT on the host so they leave with a public source address, exactly like a normal home or office router handles a private LAN. The Linux netfilter MASQUERADE mechanism is the general technique behind this. The private address space itself is the standard defined in RFC 1918.

In practice, apt-get, pip install, git clone, and outbound HTTPS all work on a VM that has no public IPv4. You can confirm this from inside the guest with a command like curl -fsS https://api.litevps.dev/health.

One important boundary: do not assume account-scoped private connectivity between your VMs. Two of your VMs are not automatically a single private network with each other, so use the documented inbound mappings for services that must communicate.

How do you reach a LiteVPS VM from the outside?

SSH

For a VM without the add-on, connect to the host's public address on the assigned port:

ssh -p "$SSH_PORT" root@"$HOST_IP"

ip_address and ssh_port come from GET /api/vps/:id. The port is allocated from a fixed range (10000–60000) and changes if the VM is deleted and recreated.

For a VM with the add-on, the dedicated address is directly reachable, so standard SSH on port 22 works:

ssh root@"$PUBLIC_IP"

HTTP and HTTPS

The managed proxy forwards https://<subdomain>.proxy.litevps.dev to a port inside the VM using nginx with a wildcard TLS certificate. The wildcard DNS record and certificate are public infrastructure; you can confirm them at any time with a DNS lookup for *.proxy.litevps.dev and a TLS handshake on the resulting name. Subdomains may contain only lowercase letters, digits, and hyphens.

Create a rule with the REST API:

curl -X POST "$LITEVPS_API/api/vps/$VPS_ID/proxy-rules" \
  -H "Authorization: Bearer $LITEVPS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"subdomain":"my-service","target_port":8080}'

The VM is then reachable at https://my-service.proxy.litevps.dev. Rules are scoped to one VM, limited to five per VM, and are removed when the VM is deleted.

When should you order the dedicated public IPv4 add-on?

The add-on is priced per hour with a monthly cap and is advertised at GET /api/pricing under addons.public_ipv4. On August 3, 2026 the live value was a $2.00 monthly cap, with the hourly rate derived as monthly ÷ 730. Prices are set by the operator and can change, so read the current value from the public endpoint instead of trusting a copy in an article. The rate you see at creation is snapshotted onto the VM and does not change if pricing is later updated.

Requirement Default managed access Dedicated public IPv4 add-on
Outbound internet Included (source NAT) Included (direct)
Inbound SSH Managed port on host IP Direct on port 22
Inbound HTTP/HTTPS Managed *.proxy.litevps.dev Direct, any port
Inbound TCP on arbitrary ports No Yes
Inbound UDP No Yes
TLS on your own domain Proxy handles TLS Point your A record at the address
Stable address across recreation No Yes, held in a sticky slot
Price Included Add-on rate from /api/pricing

Order the add-on when you need direct inbound traffic that the managed proxy cannot express. Typical cases:

  • A WireGuard, OpenVPN, or other UDP service that must accept connections.
  • A protocol that needs arbitrary TCP ports your clients will reach directly.
  • TLS with a certificate on your own domain, where the proxy's shared domain does not fit.
  • A stable address you want to keep across VM deletion and recreation, such as an allowlisted API client or a DNS record you control.

The platform still enforces its own network and mail policies at the host level, so a public address is not a general exemption from those controls.

What happens when you delete a VM with a sticky address?

The add-on's address is tied to a slot, not to the VM. Deleting the VM changes the slot from allocated to held: the address stops being routed to your VM, but it stays reserved for your account and is not billed while held. Creating another VM reclaims the same address, subject to the account's slot limit, which matches its VM limit.

To release the address back to the shared pool, cancel the slot:

curl -X DELETE "$LITEVPS_API/api/vps/ip-slots/$SLOT_ID" \
  -H "Authorization: Bearer $LITEVPS_TOKEN"

GET /api/ip-slots lists your slots and their current state. This lifecycle matters for cost: deleting and recreating a VM keeps your address and costs nothing for the gap, while cancelling the slot releases the address so it can be allocated to someone else.

How can you verify all of this with one script?

Save the following as networking-check.sh. It creates a VM without the add-on, waits for it to be ready, prints the networking fields, proves outbound internet from inside the guest, starts a tiny HTTP server, publishes it through a proxy rule, fetches it through the public URL, and then destroys the VM in a cleanup trap. Use a non-sensitive account and a template from GET /api/templates.

#!/usr/bin/env bash
# networking-check.sh — verify LiteVPS default networking, then destroy the VM.
# Requires: bash 4+, curl, jq. Uses your own LiteVPS account and balance.
set -Eeuo pipefail

LITEVPS_API="${LITEVPS_API:-https://api.litevps.dev}"
: "${LITEVPS_TOKEN:?Set LITEVPS_TOKEN (vtk_ token from the portal)}"
: "${LITEVPS_PLAN_ID:?Set LITEVPS_PLAN_ID (from GET /api/pricing)}"
: "${LITEVPS_TEMPLATE:?Set LITEVPS_TEMPLATE (from GET /api/templates)}"

auth=(-H "Authorization: Bearer $LITEVPS_TOKEN")
vps_id=""
job_id=""

cleanup() {
  if [[ -n "$job_id" && -n "$vps_id" ]]; then
    curl -sS -o /dev/null "${auth[@]}" -X DELETE \
      "$LITEVPS_API/api/vps/$vps_id/jobs/$job_id" || true
    job_id=""
  fi
  if [[ -n "$vps_id" ]]; then
    curl -sS -o /dev/null "${auth[@]}" -X DELETE \
      "$LITEVPS_API/api/vps/$vps_id" || \
      printf 'warning: deletion failed for VPS %s\n' "$vps_id" >&2
    printf 'destroyed VM %s (billing stopped)\n' "$vps_id"
    vps_id=""
  fi
}
trap cleanup EXIT INT TERM

# 1. Create a VM without the public_ipv4 add-on.
name="net-check-$(date +%s)"
create_response="$({
  jq -n --arg name "$name" --arg plan "$LITEVPS_PLAN_ID" --arg tpl "$LITEVPS_TEMPLATE" \
    '{name:$name, plan_id:$plan, template:$tpl, ttl_minutes:120}' |
  curl --fail-with-body -sS -X POST "${auth[@]}" \
    -H 'Content-Type: application/json' --data-binary @- \
    "$LITEVPS_API/api/vps"
})"
vps_id="$(jq -er '.vps.id' <<<"$create_response")"
printf 'created %s without a public IPv4\n' "$vps_id"

# 2. Wait until cloud-init has finished (ready=true).
deadline=$((SECONDS + 600))
while (( SECONDS < deadline )); do
  detail="$(curl --fail-with-body -sS "${auth[@]}" "$LITEVPS_API/api/vps/$vps_id")"
  [[ "$(jq -r '.vps.ready' <<<"$detail")" == "true" ]] && break
  sleep 5
done
if [[ "$(jq -r '.vps.ready' <<<"$detail")" != "true" ]]; then
  printf 'VM did not become ready before the deadline\n' >&2
  exit 1
fi

# 3. Show the networking fields the platform assigned.
jq '{vps: {
  state: .vps.state,
  ready: .vps.ready,
  customer_ip: .vps.customer_ip,
  ip_address: .vps.ip_address,
  ssh_port: .vps.ssh_port,
  proxy_subdomain: .vps.proxy_subdomain,
  public_ipv4: .vps.public_ipv4
}}' <<<"$detail"

# 4. Outbound internet: run a public HTTPS request from inside the guest.
outbound="$(jq -n '{command:"curl -fsS -m 20 https://api.litevps.dev/health", timeout_seconds:30}' |
  curl --fail-with-body -sS -X POST "${auth[@]}" \
    -H 'Content-Type: application/json' --data-binary @- \
    "$LITEVPS_API/api/vps/$vps_id/exec")"
printf 'outbound internet check (inside VM):\n'
jq '{exit_code, stdout, duration_ms}' <<<"$outbound"

# 5. Start a small HTTP server on port 8080 as a platform-managed background job.
job="$(jq -n '{command:"python3 -m http.server 8080 --bind 0.0.0.0", timeout_seconds:300, background:true}' |
  curl --fail-with-body -sS -X POST "${auth[@]}" \
    -H 'Content-Type: application/json' --data-binary @- \
    "$LITEVPS_API/api/vps/$vps_id/exec")"
job_id="$(jq -er '.job_id' <<<"$job")"

# 6. Publish port 8080 through the managed HTTPS proxy.
proxy_sub="net-$(jq -r '.vps.id' <<<"$create_response" | tr -d '-' | cut -c1-8)"
rule="$(jq -n --arg sub "$proxy_sub" '{subdomain:$sub, target_port:8080}' |
  curl --fail-with-body -sS -X POST "${auth[@]}" \
    -H 'Content-Type: application/json' --data-binary @- \
    "$LITEVPS_API/api/vps/$vps_id/proxy-rules")"
proxy_url="https://$proxy_sub.proxy.litevps.dev"
printf 'created proxy rule: %s -> port 8080\n' "$proxy_url"

# 7. Wait for the server job to be running, then fetch through the public URL.
for _ in {1..12}; do
  jstate="$(curl --fail-with-body -sS "${auth[@]}" "$LITEVPS_API/api/vps/$vps_id/jobs/$job_id")"
  st="$(jq -r '.status' <<<"$jstate")"
  [[ "$st" == "running" || "$st" == "done" ]] && break
  sleep 5
done
printf 'proxy response (from your machine):\n'
curl -fsS -m 20 "$proxy_url/" | head -c 120
printf '\n'

# The cleanup trap destroys the VM, cancels the job, and removes the proxy rule.

Run it with:

export LITEVPS_TOKEN="vtk_replace_with_your_token"
export LITEVPS_PLAN_ID="replace-with-a-current-plan-id"
export LITEVPS_TEMPLATE="replace-with-a-current-template-slug"
chmod +x networking-check.sh
./networking-check.sh

Expected output in a working account: outbound internet check returns exit_code: 0 and stdout: {"status":"ok"}; the proxy fetch returns the directory listing HTML of http.server. The VM and its job are removed when the script exits, and the created proxy rule disappears with the VM.

When should you use the default managed access?

Use the default model for outbound-first workloads: agent sandboxes, build jobs, integration tests, scrapers, and services that clients reach over HTTP or HTTPS through the proxy. You get internet access, a working SSH path, and TLS termination without managing certificates, and you pay only the plan rate.

When should you not use the default managed access?

Do not use it when a client must connect to a port or protocol the proxy cannot carry, such as inbound UDP or arbitrary TCP ports, when you need a certificate on your own domain, or when you need a single address that stays stable across VM recreation. For those, order the dedicated public IPv4 add-on. Also do not expect the default model to behave like a private VLAN: it is not a substitute for a dedicated network when your services need to communicate directly with each other.

How to give an AI agent a disposable Linux sandbox shows the create-and-destroy lifecycle that pairs with the default networking model. VPS, container, or serverless function for agent code execution? helps you decide whether a VM is warranted at all. The LiteVPS API reference lists the current endpoints, and current pricing shows live plan and add-on rates.

Methodology note

Product behavior was checked against the LiteVPS implementation and live public endpoints on August 3, 2026: the VPS and slot lifecycle code, the host-side NAT and SSH port mapping, the proxy-rule handler and nginx configuration, the pricing endpoint, the *.proxy.litevps.dev wildcard DNS record, and the TLS certificate for that domain. The add-on price quoted here was the live value on that date and may change; read it from GET /api/pricing before budgeting. The example script follows the documented API contract and passes bash -n syntax checking, but it was not run against a live account, so test it with non-sensitive work in your own account before relying on it.