Documentation

esc
    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:

    1. You check the VPS's security group admits nothing from 10.250.0.0/20 (the reason is below).
    2. You ask for the interface. The VPS gets an address on 10.250.0.0/20: its private_network_ip.
    3. You bring the interface up inside the VPS, with DHCP but without its routes or DNS.
    4. You add <private_network_ip>/32 to 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/0 contains the range, 10.0.0.0/8 contains it, and 10.250.3.17/32 sits 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:

    Terminal
    $ 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:

    1. Allow only the addresses you need. Best for SSH: your office's or your VPN's range, like 203.0.113.0/24.
    2. Drop it. The ICMP rule is only for ping; most machines do without it.
    3. Keep it open to the internet, minus the private range. Replace 0.0.0.0/0 with these 20 ranges, which together cover every IPv4 address except 10.250.0.0/20:
    text
    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/1

    Rules 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:

    Terminal
    $ 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.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

    Terminal
    $ curl -X POST https://api.pantechdynamics.com/public/v1/instances/vm_…/private-network \    -H "Authorization: Bearer $PANTECH_API_KEY" \    -H "Idempotency-Key: $(uuidgen)"
    JSON
    {
      "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:

    JSON
    {
      "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:

    Terminal
    $ curl https://api.pantechdynamics.com/public/v1/instances/vm_… \    -H "Authorization: Bearer $PANTECH_API_KEY"
    JSON
    {
      "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:

    Terminal
    $ ip -br linklo               UNKNOWN        00:00:00:00:00:00ens3             UP             1e:00:4a:00:01:7cens4             DOWN           1e:00:91:00:03:b2

    Create a file of its own, so the image's own configuration is left alone:

    /etc/netplan/60-pantech-private.yaml
    network:
      version: 2
      ethernets:
        ens4:
          dhcp4: true
          dhcp4-overrides:
            use-routes: false
            use-dns: false
    Terminal
    $ sudo chmod 600 /etc/netplan/60-pantech-private.yaml$ sudo netplan apply

    Check it has the address from private_network_ip, and that the default route is still on the public interface:

    Terminal
    $ 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 100

    The 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:

    Terminal
    $ 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:

    Terminal
    $ 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

    Terminal
    $ 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/32

    rules 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:

    HCL
    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

    Terminal
    $ 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 /32 from 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 seeWhyWhat to do
    409 SECURITY_GROUP_ALLOWS_PRIVATE_NETWORKThe VPS's group admits some of 10.250.0.0/20Narrow the rules the detail names (step 1)
    409 PRIVATE_NETWORK_NOT_AVAILABLEThe VPS is in a VPC, or in a zone without a database networkVMs in a VPC reach databases in their VPC directly
    409 INSTANCE_NOT_SETTLEDThe VPS is starting, stopping, resizing, restoring or being deletedWait until it is running or stopped, then retry
    409 PRIVATE_NETWORK_ALREADY_ATTACHEDIt already has the interface, or one is being addedRead private_network_ip
    409 PRIVATE_NETWORK_NOT_ATTACHEDA detach for a VPS with no interfaceNothing to do
    409 PRIVATE_NETWORK_CHANGE_IN_PROGRESSAn attach or detach is still runningFollow that operation first
    409 ACCOUNT_SUSPENDEDAttaching from a suspended accountPay the overdue invoice. Detaching is always allowed
    422 RULE_ALLOWS_PRIVATE_NETWORK on rulesA rule change would admit the range while a VPS on the group has the interfaceLeave the range out of the new rules
    The operation fails SECURITY_GROUP_ALLOWS_PRIVATE_NETWORKThe group's rules changed between your request and the attachNarrow them again, then retry
    The operation fails INSTANCE_PRIVATE_NETWORK_ATTACH_FAILED or INSTANCE_BUSYThe interface could not be added; nothing changedRetry with a new Idempotency-Key
    The VPS lost the internet after netplan applyThe private interface took the default route or DNSMake sure use-routes: false and use-dns: false are set, then netplan apply
    Connecting to the database times outNo access rule for the address, or the interface is downCheck ip -br addr and the database's effective_access_rules

    More codes are on the errors page.

    Was this page helpful?

    Updated