From bc1d8a92656e8cc30500eaeb36b6b9864b6a722b Mon Sep 17 00:00:00 2001 From: Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com> Date: Sat, 24 Jul 2021 19:02:41 +0200 Subject: [PATCH] allow custom ports for webserver and le (#111) --- GETTINGSTARTED.md | 14 +++++++++++--- cmd/gotosocial/generalflags.go | 6 ++++++ cmd/gotosocial/letsencryptflags.go | 6 ++++++ example/config.yaml | 25 +++++++++++++++++++++---- internal/config/config.go | 17 +++++++++++++++++ internal/config/default.go | 7 +++++++ internal/config/letsencrypt.go | 8 +++++--- internal/router/router.go | 22 ++++++---------------- 8 files changed, 79 insertions(+), 26 deletions(-) diff --git a/GETTINGSTARTED.md b/GETTINGSTARTED.md index be5ab231..de4cb520 100644 --- a/GETTINGSTARTED.md +++ b/GETTINGSTARTED.md @@ -33,7 +33,13 @@ docker run -d --network host --user postgres -e POSTGRES_PASSWORD=some_password On your local machine (not your server), with Go installed, clone the GoToSocial repository, and build the binary with the provided build script: ```bash -./build/sh +./build.sh +``` + +If you need to build for a different architecture other than the one you're running the build on (eg., you're running on a Raspberry Pi but building on an amd64 machine), you can put set `GOOS` or `GOARCH` environment variables before running the build script, eg: + +```bash +GOARCH=arm64 ./build.sh ``` ### 6: Prepare VPS @@ -52,7 +58,7 @@ Copy your binary from your local machine onto the VPS, using something like the scp ./gotosocial root@example.org:/gotosocial/gotosocial ``` -Replace `root` with whatever user you're actually running on your remote server. +Replace `root` with whatever user you're actually running on your remote server (you wouldn't run as root right? ;). ### 8: Copy Web Dir @@ -75,11 +81,13 @@ cd /gotosocial Then start the GoToSocial server with the following command (where `example.org` is the domain you set up in step 1, and `some_password` is the password you set for Postgres in step 4): ```bash -./gotosocial --host example.org --storage-serve-host example.org --letsencrypt-enabled=true server start +./gotosocial --host example.org --port 443 --storage-serve-host example.org --letsencrypt-enabled=true server start ``` The server should now start up and you should be able to access the splash page by navigating to your domain in the browser. Note that it might take up to a minute or so for your LetsEncrypt certificates to be created for the first time, so refresh a few times if necessary. +Note that for this example we're assuming that we're allowed to run on port 443 (standard https port), and that nothing else is running on this port. + ### 10: Create and confirm your user You can use the GoToSocial binary to also create, confirm, and promote your user account. diff --git a/cmd/gotosocial/generalflags.go b/cmd/gotosocial/generalflags.go index 3b0b9806..06d6e892 100644 --- a/cmd/gotosocial/generalflags.go +++ b/cmd/gotosocial/generalflags.go @@ -62,5 +62,11 @@ func generalFlags(flagNames, envNames config.Flags, defaults config.Defaults) [] Value: defaults.Protocol, EnvVars: []string{envNames.Protocol}, }, + &cli.IntFlag{ + Name: flagNames.Port, + Usage: "Port to use for GoToSocial. Change this to 443 if you're running the binary directly on the host machine.", + Value: defaults.Port, + EnvVars: []string{envNames.Port}, + }, } } diff --git a/cmd/gotosocial/letsencryptflags.go b/cmd/gotosocial/letsencryptflags.go index 03495fd1..86079c01 100644 --- a/cmd/gotosocial/letsencryptflags.go +++ b/cmd/gotosocial/letsencryptflags.go @@ -31,6 +31,12 @@ func letsEncryptFlags(flagNames, envNames config.Flags, defaults config.Defaults Value: defaults.LetsEncryptEnabled, EnvVars: []string{envNames.LetsEncryptEnabled}, }, + &cli.IntFlag{ + Name: flagNames.LetsEncryptPort, + Usage: "Port to listen on for letsencrypt certificate challenges. Must not be the same as the GtS webserver/API port.", + Value: defaults.LetsEncryptPort, + EnvVars: []string{envNames.LetsEncryptPort}, + }, &cli.StringFlag{ Name: flagNames.LetsEncryptCertDir, Usage: "Directory to store acquired letsencrypt certificates.", diff --git a/example/config.yaml b/example/config.yaml index 26845e41..873ac873 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -48,10 +48,22 @@ host: "localhost" accountDomain: "" # String. Protocol to use for the server. Only change to http for local testing! +# This should be the protocol part of the URI that your server is actually reachable on. So even if you're +# running GoToSocial behind a reverse proxy that handles SSL certificates for you, instead of using built-in +# letsencrypt, it should still be https. # Options: ["http","https"] # Default: "https" protocol: "https" +# Int. Listen port for the GoToSocial webserver + API. If you're running behind a reverse proxy and/or in a docker, +# container, just set this to whatever you like (or leave the default), and make sure it's forwarded properly. +# If you are running with built-in letsencrypt enabled, and running GoToSocial directly on a host machine, you will +# probably want to set this to 443 (standard https port), unless you have other services already using that port. +# This *MUST NOT* be the same as the letsencrypt port specified below, unless letsencrypt is turned off. +# Examples: [443, 6666, 8080] +# Default: 8080 +port: 8080 + ############################ ##### DATABASE CONFIG ###### ############################ @@ -256,16 +268,21 @@ statuses: letsEncrypt: # Bool. Whether or not letsencrypt should be enabled for the server. - # If true, the server will serve on port 443 (https) and obtain letsencrypt - # certificates automatically. - # If false, the server will serve on port 8080 (http), and the rest of the settings - # here will be ignored. + # If false, the rest of the settings here will be ignored. # You should only change this if you want to serve GoToSocial behind a reverse proxy # like Traefik, HAProxy, or Nginx. # Options: [true, false] # Default: true enabled: true + # Int. Port to listen for letsencrypt certificate challenges on. + # If letsencrypt is enabled, this port must be reachable or you won't be able to obtain certs. + # If letsencrypt is disabled, this port will not be used. + # This *must not* be the same as the webserver/API port specified above. + # Examples: [80, 8000, 1312] + # Default: 80 + port: 80 + # String. Directory in which to store LetsEncrypt certificates. # It is a good move to make this a sub-path within your storage directory, as it makes # backup easier, but you might wish to move them elsewhere if they're also accessed by other services. diff --git a/internal/config/config.go b/internal/config/config.go index 117b8efb..6f943d68 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -50,6 +50,7 @@ type Config struct { Host string `yaml:"host"` AccountDomain string `yaml:"accountDomain"` Protocol string `yaml:"protocol"` + Port int `yaml:"port"` DBConfig *DBConfig `yaml:"db"` TemplateConfig *TemplateConfig `yaml:"template"` AccountsConfig *AccountsConfig `yaml:"accounts"` @@ -150,6 +151,10 @@ func (c *Config) ParseCLIFlags(f KeyedFlags, version string) error { return errors.New("protocol was not set") } + if c.Port == 0 || f.IsSet(fn.Port) { + c.Port = f.Int(fn.Port) + } + // db flags if c.DBConfig.Type == "" || f.IsSet(fn.DbType) { c.DBConfig.Type = f.String(fn.DbType) @@ -262,6 +267,10 @@ func (c *Config) ParseCLIFlags(f KeyedFlags, version string) error { c.LetsEncryptConfig.Enabled = f.Bool(fn.LetsEncryptEnabled) } + if c.LetsEncryptConfig.Port == 0 || f.IsSet(fn.LetsEncryptPort) { + c.LetsEncryptConfig.Port = f.Int(fn.LetsEncryptPort) + } + if c.LetsEncryptConfig.CertDir == "" || f.IsSet(fn.LetsEncryptCertDir) { c.LetsEncryptConfig.CertDir = f.String(fn.LetsEncryptCertDir) } @@ -329,6 +338,7 @@ type Flags struct { Host string AccountDomain string Protocol string + Port string DbType string DbAddress string @@ -366,6 +376,7 @@ type Flags struct { LetsEncryptEnabled string LetsEncryptCertDir string LetsEncryptEmailAddress string + LetsEncryptPort string OIDCEnabled string OIDCIdpName string @@ -384,6 +395,7 @@ type Defaults struct { Host string AccountDomain string Protocol string + Port int SoftwareVersion string DbType string @@ -422,6 +434,7 @@ type Defaults struct { LetsEncryptEnabled bool LetsEncryptCertDir string LetsEncryptEmailAddress string + LetsEncryptPort int OIDCEnabled bool OIDCIdpName string @@ -442,6 +455,7 @@ func GetFlagNames() Flags { Host: "host", AccountDomain: "account-domain", Protocol: "protocol", + Port: "port", DbType: "db-type", DbAddress: "db-address", @@ -477,6 +491,7 @@ func GetFlagNames() Flags { StatusesMaxMediaFiles: "statuses-max-media-files", LetsEncryptEnabled: "letsencrypt-enabled", + LetsEncryptPort: "letsencrypt-port", LetsEncryptCertDir: "letsencrypt-cert-dir", LetsEncryptEmailAddress: "letsencrypt-email", @@ -500,6 +515,7 @@ func GetEnvNames() Flags { Host: "GTS_HOST", AccountDomain: "GTS_ACCOUNT_DOMAIN", Protocol: "GTS_PROTOCOL", + Port: "GTS_PORT", DbType: "GTS_DB_TYPE", DbAddress: "GTS_DB_ADDRESS", @@ -535,6 +551,7 @@ func GetEnvNames() Flags { StatusesMaxMediaFiles: "GTS_STATUSES_MAX_MEDIA_FILES", LetsEncryptEnabled: "GTS_LETSENCRYPT_ENABLED", + LetsEncryptPort: "GTS_LETSENCRYPT_PORT", LetsEncryptCertDir: "GTS_LETSENCRYPT_CERT_DIR", LetsEncryptEmailAddress: "GTS_LETSENCRYPT_EMAIL", diff --git a/internal/config/default.go b/internal/config/default.go index 61940eff..35e9f1ad 100644 --- a/internal/config/default.go +++ b/internal/config/default.go @@ -10,6 +10,7 @@ func TestDefault() *Config { ApplicationName: defaults.ApplicationName, Host: defaults.Host, Protocol: defaults.Protocol, + Port: defaults.Port, SoftwareVersion: defaults.SoftwareVersion, DBConfig: &DBConfig{ Type: defaults.DbType, @@ -51,6 +52,7 @@ func TestDefault() *Config { }, LetsEncryptConfig: &LetsEncryptConfig{ Enabled: defaults.LetsEncryptEnabled, + Port: defaults.LetsEncryptPort, CertDir: defaults.LetsEncryptCertDir, EmailAddress: defaults.LetsEncryptEmailAddress, }, @@ -115,6 +117,7 @@ func Default() *Config { }, LetsEncryptConfig: &LetsEncryptConfig{ Enabled: defaults.LetsEncryptEnabled, + Port: defaults.LetsEncryptPort, CertDir: defaults.LetsEncryptCertDir, EmailAddress: defaults.LetsEncryptEmailAddress, }, @@ -140,6 +143,7 @@ func GetDefaults() Defaults { Host: "", AccountDomain: "", Protocol: "https", + Port: 8080, DbType: "postgres", DbAddress: "localhost", @@ -175,6 +179,7 @@ func GetDefaults() Defaults { StatusesMaxMediaFiles: 6, LetsEncryptEnabled: true, + LetsEncryptPort: 80, LetsEncryptCertDir: "/gotosocial/storage/certs", LetsEncryptEmailAddress: "", @@ -197,6 +202,7 @@ func GetTestDefaults() Defaults { Host: "localhost:8080", AccountDomain: "", Protocol: "http", + Port: 8080, DbType: "postgres", DbAddress: "localhost", @@ -230,6 +236,7 @@ func GetTestDefaults() Defaults { StatusesMaxMediaFiles: 6, LetsEncryptEnabled: false, + LetsEncryptPort: 0, LetsEncryptCertDir: "", LetsEncryptEmailAddress: "", diff --git a/internal/config/letsencrypt.go b/internal/config/letsencrypt.go index ae40cb87..a7117263 100644 --- a/internal/config/letsencrypt.go +++ b/internal/config/letsencrypt.go @@ -3,9 +3,11 @@ package config // LetsEncryptConfig wraps everything needed to manage letsencrypt certificates from within gotosocial. type LetsEncryptConfig struct { // Should letsencrypt certificate fetching be enabled? - Enabled bool + Enabled bool `yaml:"enabled"` + // What port should the server listen for letsencrypt challenges on? + Port int `yaml:"port"` // Where should certificates be stored? - CertDir string + CertDir string `yaml:"certDir"` // Email address to pass to letsencrypt for notifications about certificate expiry etc. - EmailAddress string + EmailAddress string `yaml:"emailAddress"` } diff --git a/internal/router/router.go b/internal/router/router.go index 100e0b38..64d7267b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -68,30 +68,24 @@ func (r *router) AttachStaticFS(relativePath string, fs http.FileSystem) { r.engine.StaticFS(relativePath, fs) } -// Start starts the router nicely. -// -// Different ports and handlers will be served depending on whether letsencrypt is enabled or not. -// If it is enabled, then port 80 will be used for handling LE requests, and port 443 will be used -// for serving actual requests. -// -// If letsencrypt is not being used, then port 8080 only will be used for serving requests. +// Start starts the router nicely. It will serve two handlers if letsencrypt is enabled, and only the web/API handler if letsencrypt is not enabled. func (r *router) Start() { if r.config.LetsEncryptConfig.Enabled { - // serve the http handler on port 80 for receiving letsencrypt requests and solving their devious riddles + // serve the http handler on the selected letsencrypt port, for receiving letsencrypt requests and solving their devious riddles go func() { - if err := http.ListenAndServe(":http", r.certManager.HTTPHandler(http.HandlerFunc(httpsRedirect))); err != nil && err != http.ErrServerClosed { + if err := http.ListenAndServe(fmt.Sprintf(":%d", r.config.LetsEncryptConfig.Port), r.certManager.HTTPHandler(http.HandlerFunc(httpsRedirect))); err != nil && err != http.ErrServerClosed { r.logger.Fatalf("listen: %s", err) } }() - // and serve the actual TLS handler on port 443 + // and serve the actual TLS handler go func() { if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed { r.logger.Fatalf("listen: %s", err) } }() } else { - // no tls required so just serve on port 8080 + // no tls required go func() { if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { r.logger.Fatalf("listen: %s", err) @@ -148,6 +142,7 @@ func New(cfg *config.Config, db db.DB, logger *logrus.Logger) (Router, error) { // create the http server here, passing the gin engine as handler s := &http.Server{ + Addr: fmt.Sprintf(":%d", cfg.Port), Handler: engine, ReadTimeout: readTimeout, WriteTimeout: writeTimeout, @@ -167,12 +162,7 @@ func New(cfg *config.Config, db db.DB, logger *logrus.Logger) (Router, error) { Cache: autocert.DirCache(cfg.LetsEncryptConfig.CertDir), Email: cfg.LetsEncryptConfig.EmailAddress, } - // and create an HTTPS server - s.Addr = ":https" s.TLSConfig = m.TLSConfig() - } else { - // le is NOT enabled, so just serve bare requests on port 8080 - s.Addr = ":8080" } return &router{