Skip to content

Commit dee9e14

Browse files
authored
Merge pull request #73 from raghavyuva/fix/port_conflict
Fix Port Confliction in Self Hosted Appications
2 parents fa7632d + 2ebb033 commit dee9e14

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

api/internal/features/deploy/service/run_image.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/google/uuid"
1111
"github.com/raghavyuva/nixopus-api/internal/features/deploy/types"
1212
"github.com/raghavyuva/nixopus-api/internal/features/logger"
13+
"github.com/raghavyuva/nixopus-api/internal/features/ssh"
1314
shared_types "github.com/raghavyuva/nixopus-api/internal/types"
1415
)
1516

@@ -66,20 +67,53 @@ func (s *DeployService) prepareContainerConfig(
6667

6768
// prepareHostConfig creates Docker host configuration with port bindings
6869
func (s *DeployService) prepareHostConfig(port nat.Port) container.HostConfig {
70+
availablePort, err := s.getAvailablePort()
71+
if err != nil {
72+
s.logger.Log(logger.Error, types.ErrFailedToGetAvailablePort.Error(), err.Error())
73+
return container.HostConfig{}
74+
}
75+
6976
return container.HostConfig{
7077
NetworkMode: "bridge",
7178
PortBindings: map[nat.Port][]nat.PortBinding{
7279
port: {
7380
{
7481
HostIP: "0.0.0.0",
75-
HostPort: port.Port(),
82+
HostPort: availablePort,
7683
},
7784
},
7885
},
7986
PublishAllPorts: true,
8087
}
8188
}
8289

90+
func (s *DeployService) getAvailablePort() (string, error) {
91+
ssh := ssh.NewSSH()
92+
client, err := ssh.Connect()
93+
if err != nil {
94+
return "", err
95+
}
96+
defer client.Close()
97+
98+
generatePorts := "seq 49152 65535"
99+
100+
getUsedPorts := "command -v ss >/dev/null 2>&1 && ss -tan | awk '{print $4}' | cut -d':' -f2 | grep '[0-9]\\{1,5\\}' | sort -u || netstat -tan | awk '{print $4}' | grep ':[0-9]' | cut -d':' -f2 | sort -u"
101+
102+
cmd := fmt.Sprintf("comm -23 <(%s) <(%s) | sort -R | head -n 1 | tr -d '\\n'", generatePorts, getUsedPorts)
103+
104+
output, err := client.Run(cmd)
105+
if err != nil {
106+
return "", fmt.Errorf("failed to find available port: %w", err)
107+
}
108+
109+
port := string(output)
110+
if port == "" {
111+
return "", fmt.Errorf("no available ports found in range 49152-65535")
112+
}
113+
114+
return port, nil
115+
}
116+
83117
// prepareNetworkConfig creates Docker network configuration
84118
func (s *DeployService) prepareNetworkConfig() network.NetworkingConfig {
85119
return network.NetworkingConfig{

api/internal/features/deploy/types/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ var (
9494
ErrDockerComposeFileNotFound = errors.New("docker-compose file not found")
9595
ErrDockerComposeCommandFailed = errors.New("docker-compose command failed")
9696
ErrDockerComposeInvalidConfig = errors.New("invalid docker-compose configuration")
97+
ErrFailedToGetAvailablePort = errors.New("failed to get available port")
9798
)
9899

99100
const (

0 commit comments

Comments
 (0)