allow custom ports for webserver and le (#111)

This commit is contained in:
Tobi Smethurst 2021-07-24 19:02:41 +02:00 committed by GitHub
parent 05e9af089c
commit bc1d8a9265
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 79 additions and 26 deletions

View file

@ -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: On your local machine (not your server), with Go installed, clone the GoToSocial repository, and build the binary with the provided build script:
```bash ```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 ### 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 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 ### 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): 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 ```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. 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 ### 10: Create and confirm your user
You can use the GoToSocial binary to also create, confirm, and promote your user account. You can use the GoToSocial binary to also create, confirm, and promote your user account.

View file

@ -62,5 +62,11 @@ func generalFlags(flagNames, envNames config.Flags, defaults config.Defaults) []
Value: defaults.Protocol, Value: defaults.Protocol,
EnvVars: []string{envNames.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},
},
} }
} }

View file

@ -31,6 +31,12 @@ func letsEncryptFlags(flagNames, envNames config.Flags, defaults config.Defaults
Value: defaults.LetsEncryptEnabled, Value: defaults.LetsEncryptEnabled,
EnvVars: []string{envNames.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{ &cli.StringFlag{
Name: flagNames.LetsEncryptCertDir, Name: flagNames.LetsEncryptCertDir,
Usage: "Directory to store acquired letsencrypt certificates.", Usage: "Directory to store acquired letsencrypt certificates.",

View file

@ -48,10 +48,22 @@ host: "localhost"
accountDomain: "" accountDomain: ""
# String. Protocol to use for the server. Only change to http for local testing! # 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"] # Options: ["http","https"]
# Default: "https" # Default: "https"
protocol: "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 ###### ##### DATABASE CONFIG ######
############################ ############################
@ -256,16 +268,21 @@ statuses:
letsEncrypt: letsEncrypt:
# Bool. Whether or not letsencrypt should be enabled for the server. # Bool. Whether or not letsencrypt should be enabled for the server.
# If true, the server will serve on port 443 (https) and obtain letsencrypt # If false, the rest of the settings here will be ignored.
# certificates automatically.
# If false, the server will serve on port 8080 (http), and the rest of the settings
# here will be ignored.
# You should only change this if you want to serve GoToSocial behind a reverse proxy # You should only change this if you want to serve GoToSocial behind a reverse proxy
# like Traefik, HAProxy, or Nginx. # like Traefik, HAProxy, or Nginx.
# Options: [true, false] # Options: [true, false]
# Default: true # Default: true
enabled: 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. # 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 # 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. # backup easier, but you might wish to move them elsewhere if they're also accessed by other services.

View file

@ -50,6 +50,7 @@ type Config struct {
Host string `yaml:"host"` Host string `yaml:"host"`
AccountDomain string `yaml:"accountDomain"` AccountDomain string `yaml:"accountDomain"`
Protocol string `yaml:"protocol"` Protocol string `yaml:"protocol"`
Port int `yaml:"port"`
DBConfig *DBConfig `yaml:"db"` DBConfig *DBConfig `yaml:"db"`
TemplateConfig *TemplateConfig `yaml:"template"` TemplateConfig *TemplateConfig `yaml:"template"`
AccountsConfig *AccountsConfig `yaml:"accounts"` AccountsConfig *AccountsConfig `yaml:"accounts"`
@ -150,6 +151,10 @@ func (c *Config) ParseCLIFlags(f KeyedFlags, version string) error {
return errors.New("protocol was not set") return errors.New("protocol was not set")
} }
if c.Port == 0 || f.IsSet(fn.Port) {
c.Port = f.Int(fn.Port)
}
// db flags // db flags
if c.DBConfig.Type == "" || f.IsSet(fn.DbType) { if c.DBConfig.Type == "" || f.IsSet(fn.DbType) {
c.DBConfig.Type = f.String(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) 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) { if c.LetsEncryptConfig.CertDir == "" || f.IsSet(fn.LetsEncryptCertDir) {
c.LetsEncryptConfig.CertDir = f.String(fn.LetsEncryptCertDir) c.LetsEncryptConfig.CertDir = f.String(fn.LetsEncryptCertDir)
} }
@ -329,6 +338,7 @@ type Flags struct {
Host string Host string
AccountDomain string AccountDomain string
Protocol string Protocol string
Port string
DbType string DbType string
DbAddress string DbAddress string
@ -366,6 +376,7 @@ type Flags struct {
LetsEncryptEnabled string LetsEncryptEnabled string
LetsEncryptCertDir string LetsEncryptCertDir string
LetsEncryptEmailAddress string LetsEncryptEmailAddress string
LetsEncryptPort string
OIDCEnabled string OIDCEnabled string
OIDCIdpName string OIDCIdpName string
@ -384,6 +395,7 @@ type Defaults struct {
Host string Host string
AccountDomain string AccountDomain string
Protocol string Protocol string
Port int
SoftwareVersion string SoftwareVersion string
DbType string DbType string
@ -422,6 +434,7 @@ type Defaults struct {
LetsEncryptEnabled bool LetsEncryptEnabled bool
LetsEncryptCertDir string LetsEncryptCertDir string
LetsEncryptEmailAddress string LetsEncryptEmailAddress string
LetsEncryptPort int
OIDCEnabled bool OIDCEnabled bool
OIDCIdpName string OIDCIdpName string
@ -442,6 +455,7 @@ func GetFlagNames() Flags {
Host: "host", Host: "host",
AccountDomain: "account-domain", AccountDomain: "account-domain",
Protocol: "protocol", Protocol: "protocol",
Port: "port",
DbType: "db-type", DbType: "db-type",
DbAddress: "db-address", DbAddress: "db-address",
@ -477,6 +491,7 @@ func GetFlagNames() Flags {
StatusesMaxMediaFiles: "statuses-max-media-files", StatusesMaxMediaFiles: "statuses-max-media-files",
LetsEncryptEnabled: "letsencrypt-enabled", LetsEncryptEnabled: "letsencrypt-enabled",
LetsEncryptPort: "letsencrypt-port",
LetsEncryptCertDir: "letsencrypt-cert-dir", LetsEncryptCertDir: "letsencrypt-cert-dir",
LetsEncryptEmailAddress: "letsencrypt-email", LetsEncryptEmailAddress: "letsencrypt-email",
@ -500,6 +515,7 @@ func GetEnvNames() Flags {
Host: "GTS_HOST", Host: "GTS_HOST",
AccountDomain: "GTS_ACCOUNT_DOMAIN", AccountDomain: "GTS_ACCOUNT_DOMAIN",
Protocol: "GTS_PROTOCOL", Protocol: "GTS_PROTOCOL",
Port: "GTS_PORT",
DbType: "GTS_DB_TYPE", DbType: "GTS_DB_TYPE",
DbAddress: "GTS_DB_ADDRESS", DbAddress: "GTS_DB_ADDRESS",
@ -535,6 +551,7 @@ func GetEnvNames() Flags {
StatusesMaxMediaFiles: "GTS_STATUSES_MAX_MEDIA_FILES", StatusesMaxMediaFiles: "GTS_STATUSES_MAX_MEDIA_FILES",
LetsEncryptEnabled: "GTS_LETSENCRYPT_ENABLED", LetsEncryptEnabled: "GTS_LETSENCRYPT_ENABLED",
LetsEncryptPort: "GTS_LETSENCRYPT_PORT",
LetsEncryptCertDir: "GTS_LETSENCRYPT_CERT_DIR", LetsEncryptCertDir: "GTS_LETSENCRYPT_CERT_DIR",
LetsEncryptEmailAddress: "GTS_LETSENCRYPT_EMAIL", LetsEncryptEmailAddress: "GTS_LETSENCRYPT_EMAIL",

View file

@ -10,6 +10,7 @@ func TestDefault() *Config {
ApplicationName: defaults.ApplicationName, ApplicationName: defaults.ApplicationName,
Host: defaults.Host, Host: defaults.Host,
Protocol: defaults.Protocol, Protocol: defaults.Protocol,
Port: defaults.Port,
SoftwareVersion: defaults.SoftwareVersion, SoftwareVersion: defaults.SoftwareVersion,
DBConfig: &DBConfig{ DBConfig: &DBConfig{
Type: defaults.DbType, Type: defaults.DbType,
@ -51,6 +52,7 @@ func TestDefault() *Config {
}, },
LetsEncryptConfig: &LetsEncryptConfig{ LetsEncryptConfig: &LetsEncryptConfig{
Enabled: defaults.LetsEncryptEnabled, Enabled: defaults.LetsEncryptEnabled,
Port: defaults.LetsEncryptPort,
CertDir: defaults.LetsEncryptCertDir, CertDir: defaults.LetsEncryptCertDir,
EmailAddress: defaults.LetsEncryptEmailAddress, EmailAddress: defaults.LetsEncryptEmailAddress,
}, },
@ -115,6 +117,7 @@ func Default() *Config {
}, },
LetsEncryptConfig: &LetsEncryptConfig{ LetsEncryptConfig: &LetsEncryptConfig{
Enabled: defaults.LetsEncryptEnabled, Enabled: defaults.LetsEncryptEnabled,
Port: defaults.LetsEncryptPort,
CertDir: defaults.LetsEncryptCertDir, CertDir: defaults.LetsEncryptCertDir,
EmailAddress: defaults.LetsEncryptEmailAddress, EmailAddress: defaults.LetsEncryptEmailAddress,
}, },
@ -140,6 +143,7 @@ func GetDefaults() Defaults {
Host: "", Host: "",
AccountDomain: "", AccountDomain: "",
Protocol: "https", Protocol: "https",
Port: 8080,
DbType: "postgres", DbType: "postgres",
DbAddress: "localhost", DbAddress: "localhost",
@ -175,6 +179,7 @@ func GetDefaults() Defaults {
StatusesMaxMediaFiles: 6, StatusesMaxMediaFiles: 6,
LetsEncryptEnabled: true, LetsEncryptEnabled: true,
LetsEncryptPort: 80,
LetsEncryptCertDir: "/gotosocial/storage/certs", LetsEncryptCertDir: "/gotosocial/storage/certs",
LetsEncryptEmailAddress: "", LetsEncryptEmailAddress: "",
@ -197,6 +202,7 @@ func GetTestDefaults() Defaults {
Host: "localhost:8080", Host: "localhost:8080",
AccountDomain: "", AccountDomain: "",
Protocol: "http", Protocol: "http",
Port: 8080,
DbType: "postgres", DbType: "postgres",
DbAddress: "localhost", DbAddress: "localhost",
@ -230,6 +236,7 @@ func GetTestDefaults() Defaults {
StatusesMaxMediaFiles: 6, StatusesMaxMediaFiles: 6,
LetsEncryptEnabled: false, LetsEncryptEnabled: false,
LetsEncryptPort: 0,
LetsEncryptCertDir: "", LetsEncryptCertDir: "",
LetsEncryptEmailAddress: "", LetsEncryptEmailAddress: "",

View file

@ -3,9 +3,11 @@
// LetsEncryptConfig wraps everything needed to manage letsencrypt certificates from within gotosocial. // LetsEncryptConfig wraps everything needed to manage letsencrypt certificates from within gotosocial.
type LetsEncryptConfig struct { type LetsEncryptConfig struct {
// Should letsencrypt certificate fetching be enabled? // 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? // Where should certificates be stored?
CertDir string CertDir string `yaml:"certDir"`
// Email address to pass to letsencrypt for notifications about certificate expiry etc. // Email address to pass to letsencrypt for notifications about certificate expiry etc.
EmailAddress string EmailAddress string `yaml:"emailAddress"`
} }

View file

@ -68,30 +68,24 @@ func (r *router) AttachStaticFS(relativePath string, fs http.FileSystem) {
r.engine.StaticFS(relativePath, fs) r.engine.StaticFS(relativePath, fs)
} }
// Start starts the router nicely. // 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.
//
// 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.
func (r *router) Start() { func (r *router) Start() {
if r.config.LetsEncryptConfig.Enabled { 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() { 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) r.logger.Fatalf("listen: %s", err)
} }
}() }()
// and serve the actual TLS handler on port 443 // and serve the actual TLS handler
go func() { go func() {
if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed { if err := r.srv.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err) r.logger.Fatalf("listen: %s", err)
} }
}() }()
} else { } else {
// no tls required so just serve on port 8080 // no tls required
go func() { go func() {
if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := r.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
r.logger.Fatalf("listen: %s", err) 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 // create the http server here, passing the gin engine as handler
s := &http.Server{ s := &http.Server{
Addr: fmt.Sprintf(":%d", cfg.Port),
Handler: engine, Handler: engine,
ReadTimeout: readTimeout, ReadTimeout: readTimeout,
WriteTimeout: writeTimeout, 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), Cache: autocert.DirCache(cfg.LetsEncryptConfig.CertDir),
Email: cfg.LetsEncryptConfig.EmailAddress, Email: cfg.LetsEncryptConfig.EmailAddress,
} }
// and create an HTTPS server
s.Addr = ":https"
s.TLSConfig = m.TLSConfig() s.TLSConfig = m.TLSConfig()
} else {
// le is NOT enabled, so just serve bare requests on port 8080
s.Addr = ":8080"
} }
return &router{ return &router{