feat: fixes to webroot feature and improvements to development using it (#1046)

* feat: Add nginx service to test shiori webroot configuration

chore: Update nginx configuration to resolve 502 gateway error

fix: Update SHIORI_WEBROOT to SHIORI_HTTP_ROOT_PATH in docker-compose

feat: Add debug log level flag to shiori service

refactor: Update docker-compose with simplified command and log configuration

fix: Change nginx port mapping from 80 to 8081

feat: Add volume for Go module cache in docker-compose

style: Add type attribute to script tags in index.html

feat: Update import statements to use RootPath variable in index.html

* docs: Update contribution guide with server and docker instructions

* docs: Add Docker and nginx documentation for local development

* test: IsValid()
This commit is contained in:
Felipe Martin 2025-01-01 16:22:30 +01:00 committed by GitHub
parent d75de89701
commit 45bd4d693f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 125 additions and 31 deletions

View file

@ -57,11 +57,6 @@ help:
clean:
rm -rf dist
## Runs the legacy http API for local development
.PHONY: serve
serve:
SHIORI_DEVELOPMENT=$(SHIORI_DEVELOPMENT) SHIORI_DIR=$(SHIORI_DIR) go run main.go serve
## Runs server for local development
.PHONY: run-server
run-server:

View file

@ -1,25 +1,39 @@
# Docker compose for development purposes only.
# Edit it to fit your current development needs.
version: "3"
services:
shiori:
build:
context: .
dockerfile: Dockerfile.compose
container_name: shiori
command:
- "server"
- "--log-level"
- "debug"
ports:
- "8080:8080"
volumes:
- "./dev-data:/srv/shiori"
- ".:/src/shiori"
- "go-mod-cache:/go/pkg/mod"
restart: unless-stopped
links:
- "postgres"
- "mariadb"
environment:
SHIORI_DIR: /srv/shiori
#SHIORI_DATABASE_URL: mysql://shiori:shiori@(mariadb)/shiori?charset=utf8mb4
SHIORI_DATABASE_URL: postgres://shiori:shiori@postgres/shiori?sslmode=disable
# SHIORI_HTTP_ROOT_PATH: /shiori/
# SHIORI_DATABASE_URL: mysql://shiori:shiori@(mariadb)/shiori?charset=utf8mb4
# SHIORI_DATABASE_URL: postgres://shiori:shiori@postgres/shiori?sslmode=disable
nginx:
image: nginx:alpine
ports:
- "8081:8081"
volumes:
- "./testdata/nginx.conf:/etc/nginx/nginx.conf:ro"
depends_on:
- shiori
postgres:
image: postgres:15
@ -38,3 +52,6 @@ services:
MYSQL_PASSWORD: shiori
ports:
- "3306:3306"
volumes:
go-mod-cache:

View file

@ -9,18 +9,10 @@
To run the current development server with the defaults you can run the following command:
```bash
make serve
```
If you want to run the refactored server, you can run the following command:
```bash
make run-server
```
> ** Note:** For more information into what the _refactored server_ means, please check this issue: https://github.com/go-shiori/shiori/issues/640
## Updating the API documentation
> ** Note:** This only applies for the Rest API documentation under the `internal/http` folder, **not** the one under `internal/webserver`.
@ -94,3 +86,33 @@ mkdocs serve
This will start a local server at `http://127.0.0.1:8000` where you can preview your changes in real-time.
Documentation for production is generated automatically on every release and published using github pages.
## Running the server with docker
To run the development server using Docker, you can use the provided `docker-compose.yaml` file which includes both PostgreSQL and MariaDB databases:
```bash
docker compose up shiori
```
This will start the Shiori server on port 8080 with hot-reload enabled. Any changes you make to the code will automatically rebuild and restart the server.
By default, it uses SQLite mounting the local `dev-data` folder in the source code path. To use MariaDB or PostgreSQL instead, uncomment the `SHIORI_DATABASE_URL` line for the appropriate engine in the `docker-compose.yaml` file.
## Running the server using an nginx reverse proxy and a custom webroot
To test Shiori behind an nginx reverse proxy with a custom webroot (e.g., `/shiori/`), you can use the provided nginx configuration:
1. First, ensure the `SHIORI_HTTP_ROOT_PATH` environment variable is uncommented in `docker-compose.yaml`:
```yaml
SHIORI_HTTP_ROOT_PATH: /shiori/
```
2. Then start both Shiori and nginx services:
```bash
docker compose up shiori nginx
```
This will start the shiori service along with nginx. You can access Shiori using [http://localhost:8081/shiori](http://localhost:8081/shiori).
The nginx configuration in `testdata/nginx.conf` handles all the necessary configuration.

View file

@ -80,6 +80,10 @@ func initShiori(ctx context.Context, cmd *cobra.Command) (*config.Config, *depen
cfg.SetDefaults(logger, portableMode)
if err := cfg.IsValid(); err != nil {
logger.WithError(err).Fatal("invalid configuration detected")
}
err := os.MkdirAll(cfg.Storage.DataDir, model.DataDirPerm)
if err != nil {
logger.WithError(err).Fatal("error creating data directory")

View file

@ -79,6 +79,14 @@ func (c *HttpConfig) SetDefaults(logger *logrus.Logger) {
}
}
func (c *HttpConfig) IsValid() error {
if !strings.HasSuffix(c.RootPath, "/") {
return fmt.Errorf("root path should end with a slash")
}
return nil
}
type DatabaseConfig struct {
DBMS string `env:"DBMS"` // Deprecated
// DBMS requires more environment variables. Check the database package for more information.
@ -140,6 +148,14 @@ func (c *Config) DebugConfiguration(logger *logrus.Logger) {
logger.Debugf(" SHIORI_HTTP_DISABLE_PARSE_MULTIPART_FORM: %t", c.Http.DisablePreParseMultipartForm)
}
func (c *Config) IsValid() error {
if err := c.Http.IsValid(); err != nil {
return fmt.Errorf("http configuration is invalid: %w", err)
}
return nil
}
// ParseServerConfiguration parses the configuration from the enabled lookupers
func ParseServerConfiguration(ctx context.Context, logger *logrus.Logger) *Config {
var cfg Config

View file

@ -101,3 +101,19 @@ func TestConfigSetDefaults(t *testing.T) {
require.NotEmpty(t, cfg.Storage.DataDir)
require.NotEmpty(t, cfg.Database.URL)
}
func TestConfigIsValid(t *testing.T) {
log := logrus.New()
t.Run("valid configuration", func(t *testing.T) {
cfg := ParseServerConfiguration(context.TODO(), log)
cfg.SetDefaults(log, false)
require.NoError(t, cfg.IsValid())
})
t.Run("invalid http root path", func(t *testing.T) {
cfg := ParseServerConfiguration(context.TODO(), log)
cfg.Http.RootPath = "/invalid"
require.Error(t, cfg.IsValid())
})
}

View file

@ -16,27 +16,27 @@
<link href="assets/css/style.css" rel="stylesheet">
<script src="assets/js/vue.min.js"></script>
<script src="assets/js/url.min.js"></script>
<script src="assets/js/vue.min.js" type="text/javascript"></script>
<script src="assets/js/url.min.js" type="text/javascript"></script>
</head>
<body>
<div id="app">
<login-view v-if="isLoggedIn === false && loginRequired" @login-success="onLoginSuccess"></login-view>
<div id="main-scene" v-else-if="isLoggedIn === true">
<div id="main-sidebar">
<a v-for="item in sidebarItems" :title="item.title" :class="{active: activePage === item.page}" @click="switchPage(item.page)">
<i class="fas fa-fw" :class="item.icon"></i>
</a>
<div class="spacer"></div>
<a title="Logout" @click="logout">
<i class="fas fa-fw fa-sign-out-alt"></i>
</a>
</div>
<keep-alive>
<component :is="activePage" :active-account="activeAccount" :app-options="appOptions" @setting-changed="saveSetting"></component>
</keep-alive>
<custom-dialog v-bind="dialog" />
<div id="main-sidebar">
<a v-for="item in sidebarItems" :title="item.title" :class="{active: activePage === item.page}" @click="switchPage(item.page)">
<i class="fas fa-fw" :class="item.icon"></i>
</a>
<div class="spacer"></div>
<a title="Logout" @click="logout">
<i class="fas fa-fw fa-sign-out-alt"></i>
</a>
</div>
<keep-alive>
<component :is="activePage" :active-account="activeAccount" :app-options="appOptions" @setting-changed="saveSetting"></component>
</keep-alive>
<custom-dialog v-bind="dialog"></custom-dialog>
</div>
</div>

24
testdata/nginx.conf vendored Normal file
View file

@ -0,0 +1,24 @@
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 8081;
server_name localhost;
location /shiori/ {
proxy_pass http://shiori:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
}
}
}