fix: [#222] Configure SSH port via cloud-init with reboot pattern#223
Merged
josecelano merged 3 commits intomainfrom Dec 12, 2025
Merged
fix: [#222] Configure SSH port via cloud-init with reboot pattern#223josecelano merged 3 commits intomainfrom
josecelano merged 3 commits intomainfrom
Conversation
- Add ssh_port field to CloudInitContext with builder pattern - Update cloud-init.yml.tera to configure SSH port via write_files - Pass ssh_port from environment to TofuProjectGenerator - Refactor CloudInitRenderer: remove unused provider field, move ssh_port to render method - Update all tests to use new CloudInitRenderer API - Update issue spec to document cloud-init approach and explain why Ansible was discarded This implementation configures SSH port during VM initialization (provision phase) rather than post-provisioning (configure phase), ensuring SSH service is listening on the configured port before any Ansible connections are attempted.
Implements custom SSH port configuration during VM provisioning using cloud-init's reboot pattern following Hetzner best practices. Solution Overview: - Cloud-init writes SSH config file and triggers system reboot - Reboot ensures clean SSH restart with new port configuration - Provision handler waits for configured port (not default port 22) - Increased timeout from 60s to 120s for cloud-init + reboot time Key Changes: 1. Cloud-init template: Added write_files + runcmd with reboot 2. Provision handler: Use configured SSH port in wait_for_readiness() 3. SSH adapter: Increased DEFAULT_MAX_RETRY_ATTEMPTS from 30 to 60 4. Documentation: Created ADR and updated issue spec Technical Details: - Cloud-init creates /etc/ssh/sshd_config.d/99-custom-port.conf - System reboot guarantees SSH only on custom port (no port 22) - Total timeout: 120 seconds (60 attempts × 2 second interval) - Testing confirmed: SSH listens only on configured port after reboot Why Reboot Approach: - systemctl restart doesn't kill old SSH process when port changes - bootcmd ineffective - systemd auto-restarts SSH after bootcmd - Reboot is cleaner and follows Hetzner cloud-config tutorial Files Modified: - templates/tofu/common/cloud-init.yml.tera - src/application/command_handlers/provision/handler.rs - src/adapters/ssh/config.rs - docs/decisions/cloud-init-ssh-port-reboot.md (new) - docs/decisions/README.md - docs/issues/222-configure-ssh-service-port.md - project-words.txt References: - Hetzner cloud-config tutorial section 5.3 - Issue #222
50 tasks
The cloud-init template was unconditionally configuring SSH port and
rebooting the VM, even when using the default port 22. This caused:
- Unnecessary VM reboots for environments using default SSH port
- E2E infrastructure lifecycle test failures on GitHub Actions
- Longer provisioning times for default configurations
Root Cause:
- Cloud-init template always wrote SSH port config file and triggered reboot
- E2E test uses default port 22, but was forced to reboot unnecessarily
- GitHub runner timed out waiting for SSH after unnecessary reboot
Solution:
- Add Tera conditional {% if ssh_port != 22 %} around write_files and runcmd
- SSH port configuration and reboot now only happen for custom ports
- E2E tests with default port 22 no longer trigger unnecessary reboots
- Provisioning is faster for default port configurations
Benefits:
- Faster provisioning when using default SSH port (no reboot overhead)
- E2E tests pass on GitHub Actions without timeout issues
- Still maintains reboot pattern for custom ports (proper SSH restart)
- Conditional approach is more efficient and user-friendly
Files Modified:
- templates/tofu/common/cloud-init.yml.tera: Add conditional around write_files and runcmd
- docs/issues/222-configure-ssh-service-port.md: Document conditional behavior
- docs/decisions/cloud-init-ssh-port-reboot.md: Add positive consequence about conditional execution
Technical Details:
The Tera template now checks if ssh_port != 22 before:
1. Writing /etc/ssh/sshd_config.d/99-custom-port.conf
2. Executing runcmd: [reboot]
This preserves the reboot pattern for custom ports (ensuring clean SSH restart)
while avoiding unnecessary reboots for default port configurations.
Testing:
- All 1424 unit tests pass
- All doctests pass
- E2E infrastructure lifecycle tests pass (default port 22, no reboot)
- E2E deployment workflow tests pass
- Documentation builds successfully
- Pre-commit verification: ✅ All checks passed
Member
Author
|
ACK 41cda98 |
josecelano
added a commit
that referenced
this pull request
Dec 12, 2025
Removed docs/issues/222-configure-ssh-service-port.md as PR #223 has been successfully merged into main. The implementation details are now preserved in the ADR (docs/decisions/cloud-init-ssh-port-reboot.md) and git history.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Implements custom SSH port configuration during VM provisioning using cloud-init's reboot pattern following Hetzner best practices.
Fixes #222
Solution Overview
Key Changes
write_files+runcmdwith rebootwait_for_readiness()DEFAULT_MAX_RETRY_ATTEMPTSfrom 30 to 60Technical Details
/etc/ssh/sshd_config.d/99-custom-port.confWhy Reboot Approach?
systemctl restartdoesn't kill old SSH process when port changesbootcmdineffective - systemd auto-restarts SSH after bootcmdFiles Modified
templates/tofu/common/cloud-init.yml.terasrc/application/command_handlers/provision/handler.rssrc/adapters/ssh/config.rsdocs/decisions/cloud-init-ssh-port-reboot.md(new)docs/decisions/README.mddocs/issues/222-configure-ssh-service-port.mdproject-words.txtReferences