Skip to content

Commit

Permalink
feat: fixes to webroot feature and improvements to development using …
Browse files Browse the repository at this point in the history
…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()
  • Loading branch information
fmartingr authored Jan 1, 2025
1 parent d75de89 commit 45bd4d6
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 31 deletions.
5 changes: 0 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
23 changes: 20 additions & 3 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -38,3 +52,6 @@ services:
MYSQL_PASSWORD: shiori
ports:
- "3306:3306"

volumes:
go-mod-cache:
38 changes: 30 additions & 8 deletions docs/Contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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.
4 changes: 4 additions & 0 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
16 changes: 16 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
})
}
30 changes: 15 additions & 15 deletions internal/view/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
24 changes: 24 additions & 0 deletions testdata/nginx.conf
Original file line number Diff line number Diff line change
@@ -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;
}
}
}

0 comments on commit 45bd4d6

Please sign in to comment.