Files
buque/internal/proxy/nginx.go
2025-11-02 01:41:51 +01:00

253 líneas
6.2 KiB
Go

package proxy
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/manalejandro/buque/internal/docker"
"github.com/manalejandro/buque/internal/models"
)
const (
nginxProxyImage = "nginxproxy/nginx-proxy:latest"
nginxProxyCompanionImage = "nginxproxy/acme-companion:latest"
)
// NginxManager manages nginx-proxy deployment and configuration
type NginxManager struct {
config models.NginxProxyConfig
dockerClient *docker.Client
composeManager *docker.ComposeManager
}
// NewNginxManager creates a new nginx-proxy manager
func NewNginxManager(config models.NginxProxyConfig) (*NginxManager, error) {
dockerClient, err := docker.NewClient()
if err != nil {
return nil, err
}
composeManager, err := docker.NewComposeManager()
if err != nil {
return nil, err
}
return &NginxManager{
config: config,
dockerClient: dockerClient,
composeManager: composeManager,
}, nil
}
// Close closes the nginx manager
func (nm *NginxManager) Close() error {
return nm.dockerClient.Close()
}
// Deploy deploys the nginx-proxy environment
func (nm *NginxManager) Deploy(ctx context.Context) error {
// Create nginx-proxy directory if it doesn't exist
if err := os.MkdirAll(nm.config.Path, 0755); err != nil {
return fmt.Errorf("failed to create nginx-proxy directory: %w", err)
}
// Create docker-compose.yml
composeContent := nm.generateComposeFile()
composePath := filepath.Join(nm.config.Path, "docker-compose.yml")
if err := os.WriteFile(composePath, []byte(composeContent), 0644); err != nil {
return fmt.Errorf("failed to write compose file: %w", err)
}
// Create network if it doesn't exist
exists, err := nm.dockerClient.NetworkExists(ctx, nm.config.NetworkName)
if err != nil {
return fmt.Errorf("failed to check network: %w", err)
}
if !exists {
if err := nm.dockerClient.CreateNetwork(ctx, nm.config.NetworkName); err != nil {
return fmt.Errorf("failed to create network: %w", err)
}
fmt.Printf("Created network: %s\n", nm.config.NetworkName)
}
// Deploy using docker-compose
env := models.Environment{
Name: "nginx-proxy",
Path: nm.config.Path,
ComposeFile: "docker-compose.yml",
Enabled: true,
}
fmt.Println("Deploying nginx-proxy...")
if err := nm.composeManager.Up(ctx, env, true); err != nil {
return fmt.Errorf("failed to deploy nginx-proxy: %w", err)
}
fmt.Println("Nginx-proxy deployed successfully!")
return nil
}
// Remove removes the nginx-proxy environment
func (nm *NginxManager) Remove(ctx context.Context) error {
env := models.Environment{
Name: "nginx-proxy",
Path: nm.config.Path,
ComposeFile: "docker-compose.yml",
Enabled: true,
}
fmt.Println("Removing nginx-proxy...")
if err := nm.composeManager.Down(ctx, env, true); err != nil {
return fmt.Errorf("failed to remove nginx-proxy: %w", err)
}
fmt.Println("Nginx-proxy removed successfully!")
return nil
}
// Status returns the status of nginx-proxy
func (nm *NginxManager) Status(ctx context.Context) (string, error) {
env := models.Environment{
Name: "nginx-proxy",
Path: nm.config.Path,
ComposeFile: "docker-compose.yml",
Enabled: true,
}
return nm.composeManager.PS(ctx, env)
}
// generateComposeFile generates the docker-compose.yml content for nginx-proxy
func (nm *NginxManager) generateComposeFile() string {
content := fmt.Sprintf(`version: '3.8'
services:
nginx-proxy:
image: %s
container_name: %s
restart: unless-stopped
ports:
- "%d:80"`, nginxProxyImage, nm.config.ContainerName, nm.config.HTTPPort)
if nm.config.SSLEnabled {
content += fmt.Sprintf(`
- "%d:443"`, nm.config.HTTPSPort)
}
content += `
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro`
if nm.config.SSLEnabled {
content += `
- certs:/etc/nginx/certs:ro
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html`
}
content += `
environment:
- DEFAULT_HOST=localhost
networks:
- ` + nm.config.NetworkName
content += `
labels:
- "buque.managed=true"
- "buque.service=nginx-proxy"`
if nm.config.SSLEnabled {
content += fmt.Sprintf(`
acme-companion:
image: %s
container_name: nginx-proxy-acme
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- certs:/etc/nginx/certs
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- acme:/etc/acme.sh
environment:
- DEFAULT_EMAIL=admin@localhost
- NGINX_PROXY_CONTAINER=%s
networks:
- %s
depends_on:
- nginx-proxy
labels:
- "buque.managed=true"
- "buque.service=nginx-proxy-acme"`, nginxProxyCompanionImage, nm.config.ContainerName, nm.config.NetworkName)
}
content += `
networks:
` + nm.config.NetworkName + `:
external: true`
if nm.config.SSLEnabled {
content += `
volumes:
certs:
vhost:
html:
acme:`
}
return content
}
// GenerateServiceLabels generates labels for a service to work with nginx-proxy
func (nm *NginxManager) GenerateServiceLabels(virtualHost string, virtualPort int, letsencryptHost string, letsencryptEmail string) map[string]string {
labels := map[string]string{
"VIRTUAL_HOST": virtualHost,
}
if virtualPort > 0 {
labels["VIRTUAL_PORT"] = fmt.Sprintf("%d", virtualPort)
}
if nm.config.SSLEnabled && letsencryptHost != "" {
labels["LETSENCRYPT_HOST"] = letsencryptHost
if letsencryptEmail != "" {
labels["LETSENCRYPT_EMAIL"] = letsencryptEmail
}
}
return labels
}
// GetExampleServiceCompose returns an example docker-compose.yml for a service behind nginx-proxy
func (nm *NginxManager) GetExampleServiceCompose(serviceName, virtualHost string) string {
return fmt.Sprintf(`version: '3.8'
services:
%s:
image: your-image:latest
container_name: %s
restart: unless-stopped
expose:
- "80"
environment:
- VIRTUAL_HOST=%s
- VIRTUAL_PORT=80
- LETSENCRYPT_HOST=%s
- LETSENCRYPT_EMAIL=admin@%s
networks:
- %s
labels:
- "buque.environment=%s"
- "buque.managed=true"
networks:
%s:
external: true
`, serviceName, serviceName, virtualHost, virtualHost, virtualHost, nm.config.NetworkName, serviceName, nm.config.NetworkName)
}