diff --git a/install/config/config.yml b/install/config/config.yml index 1f50057e8..85dbc944f 100644 --- a/install/config/config.yml +++ b/install/config/config.yml @@ -37,3 +37,8 @@ flags: disable_signup_without_invite: true disable_user_create_org: false allow_raw_resources: true + +{{if .IsPostgreSQL}} +postgres: + connection_string: postgresql://pangolin:{{.IsPostgreSQLPass}}@postgres:5432/pangolin +{{end}} diff --git a/install/config/docker-compose.yml b/install/config/docker-compose.yml index 505089bed..fe6a41644 100644 --- a/install/config/docker-compose.yml +++ b/install/config/docker-compose.yml @@ -1,7 +1,7 @@ name: pangolin services: pangolin: - image: docker.io/fosrl/pangolin:{{if .IsEnterprise}}ee-{{end}}{{.PangolinVersion}} + image: docker.io/fosrl/pangolin:{{if .IsEnterprise}}ee-{{end}}{{if .IsPostgreSQL}}postgresql-{{end}}{{.PangolinVersion}} container_name: pangolin restart: unless-stopped deploy: @@ -10,6 +10,20 @@ services: memory: 1g reservations: memory: 256m +{{if or .IsPostgreSQL .IsRedis}} + depends_on: + {{if .IsPostgreSQL}} + postgres: + condition: service_healthy + {{end}} + {{if .IsRedis}} + redis: + condition: service_healthy + {{end}} + networks: + - default + - backend +{{end}} volumes: - ./config:/app/config healthcheck: @@ -60,8 +74,56 @@ services: - ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates - ./config/traefik/logs:/var/log/traefik # Volume to store Traefik logs +{{if .IsPostgreSQL}} + postgres: + image: postgres:18 + container_name: postgres + restart: unless-stopped + environment: + POSTGRES_USER: pangolin + POSTGRES_PASSWORD: {{.IsPostgreSQLPass}} + POSTGRES_DB: pangolin + volumes: + - ./postgres18:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U pangolin"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - backend +{{end}} + +{{if .IsRedis}} + redis: + image: redis:8-trixie + container_name: redis + restart: unless-stopped + command: > + redis-server + --save 3600 1000 + --appendonly yes + --requirepass {{.IsRedisPass}} + volumes: + - ./redis8:/data + healthcheck: + test: ["CMD", "redis-cli", "-a", "{{.IsRedisPass}}", "ping"] + interval: 10s + timeout: 3s + retries: 3 + start_period: 10s + networks: + - backend +{{end}} + networks: default: driver: bridge - name: pangolin + name: pangolin_frontend {{if .EnableIPv6}} enable_ipv6: true{{end}} +{{if or .IsPostgreSQL .IsRedis}} + backend: + driver: bridge + name: pangolin_backend + internal: true +{{end}} diff --git a/install/config/privateConfig.yml b/install/config/privateConfig.yml new file mode 100644 index 000000000..58a4c9435 --- /dev/null +++ b/install/config/privateConfig.yml @@ -0,0 +1,6 @@ +{{if .IsRedis}} +redis: + host: "redis" + port: 6379 + password: "{{.IsRedisPass}}" +{{end}} diff --git a/install/main.go b/install/main.go index f12a0c769..5687f6f5d 100644 --- a/install/main.go +++ b/install/main.go @@ -57,6 +57,10 @@ type Config struct { EnableMaxMind bool Secret string IsEnterprise bool + IsPostgreSQL bool + IsPostgreSQLPass string + IsRedis bool + IsRedisPass string } type SupportedContainer string @@ -486,6 +490,17 @@ func collectUserInput() Config { fmt.Println("\n=== Basic Configuration ===") config.IsEnterprise = readBoolNoDefault("Do you want to install the Enterprise version of Pangolin? The EE is free for personal use or for businesses making less than 100k USD annually.") + if config.IsEnterprise { + config.IsRedis = readBool("Do you want to run the Redis containers locally? Required for HA.") + if config.IsRedis { + config.IsRedisPass = readPassword("Enter a unique password for the Redis service.") + } + } + + config.IsPostgreSQL = readBool("Do you want to run the PostgreSQL containers locally? Otherwise, default to the local SQLite database only.", false) + if config.IsPostgreSQL { + config.IsPostgreSQLPass = readPassword("Enter a unique password for the PostgreSQL pangolin user.") + } config.BaseDomain = readString("Enter your base domain (no subdomain e.g. example.com)", "")