mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-06-18 10:06:26 +00:00
Support for dynamic ip ranges from urls
- Adds ipranges command to fetch ip ranges from Cloudfront and Cloudflare - Write the ipranges file on docker start - Support disabling ipv4 as well as ipv6 now - Prevent disabling both
This commit is contained in:
@ -32,6 +32,9 @@ tasks:
|
||||
silent: true
|
||||
- cmd: go build -buildvcs=false -ldflags="-X main.commit={{.GIT_COMMIT}} -X main.version={{.VERSION}}" -o ../dist/bin/server ./cmd/server/main.go
|
||||
silent: true
|
||||
- cmd: go build -buildvcs=false -ldflags="-X main.commit={{.GIT_COMMIT}} -X main.version={{.VERSION}}" -o ../dist/bin/ipranges ./cmd/ipranges/main.go
|
||||
silent: true
|
||||
- cmd: rm -f /etc/nginx/conf.d/include/ipranges.conf && /app/dist/bin/ipranges > /etc/nginx/conf.d/include/ipranges.conf
|
||||
- task: lint
|
||||
vars:
|
||||
GIT_COMMIT:
|
||||
|
126
backend/cmd/ipranges/main.go
Normal file
126
backend/cmd/ipranges/main.go
Normal file
@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"npm/internal/config"
|
||||
"npm/internal/model"
|
||||
|
||||
"github.com/rotisserie/eris"
|
||||
)
|
||||
|
||||
var commit string
|
||||
var version string
|
||||
var sentryDSN string
|
||||
|
||||
var cloudfrontURL = "https://ip-ranges.amazonaws.com/ip-ranges.json"
|
||||
var cloudflare4URL = "https://www.cloudflare.com/ips-v4"
|
||||
var cloudflare6URL = "https://www.cloudflare.com/ips-v6"
|
||||
|
||||
func main() {
|
||||
config.InitArgs(&version, &commit)
|
||||
if err := config.InitIPRanges(&version, &commit, &sentryDSN); err != nil {
|
||||
fmt.Printf("# Config ERROR: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
exitCode := 0
|
||||
|
||||
// Cloudfront
|
||||
fmt.Printf("# Cloudfront Ranges from: %s\n", cloudfrontURL)
|
||||
if ranges, err := parseCloudfront(); err == nil {
|
||||
for _, item := range ranges {
|
||||
fmt.Printf("set_real_ip_from %s;\n", item)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("# ERROR: %v\n", err)
|
||||
}
|
||||
|
||||
// Cloudflare ipv4
|
||||
if !config.Configuration.DisableIPV4 {
|
||||
fmt.Printf("\n# Cloudflare Ranges from: %s\n", cloudflare4URL)
|
||||
if ranges, err := parseCloudflare(cloudflare4URL); err == nil {
|
||||
for _, item := range ranges {
|
||||
fmt.Printf("set_real_ip_from %s;\n", item)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("# ERROR: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Cloudflare ipv6
|
||||
if !config.Configuration.DisableIPV6 {
|
||||
fmt.Printf("\n# Cloudflare Ranges from: %s\n", cloudflare6URL)
|
||||
if ranges, err := parseCloudflare(cloudflare6URL); err == nil {
|
||||
for _, item := range ranges {
|
||||
fmt.Printf("set_real_ip_from %s;\n", item)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("# ERROR: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func parseCloudfront() ([]string, error) {
|
||||
// nolint: gosec
|
||||
resp, err := http.Get(cloudfrontURL)
|
||||
if err != nil {
|
||||
return nil, eris.Wrapf(err, "Failed to download Cloudfront IP Ranges from %s", cloudfrontURL)
|
||||
}
|
||||
|
||||
// nolint: errcheck, gosec
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, eris.Wrapf(err, "Failed to read Cloudfront IP Ranges body")
|
||||
}
|
||||
|
||||
var result model.CloudfrontIPRanges
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, eris.Wrapf(err, "Failed to unmarshal Cloudfront IP Ranges file")
|
||||
}
|
||||
|
||||
ranges := make([]string, 0)
|
||||
if !config.Configuration.DisableIPV4 {
|
||||
for _, item := range result.IPV4Prefixes {
|
||||
ranges = append(ranges, item.Value)
|
||||
}
|
||||
}
|
||||
if !config.Configuration.DisableIPV6 {
|
||||
for _, item := range result.IPV6Prefixes {
|
||||
ranges = append(ranges, item.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return ranges, nil
|
||||
}
|
||||
|
||||
func parseCloudflare(url string) ([]string, error) {
|
||||
// nolint: gosec
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, eris.Wrapf(err, "Failed to download Cloudflare IP Ranges from %s", url)
|
||||
}
|
||||
|
||||
// nolint: errcheck, gosec
|
||||
defer resp.Body.Close()
|
||||
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
ranges := make([]string, 0)
|
||||
for scanner.Scan() {
|
||||
if scanner.Text() != "" {
|
||||
ranges = append(ranges, scanner.Text())
|
||||
}
|
||||
}
|
||||
return ranges, nil
|
||||
}
|
@ -29,6 +29,16 @@ func Init(version, commit, sentryDSN *string) {
|
||||
loadKeys()
|
||||
}
|
||||
|
||||
// InitIPRanges will initialise the config for the ipranges command
|
||||
func InitIPRanges(version, commit, sentryDSN *string) error {
|
||||
ErrorReporting = true
|
||||
Version = *version
|
||||
Commit = *commit
|
||||
err := envconfig.InitWithPrefix(&Configuration, "NPM")
|
||||
initLogger(*sentryDSN)
|
||||
return err
|
||||
}
|
||||
|
||||
// Init initialises the Log object and return it
|
||||
func initLogger(sentryDSN string) {
|
||||
// this removes timestamp prefixes from logs
|
||||
|
@ -38,9 +38,11 @@ type acmesh struct {
|
||||
|
||||
// Configuration is the main configuration object
|
||||
var Configuration struct {
|
||||
DataFolder string `json:"data_folder" envconfig:"optional,default=/data"`
|
||||
Acmesh acmesh `json:"acmesh"`
|
||||
Log log `json:"log"`
|
||||
DataFolder string `json:"data_folder" envconfig:"optional,default=/data"`
|
||||
DisableIPV4 bool `json:"disable_ipv4" envconfig:"optional"`
|
||||
DisableIPV6 bool `json:"disable_ipv6" envconfig:"optional"`
|
||||
Acmesh acmesh `json:"acmesh"`
|
||||
Log log `json:"log"`
|
||||
}
|
||||
|
||||
// GetWellknown returns the well known path
|
||||
|
17
backend/internal/model/cloudfrontranges.go
Normal file
17
backend/internal/model/cloudfrontranges.go
Normal file
@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
// CloudfrontIPRangePrefix is used within config for cloudfront
|
||||
type CloudfrontIPRangeV4Prefix struct {
|
||||
Value string `json:"ip_prefix"`
|
||||
}
|
||||
|
||||
// CloudfrontIPRangeV6Prefix is used within config for cloudfront
|
||||
type CloudfrontIPRangeV6Prefix struct {
|
||||
Value string `json:"ipv6_prefix"`
|
||||
}
|
||||
|
||||
// CloudfrontIPRanges is the main config for cloudfront
|
||||
type CloudfrontIPRanges struct {
|
||||
IPV4Prefixes []CloudfrontIPRangeV4Prefix `json:"prefixes"`
|
||||
IPV6Prefixes []CloudfrontIPRangeV6Prefix `json:"ipv6_prefixes"`
|
||||
}
|
@ -39,8 +39,8 @@ func ConfigureHost(h host.Model) error {
|
||||
Certificate: certificateTemplate,
|
||||
ConfDir: fmt.Sprintf("%s/nginx/hosts", config.Configuration.DataFolder),
|
||||
Config: Config{ // todo
|
||||
Ipv4: true,
|
||||
Ipv6: false,
|
||||
Ipv4: !config.Configuration.DisableIPV4,
|
||||
Ipv6: !config.Configuration.DisableIPV6,
|
||||
},
|
||||
DataDir: config.Configuration.DataFolder,
|
||||
Host: h.GetTemplate(),
|
||||
|
Reference in New Issue
Block a user