Databases / From a standard VPS
Connect a standard VPS to a database
In af-abj-1, give a standard VPS a second, private network interface on the database network, configure it, and allow its address on the database.
How it works
A database in af-abj-1 never sits on the public network your standard VPSes use. It lives on a private database network, 10.250.0.0/20, shared by the databases of that zone. To reach it, a standard VPS gets a second network interface on that network:
- You check the VPS's security group admits nothing from
10.250.0.0/20(the reason is below). - You ask for the interface. The VPS gets an address on
10.250.0.0/20: itsprivate_network_ip. - You bring the interface up inside the VPS, with DHCP but without its routes or DNS.
- You add
<private_network_ip>/32to the database's access rules.
The interface is free. A running VPS gets it without a restart.
The range is in the catalogue as the zone's private_network_cidr in GET /regions; it is null in a zone without one, and in every VPC zone.
This page is for af-abj-1 only. A VM in a VPC (af-abj-2) already reaches databases in its own VPC; see connecting. Asking for the interface anywhere else is 409 PRIVATE_NETWORK_NOT_AVAILABLE.
Why the security group matters
A security group applies to every interface of a machine, not just its public one. If the VPS's group has an inbound rule whose source includes any part of 10.250.0.0/20, that rule would also admit traffic arriving on the new private interface: from every database on the network, and from every other customer's VPS that has an interface there.
So a VPS may have the interface only while its group admits nothing from 10.250.0.0/20:
- Any inbound rule whose source overlaps the range is refused, whatever its protocol or ports, ICMP included.
0.0.0.0/0contains the range,10.0.0.0/8contains it, and10.250.3.17/32sits inside it: all three are refused. - Outbound rules do not count. The VPS can still reach anything its outbound rules allow, including the database.
The check is made when you ask, again just before the interface is added, and for as long as the VPS has it: while it does, a rule change on its group, or moving it to another group, that would admit the range is refused with 422, code RULE_ALLOWS_PRIVATE_NETWORK on rules or SECURITY_GROUP_ALLOWS_PRIVATE_NETWORK on security_group_id.
Step 1: narrow the security group
Find the group the VPS uses (security_group_id on the instance) and read its rules:
$ curl https://api.pantechdynamics.com/public/v1/security-groups/sg_… \ -H "Authorization: Bearer $PANTECH_API_KEY"Every inbound rule with 0.0.0.0/0, a 10.0.0.0/8 or any other range overlapping 10.250.0.0/20 has to change. You have three choices for each:
- Allow only the addresses you need. Best for SSH: your office's or your VPN's range, like
203.0.113.0/24. - Drop it. The ICMP rule is only for ping; most machines do without it.
- Keep it open to the internet, minus the private range. Replace
0.0.0.0/0with these 20 ranges, which together cover every IPv4 address except10.250.0.0/20:
0.0.0.0/5 8.0.0.0/7 10.0.0.0/9 10.128.0.0/10
10.192.0.0/11 10.224.0.0/12 10.240.0.0/13 10.248.0.0/15
10.250.16.0/20 10.250.32.0/19 10.250.64.0/18 10.250.128.0/17
10.251.0.0/16 10.252.0.0/14 11.0.0.0/8 12.0.0.0/6
16.0.0.0/4 32.0.0.0/3 64.0.0.0/2 128.0.0.0/1Rules are replaced as a whole. For a web server that serves HTTPS to everyone and SSH to one office, with all traffic allowed out, the new set is:
$ curl -X PUT https://api.pantechdynamics.com/public/v1/security-groups/sg_…/rules \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d @rules.json{
"rules": [
{ "direction": "ingress", "protocol": "tcp", "port_range": "22", "cidr": "203.0.113.0/24" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "0.0.0.0/5" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "8.0.0.0/7" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.0.0.0/9" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.128.0.0/10" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.192.0.0/11" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.224.0.0/12" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.240.0.0/13" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.248.0.0/15" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.250.16.0/20" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.250.32.0/19" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.250.64.0/18" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.250.128.0/17" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.251.0.0/16" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "10.252.0.0/14" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "11.0.0.0/8" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "12.0.0.0/6" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "16.0.0.0/4" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "32.0.0.0/3" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "64.0.0.0/2" },
{ "direction": "ingress", "protocol": "tcp", "port_range": "443", "cidr": "128.0.0.0/1" },
{ "direction": "egress", "protocol": "all", "cidr": "0.0.0.0/0" }
]
}The ICMP rule is gone, SSH is open to one range, and HTTPS to everything except the private network. The outbound rule can stay 0.0.0.0/0.
Step 2: add the interface
$ curl -X POST https://api.pantechdynamics.com/public/v1/instances/vm_…/private-network \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)"{
"operation_id": "op_…",
"resource_id": "vm_…",
"status": "submitting"
}The VPS must be running or stopped, with no other change under way (start, stop, resize, restore or delete): otherwise 409 INSTANCE_NOT_SETTLED, so wait and try again. If the group still admits the range, the answer is 409 SECURITY_GROUP_ALLOWS_PRIVATE_NETWORK, and its detail lists the rules to change:
{
"status": 409,
"code": "SECURITY_GROUP_ALLOWS_PRIVATE_NETWORK",
"title": "Security group allows the private network",
"detail": "This instance's security group allows inbound traffic from 10.250.0.0/20, the private database network: ingress icmp from 0.0.0.0/0. Security groups apply to every network interface of an instance, so these rules would also let other machines on the private network reach it. Narrow them so that no rule's source includes 10.250.0.0/20 (for example, replace 0.0.0.0/0 with the addresses you need), then try again.",
"request_id": "req_…"
}Follow the operation. While it runs the instance's private_network_state is attaching; when it has succeeded, it is attached and private_network_ip holds the address:
$ curl https://api.pantechdynamics.com/public/v1/instances/vm_… \ -H "Authorization: Bearer $PANTECH_API_KEY"{
"id": "vm_…",
"private_network_state": "attached",
"private_network_ip": "10.250.4.23"
}Step 3: configure it in the VPS
The new interface arrives down. Bring it up with DHCP, but take neither its routes nor its DNS: your VPS's default route and resolvers must stay on its public interface, or it loses the internet.
Find the interface's name. It is the one with no address, often ens4 or eth1:
$ ip -br linklo UNKNOWN 00:00:00:00:00:00ens3 UP 1e:00:4a:00:01:7cens4 DOWN 1e:00:91:00:03:b2Create a file of its own, so the image's own configuration is left alone:
network:
version: 2
ethernets:
ens4:
dhcp4: true
dhcp4-overrides:
use-routes: false
use-dns: false$ sudo chmod 600 /etc/netplan/60-pantech-private.yaml$ sudo netplan apply$ sudo nmcli connection add type ethernet ifname eth1 con-name pantech-private \ ipv4.method auto ipv4.never-default yes ipv4.ignore-auto-routes yes \ ipv4.ignore-auto-dns yes ipv6.method disabled$ sudo nmcli connection up pantech-privateCheck it has the address from private_network_ip, and that the default route is still on the public interface:
$ ip -br addr show ens4ens4 UP 10.250.4.23/20$ ip route show defaultdefault via 102.211.122.1 dev ens3 proto dhcp src 102.211.122.80 metric 100The database network is directly attached (10.250.0.0/20 dev ens4), so no route needs adding.
Step 4: allow it on the database
Add the VPS's private_network_ip as a /32 access rule. The rules are replaced as a whole, so send the full list, including any rules you already have:
$ curl -X PUT https://api.pantechdynamics.com/public/v1/databases/db_…/access-rules \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"rules": [{"cidr": "10.250.4.23/32"}]}'When that operation has succeeded, connect from the VPS using the database's hostname:
$ psql "host=db-3h8w1c6r0b.af-abj-1.db.pantechdynamics.com port=5432 user=dbadmin dbname=defaultdb"Use one /32 per VPS. A wider range such as 10.250.0.0/20 would admit every machine on the shared network, other customers' included.
With the CLI
$ pantech security-groups rules set web --rule ingress:tcp:22:203.0.113.0/24 \ --rule egress:all::0.0.0.0/0$ pantech vm private-network attach web-1$ pantech db access-rules add orders-db 10.250.4.23/32rules set replaces every rule of the group with the --rule DIRECTION:PROTOCOL:PORTS:CIDR flags given (here: SSH from one office, everything out, no ICMP), so the group admits nothing from 10.250.0.0/20. attach waits for the interface, then prints its address and the db access-rules add command to allow it. access-rules add keeps the database's other rules. If the group still admits the range, the CLI says which rules to narrow. pantech vm private-network detach web-1 removes the interface. Both wait for the operation; pass --no-wait to return its id at once.
With Terraform
In the provider's next release:
resource "pantechdynamics_instance" "web" {
name = "web-1"
plan_slug = "starter"
image_slug = "ubuntu-24-04"
ssh_key_id = pantechdynamics_ssh_key.admin.id
security_group_id = pantechdynamics_security_group.web.id
private_network = true
}
resource "pantechdynamics_database" "orders" {
name = "orders-db"
engine = "postgresql"
version = "18"
plan_slug = "starter"
zone_id = "af-abj-1"
access_rules = ["${pantechdynamics_instance.web.private_network_ip}/32"]
password_wo = var.orders_db_password
password_wo_version = 1
}private_network_ip is known once the interface is attached, so Terraform creates the database's rule after the instance has its address. The security group must already be narrow: Terraform does not change your rules for you, and an apply against a group that admits 10.250.0.0/20 fails with the error above.
Remove the interface
$ curl -X DELETE https://api.pantechdynamics.com/public/v1/instances/vm_…/private-network \ -H "Authorization: Bearer $PANTECH_API_KEY" \ -H "Idempotency-Key: $(uuidgen)"private_network_state goes detaching and then none. The address stays readable until it has gone. Afterwards:
- remove its
/32from each database's access rules, because the address can be given to another machine later, - delete the netplan file (or the NetworkManager connection) from the VPS.
Once the interface is gone, the security group may admit the private range again.
If something goes wrong
| What you see | Why | What to do |
|---|---|---|
409 SECURITY_GROUP_ALLOWS_PRIVATE_NETWORK | The VPS's group admits some of 10.250.0.0/20 | Narrow the rules the detail names (step 1) |
409 PRIVATE_NETWORK_NOT_AVAILABLE | The VPS is in a VPC, or in a zone without a database network | VMs in a VPC reach databases in their VPC directly |
409 INSTANCE_NOT_SETTLED | The VPS is starting, stopping, resizing, restoring or being deleted | Wait until it is running or stopped, then retry |
409 PRIVATE_NETWORK_ALREADY_ATTACHED | It already has the interface, or one is being added | Read private_network_ip |
409 PRIVATE_NETWORK_NOT_ATTACHED | A detach for a VPS with no interface | Nothing to do |
409 PRIVATE_NETWORK_CHANGE_IN_PROGRESS | An attach or detach is still running | Follow that operation first |
409 ACCOUNT_SUSPENDED | Attaching from a suspended account | Pay the overdue invoice. Detaching is always allowed |
422 RULE_ALLOWS_PRIVATE_NETWORK on rules | A rule change would admit the range while a VPS on the group has the interface | Leave the range out of the new rules |
The operation fails SECURITY_GROUP_ALLOWS_PRIVATE_NETWORK | The group's rules changed between your request and the attach | Narrow them again, then retry |
The operation fails INSTANCE_PRIVATE_NETWORK_ATTACH_FAILED or INSTANCE_BUSY | The interface could not be added; nothing changed | Retry with a new Idempotency-Key |
The VPS lost the internet after netplan apply | The private interface took the default route or DNS | Make sure use-routes: false and use-dns: false are set, then netplan apply |
| Connecting to the database times out | No access rule for the address, or the interface is down | Check ip -br addr and the database's effective_access_rules |
More codes are on the errors page.