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.
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:
- Outbound internet — the VM can reach public hosts through host-level source NAT. No extra setup, no per-VM firewall rules.
- 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. - Inbound HTTP/HTTPS — the platform runs an HTTPS proxy under
*.proxy.litevps.devthat forwards to ports inside the VM. A default subdomain (the VM'sproxy_subdomainfield) 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.
What should you read next?
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.