@@ -326,6 +326,191 @@ make infra-apply ENVIRONMENT_TYPE=production ENVIRONMENT_FILE=production-hetzner
326326make app-deploy ENVIRONMENT_TYPE=production ENVIRONMENT_FILE=production-hetzner
327327```
328328
329+ ## Step 6.5: Configure Floating IP Network Interface
330+
331+ After infrastructure deployment, Hetzner assigns the floating IP at the cloud level, but
332+ the server requires additional network configuration to use the floating IP for external
333+ connectivity. This is a ** required step** for floating IP functionality.
334+
335+ ### Why This Step is Necessary
336+
337+ Hetzner's floating IP system requires two-phase configuration:
338+
339+ 1 . ** Cloud-level assignment** (handled by Terraform during ` infra-apply ` )
340+ 2 . ** Server-level network interface configuration** (manual step detailed below)
341+
342+ Without the server-side configuration, the floating IP will not be accessible externally,
343+ even though it appears assigned in the Hetzner Cloud Console.
344+
345+ ### 6.5.1 Verify Current Network Configuration
346+
347+ First, check the current network setup:
348+
349+ ``` bash
350+ # SSH into your server
351+ make vm-ssh ENVIRONMENT=staging # or production
352+
353+ # Check current network interfaces
354+ ip addr show eth0
355+
356+ # Check current netplan configuration
357+ sudo cat /etc/netplan/50-cloud-init.yaml
358+ ```
359+
360+ You should see output similar to:
361+
362+ ``` text
363+ 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
364+ link/ether 96:00:00:12:34:56 brd ff:ff:ff:ff:ff:ff
365+ inet 188.245.95.154/32 scope global dynamic eth0
366+ valid_lft 86395sec preferred_lft 86395sec
367+ inet6 2a01:4f8:c014:333e::1/64 scope global
368+ valid_lft forever preferred_lft forever
369+ ```
370+
371+ Note that only the DHCP IP (e.g., ` 188.245.95.154 ` ) and IPv6 address are configured.
372+
373+ ### 6.5.2 Configure Floating IP on Network Interface
374+
375+ Create a separate netplan configuration for the floating IP:
376+
377+ ``` bash
378+ # Create floating IP network configuration
379+ sudo tee /etc/netplan/60-floating-ip.yaml > /dev/null << 'EOF '
380+ network:
381+ version: 2
382+ renderer: networkd
383+ ethernets:
384+ eth0:
385+ dhcp4: true
386+ addresses:
387+ - 78.47.140.132/32
388+ EOF
389+
390+ # Set proper permissions
391+ sudo chmod 600 /etc/netplan/60-floating-ip.yaml
392+
393+ # Validate the configuration
394+ sudo netplan try
395+
396+ # If validation succeeds, apply the configuration
397+ sudo netplan apply
398+ ```
399+
400+ ** Important** : Replace ` 78.47.140.132 ` with your actual floating IP address from your
401+ environment configuration file.
402+
403+ ### 6.5.3 Verify Floating IP Configuration
404+
405+ After applying the configuration, verify both IP addresses are active:
406+
407+ ``` bash
408+ # Check that both IPs are configured on eth0
409+ ip addr show eth0
410+
411+ # Expected output should show both addresses:
412+ # inet 78.47.140.132/32 scope global eth0 <- Floating IP
413+ # inet 188.245.95.154/32 scope global dynamic eth0 <- DHCP IP
414+
415+ # Test internal connectivity to floating IP
416+ ping -c 3 78.47.140.132
417+
418+ # Check systemd-networkd status
419+ sudo systemctl status systemd-networkd
420+ ```
421+
422+ ### 6.5.4 Test External Connectivity
423+
424+ From your local machine, test connectivity to the floating IP:
425+
426+ ``` bash
427+ # Test SSH connectivity (may take a few minutes for routing to propagate)
428+ timeout 10 ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 \
429+ [email protected] " echo 'Floating IP SSH works'" 430+
431+ # Test ping connectivity
432+ ping -c 3 78.47.140.132
433+
434+ # Test HTTP port connectivity
435+ timeout 5 nc -zv 78.47.140.132 22
436+ ```
437+
438+ ** Note** : External connectivity may take 2-5 minutes to become available after configuration
439+ due to Hetzner's network routing propagation. If connectivity tests fail initially, wait
440+ a few minutes and retry.
441+
442+ ### 6.5.5 Understanding the Network Configuration
443+
444+ The floating IP configuration uses this approach:
445+
446+ ``` yaml
447+ network :
448+ version : 2
449+ renderer : networkd
450+ ethernets :
451+ eth0 :
452+ dhcp4 : true # Preserves DHCP for primary IP
453+ addresses :
454+ - 78.47.140.132/32 # Adds floating IP as additional address
455+ ` ` `
456+
457+ This configuration:
458+
459+ - ✅ **Preserves DHCP**: Maintains automatic IP assignment from Hetzner
460+ - ✅ **Adds Floating IP**: Configures floating IP as additional address
461+ - ✅ **Maintains Connectivity**: Ensures both IPs work simultaneously
462+ - ✅ **Persistent Setup**: Survives server reboots
463+
464+ ### 6.5.6 Troubleshooting
465+
466+ If you encounter issues:
467+
468+ 1. **Check netplan syntax**:
469+
470+ ` ` ` bash
471+ sudo netplan try
472+ ```
473+
474+ 2 . ** Verify file permissions** :
475+
476+ ``` bash
477+ ls -la /etc/netplan/60-floating-ip.yaml
478+ # Should show: -rw------- 1 root root
479+ ```
480+
481+ 3 . ** Check systemd-networkd logs** :
482+
483+ ``` bash
484+ sudo journalctl -u systemd-networkd -f
485+ ```
486+
487+ 4 . ** Reset network configuration if needed** :
488+
489+ ``` bash
490+ # Remove floating IP config and restart networking
491+ sudo rm /etc/netplan/60-floating-ip.yaml
492+ sudo netplan apply
493+ # Then recreate the configuration
494+ ```
495+
496+ 5 . ** Verify cloud-level assignment** :
497+
498+ ``` bash
499+ # Check Hetzner Cloud Console or use CLI
500+ HCLOUD_TOKEN=" $HETZNER_API_TOKEN " hcloud floating-ip list
501+ ```
502+
503+ ### 6.5.7 Important Notes
504+
505+ - ** Two-phase requirement** : Both cloud assignment AND server configuration are required
506+ - ** Propagation time** : External connectivity may take several minutes to become available
507+ - ** Persistent configuration** : This setup survives server reboots
508+ - ** Multiple IPs** : The server maintains both DHCP and floating IP addresses
509+ - ** Firewall compatibility** : UFW rules apply to both IP addresses automatically
510+
511+ After completing this step, your floating IP should be externally accessible and ready
512+ for DNS configuration in the next step.
513+
329514## Step 7: Configure DNS
330515
331516After deployment, you need to configure DNS to point your domain to the floating
0 commit comments