updated docs for new feature
This commit is contained in:
388
README.md
388
README.md
@@ -1,65 +1,111 @@
|
||||
# MiauInv - Inventory and Project Management System
|
||||
# MiauInv
|
||||
|
||||
MiauInv is a secure, light-weight inventory, stock, and project allocation tracking system written in Go. It utilizes HTMX for a dynamic, reactive single-page experience over traditional server-rendered HTML blocks, backed by an encrypted JWT and dual-token refresh architecture alongside an embedded SQLite instance.
|
||||
MiauInv is a lightweight inventory, stock, and project allocation management system written in Go. It provides a server-rendered dashboard with HTMX-style page composition, vanilla JavaScript for API interactions, SQLite for persistence, JWT-based sessions, refresh-token rotation, account settings, and optional TOTP-based two-factor authentication.
|
||||
|
||||
## Table of Contents
|
||||
The project is designed for self-hosted/private deployments. It is not a full enterprise asset-management platform, but it already covers the main workflows needed for tracking items, locations, stock distribution, and project allocations.
|
||||
|
||||
* [Technical Specifications](#technical-specifications)
|
||||
* [Architecture Overview](#architecture-overview)
|
||||
* [Detailed Documentation](#detailed-documentation)
|
||||
* [Configuration](#configuration)
|
||||
* [Configuration File (config.yaml)](#configuration-file-configyaml)
|
||||
* [Environment Variables](#environment-variables)
|
||||
* [Route and Endpoint Matrix](#route-and-endpoint-matrix)
|
||||
* [Frontend Web Routes (HTML Views)](#frontend-web-routes-html-views)
|
||||
* [Backend API Endpoints (JSON Serialization)](#backend-api-endpoints-json-serialization)
|
||||
* [Setup and Deployment Tutorial](#setup-and-deployment-tutorial)
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Option 1: Native Local Deployment](#option-1-native-local-deployment)
|
||||
* [Option 2: Docker Deployment (Recommended)](#option-2-docker-deployment-recommended)
|
||||
* [Reverse Proxy Integration with Caddy](#reverse-proxy-integration-with-caddy)
|
||||
* [Images](#images)
|
||||
## Contents
|
||||
|
||||
## Technical Specifications
|
||||
- [Features](#features)
|
||||
- [Current Status](#current-status)
|
||||
- [Technical Stack](#technical-stack)
|
||||
- [Architecture](#architecture)
|
||||
- [Documentation](#documentation)
|
||||
- [Configuration](#configuration)
|
||||
- [Routes and API Endpoints](#routes-and-api-endpoints)
|
||||
- [Setup](#setup)
|
||||
- [Docker Deployment](#docker-deployment)
|
||||
- [Reverse Proxy Deployment](#reverse-proxy-deployment)
|
||||
- [Security Notes](#security-notes)
|
||||
- [Screenshots](#screenshots)
|
||||
|
||||
* **Backend Language:** Go (Golang 1.22+)
|
||||
* **Frontend Interactivity:** HTMX (v2.0.4) & Vanilla JavaScript (API Client integration)
|
||||
* **Database Engine:** SQLite (via standard driver dependencies)
|
||||
* **Security & Session Layer:** JSON Web Tokens (JWT) with HTTP-Only/Secure dual cookie strategy (Access and Refresh Token Rotation)
|
||||
* **Styling Architecture:** Modern dark-theme customized native CSS variables (`--bg`, `--card`, `--accent`, `--border`)
|
||||
* **Transport Security:** Compulsory HTTPS / Native TLS Listener implementation
|
||||
## Features
|
||||
|
||||
---
|
||||
### Inventory and allocation
|
||||
|
||||
## Architecture Overview
|
||||
- Item management with name, category, description, and total quantity.
|
||||
- Location management for physical or logical storage places.
|
||||
- Stock mapping between items and locations.
|
||||
- Project management for allocating items to projects.
|
||||
- Association tracking between projects and item quantities.
|
||||
- Dashboard statistics for items, locations, and projects.
|
||||
|
||||
MiauInv splits responsibility cleanly across modularized architecture packages:
|
||||
### Account and authentication
|
||||
|
||||
* **`main.go`**: Entrypoint initializing components and connecting layers.
|
||||
* **`server/`**: Configures variables, spins up TLS mechanisms, and exposes route endpoints.
|
||||
* **`auth/`**: Custom HTTP Middleware interceptors validating JWT signatures and parsing sub-claims.
|
||||
* **`handlers/`**: Core API Controller actions processing CRUD functions on database entities.
|
||||
* **`storage/`**: Direct abstraction queries interacting with the underlying SQLite database schema.
|
||||
* **`frontend/`**: Serving standard static assets and injecting structural data into components.
|
||||
- User registration, if enabled in the configuration.
|
||||
- Password hashing with bcrypt.
|
||||
- Signed JWT access tokens.
|
||||
- Database-backed refresh tokens with rotation.
|
||||
- HTTP-only secure cookies for access and refresh tokens.
|
||||
- Account settings page at `/profile/settings`.
|
||||
- Username change with password confirmation.
|
||||
- Password change with old-password verification and session refresh.
|
||||
- Avatar placeholder in the account settings UI for a later avatar implementation.
|
||||
|
||||
---
|
||||
### Two-factor authentication
|
||||
|
||||
---
|
||||
- Optional TOTP 2FA using authenticator apps.
|
||||
- QR-code based setup from the account settings page.
|
||||
- Manual setup key fallback if QR scanning is not available.
|
||||
- Two-step login flow for accounts with 2FA enabled.
|
||||
- Recovery codes generated when 2FA is enabled.
|
||||
- Recovery codes are stored only as hashes.
|
||||
- Recovery codes can be downloaded as a text file after generation.
|
||||
- Recovery codes can be regenerated from account settings.
|
||||
- Recovery codes are one-time use.
|
||||
|
||||
## Detailed Documentation
|
||||
## Current Status
|
||||
|
||||
For deep dives into specific subsystems, database layouts, and security mechanisms, please refer to the dedicated documentation files:
|
||||
MiauInv is an active private project. The current version supports core inventory workflows and account-level security settings. Some areas are intentionally still basic:
|
||||
|
||||
* **[Database Schema & Integrity](docs/DATABASE.md):** Comprehensive breakdown of the SQLite table structures, fields, and foreign key relations.
|
||||
* **[Authentication Architecture](docs/AUTHENTICATION.md):** Detailed explanation of the dual-token rotation flow, JWT lifecycle, and frontend loop protection.
|
||||
- Avatar support is currently only represented by a placeholder in the UI.
|
||||
- There is no dedicated admin panel yet.
|
||||
- There is no rate limiting yet for login, 2FA, or recovery-code attempts.
|
||||
- Automated test coverage is still incomplete and should be expanded around authentication, 2FA, recovery codes, and inventory handlers.
|
||||
- The application currently uses native TLS. If deployed behind a reverse proxy, the proxy must connect to the backend over HTTPS or the backend TLS behavior must be adjusted intentionally.
|
||||
|
||||
## Technical Stack
|
||||
|
||||
| Area | Technology |
|
||||
| --- | --- |
|
||||
| Backend | Go 1.26 |
|
||||
| Routing | Go standard library `net/http` |
|
||||
| Database | SQLite via `github.com/glebarez/go-sqlite` |
|
||||
| Authentication | JWT via `github.com/golang-jwt/jwt/v5` |
|
||||
| Password hashing | bcrypt via `golang.org/x/crypto/bcrypt` |
|
||||
| 2FA | TOTP via `github.com/pquerna/otp/totp` |
|
||||
| Frontend | Server-rendered HTML, HTMX-style structure, vanilla JavaScript |
|
||||
| Styling | Custom CSS with dark theme variables |
|
||||
| Deployment | Docker / Docker Compose |
|
||||
|
||||
## Architecture
|
||||
|
||||
The codebase is split into small packages with mostly direct responsibilities:
|
||||
|
||||
| Path | Responsibility |
|
||||
| --- | --- |
|
||||
| `main.go` | Application entrypoint. Initializes configuration, database, and server startup. |
|
||||
| `server/` | HTTP route registration, TLS listener, and server-level configuration. |
|
||||
| `config/` | Runtime configuration file creation and loading. |
|
||||
| `auth/` | JWT generation, JWT validation, middleware, role middleware, and password helpers. |
|
||||
| `handlers/` | JSON API handlers for authentication, account settings, inventory, locations, projects, stock, and associations. |
|
||||
| `storage/` | SQLite schema setup, migrations, and database access helpers. |
|
||||
| `models/` | Shared data structures and constants. |
|
||||
| `frontend/` | HTML template rendering and static asset serving. |
|
||||
| `frontend/assets/js/` | Frontend API client, login flow, token refresh logic, account settings logic, and dashboard actions. |
|
||||
| `frontend/htmx/` | HTML views and dashboard content templates. |
|
||||
|
||||
## Documentation
|
||||
|
||||
More detailed documentation is available in:
|
||||
|
||||
- [Authentication](docs/AUTHENTICATION.md)
|
||||
- [Database](docs/DATABASE.md)
|
||||
- [Testing](docs/TESTING.md)
|
||||
|
||||
## Configuration
|
||||
|
||||
The system uses a combination of a structural JSON configuration file and environment variables for system runtime flags.
|
||||
|
||||
### Configuration File (`config.yaml`)
|
||||
|
||||
The application automatically creates or reads a configuration file named `config.json` in the working directory on startup.
|
||||
MiauInv reads `./appdata/config.yaml`. If the file does not exist, the application creates a default configuration on startup.
|
||||
|
||||
```yaml
|
||||
port: "8080"
|
||||
@@ -69,101 +115,132 @@ private_key_path: ./appdata/key.pem
|
||||
allow_registration: true
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
### Configuration fields
|
||||
|
||||
For cryptographic functions, a mandatory environment variable must be exported before executing the binary:
|
||||
| Field | Description |
|
||||
| --- | --- |
|
||||
| `port` | HTTPS listen port. |
|
||||
| `database_path` | SQLite database path. |
|
||||
| `certificate_path` | TLS certificate path. |
|
||||
| `private_key_path` | TLS private key path. |
|
||||
| `allow_registration` | Enables or disables public registration. If false, `/register` renders a blocked-registration page and `/api/register` is not registered. |
|
||||
|
||||
| Variable | Type | Description | Minimum Requirement |
|
||||
### Environment variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `JWT_SECRET` | Yes | Symmetric signing secret for JWTs. Must be at least 32 characters. |
|
||||
|
||||
Generate a local development secret with:
|
||||
|
||||
```bash
|
||||
openssl rand -base64 48
|
||||
```
|
||||
|
||||
## Routes and API Endpoints
|
||||
|
||||
### Frontend routes
|
||||
|
||||
| Route | Method | Auth required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `JWT_SECRET` | String | Symmetric secret signature key used to sign access tokens | Minimum 32 characters |
|
||||
| `/` | `GET` | No | Landing page. |
|
||||
| `/login` | `GET` | No | Login page. Supports password login and the second 2FA step. |
|
||||
| `/register` | `GET` | No | Registration page or blocked-registration page, depending on configuration. |
|
||||
| `/dashboard` | `GET` | Yes | Dashboard overview. |
|
||||
| `/inventory` | `GET` | Yes | Stock and inventory overview. |
|
||||
| `/items` | `GET` | Yes | Item management view. |
|
||||
| `/locations` | `GET` | Yes | Location management view. |
|
||||
| `/projects` | `GET` | Yes | Project management view. |
|
||||
| `/profile/settings` | `GET` | Yes | Account settings, password changes, 2FA setup, 2FA disable, and recovery-code management. |
|
||||
| `/profile/` | `GET` | No | Placeholder page for unfinished profile subpages. |
|
||||
| `/assets/*` | `GET` | No | Static CSS/JS assets. Minified CSS/JS variants are generated on request. |
|
||||
|
||||
---
|
||||
### Authentication and account API
|
||||
|
||||
## Route and Endpoint Matrix
|
||||
|
||||
All communication with the application happens over defined HTTP transport interfaces. The routes are divided into User-Facing Views (HTML renders) and programmatic Data Hooks (JSON APIs).
|
||||
|
||||
### Frontend Web Routes (HTML Views)
|
||||
|
||||
| Route Path | HTTP Method | Auth Required | Description |
|
||||
| Endpoint | Method | Auth required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `/` | `GET` | No | Root index landing view. |
|
||||
| `/login` | `GET` | No | Renders login page component. |
|
||||
| `/register` | `GET` | No | Registration layout or block alert based on authorization properties. |
|
||||
| `/dashboard` | `GET` | **Yes** | Aggregated stats layout covering items, projects, and locations. |
|
||||
| `/inventory` | `GET` | **Yes** | General overview interface managing stock quantities. |
|
||||
| `/items` | `GET` | **Yes** | Standard component interface targeting primary atomic assets. |
|
||||
| `/locations` | `GET` | **Yes** | Physical or logical facility structures view. |
|
||||
| `/projects` | `GET` | **Yes** | Overview interface listing active construction and logistics operations. |
|
||||
| `/profile/` | `GET` | **Yes** | Component context under development. |
|
||||
| `/assets/*` | `GET` | No | Serves global minified system design files (`.css`, `.js`). |
|
||||
| `/api/register` | `POST` | No | Creates a user if registration is enabled. |
|
||||
| `/api/login` | `POST` | No | Validates username/password. Returns a full session if 2FA is disabled; otherwise returns a short-lived 2FA challenge token. |
|
||||
| `/api/login/2fa` | `POST` | No | Completes login using the 2FA challenge token plus either a TOTP code or a recovery code. |
|
||||
| `/api/refresh` | `POST` | No | Rotates a refresh token. Accepts the token from JSON or the `refresh_token` cookie. |
|
||||
| `/api/logout` | `POST` | Yes | Revokes refresh tokens for the current user and clears auth cookies. |
|
||||
| `/api/profile` | `GET` | Yes | Returns current user metadata, 2FA state, and unused recovery-code count. |
|
||||
| `/api/userinfo` | `GET` | Yes | Same user information handler as `/api/profile`. |
|
||||
| `/api/account/username` | `POST` | Yes | Changes the current username after password confirmation. |
|
||||
| `/api/account/password` | `POST` | Yes | Changes the current password, revokes old refresh tokens, and issues a new session. |
|
||||
| `/api/2fa/setup` | `POST` | Yes | Creates a pending TOTP secret and returns `secret`, `otpauth_url`, and a base64 PNG QR code. |
|
||||
| `/api/2fa/enable` | `POST` | Yes | Enables 2FA after validating a TOTP code. Returns one-time recovery codes. |
|
||||
| `/api/2fa/disable` | `POST` | Yes | Disables 2FA after password and TOTP confirmation. Revokes sessions and clears auth cookies. |
|
||||
| `/api/2fa/recovery-codes/regenerate` | `POST` | Yes | Invalidates existing recovery codes and returns a new set after password and TOTP confirmation. |
|
||||
|
||||
### Backend API Endpoints (JSON Serialization)
|
||||
### Inventory API
|
||||
|
||||
| Endpoint Path | Method | Auth | Query Parameters | Request/Response Behavior |
|
||||
| Endpoint | Method | Auth required | Query parameters | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `/api/register` | `POST` | No | None | Creates a new user record. Requires plain JSON payload containing raw `username` and `password`. Returns status code `201 Created`. |
|
||||
| `/api/login` | `POST` | No | None | Performs credential authentication. Sets `access_token` and `refresh_token` as secure, HTTP-Only cookies, and returns user identity metadata. |
|
||||
| `/api/refresh` | `POST` | No | None | Accepts JSON containing `refresh_token`. Invalidates previous token structures, rotates identities, and hands over a newly active pair. |
|
||||
| `/api/logout` | `POST` | **Yes** | None | Revokes active database-linked refresh session IDs for the user context and drops current browser state tracking. Returns status `204`. |
|
||||
| `/api/profile` | `GET` | **Yes** | `id` *(Optional)* | Returns `id`, `username`, and metadata of either the target parameter or active identity mapped from token signatures. |
|
||||
| `/api/item` | `GET` | **Yes** | `id` *(Optional)* | Empty parameters fetch all available items with aggregated `allocated` and `available` calculations. Providing `id` isolates a specific item. |
|
||||
| `/api/item` | `POST` | **Yes** | None | Inserts a new tracked inventory item schema definition. |
|
||||
| `/api/item` | `PUT` | **Yes** | `id` *(Required)* | Modifies values (`name`, `category`, `description`, `total_quantity`) of an active asset by primary key. |
|
||||
| `/api/item` | `DELETE` | **Yes** | `id` *(Required)* | Removes an entry. SQLite blocks cascade execution if foreign key assignments still exist in stock or project tracking. |
|
||||
| `/api/location` | `GET` | **Yes** | `id`, `content` | Fetching with `id` and `content=true` extracts an array of items grouped at the facility (`item_id`, `name`, `quantity`). Without `content`, returns details or global catalogs. |
|
||||
| `/api/location` | `POST` | **Yes** | None | Instantiates a singular distinct location boundary identifier. |
|
||||
| `/api/location` | `PUT` | **Yes** | `id` *(Required)* | Renames a location while maintaining foreign keys. |
|
||||
| `/api/location` | `DELETE` | **Yes** | `id` *(Required)* | Destroys location configurations if currently cleared of active items. |
|
||||
| `/api/project` | `GET` | **Yes** | `id`, `details` | Providing `id` with `details=true` unrolls associated items allocated to that project context. |
|
||||
| `/api/project` | `POST` | **Yes** | None | Inserts a tracking context entity for targeted hardware allocation. |
|
||||
| `/api/project` | `PUT` | **Yes** | `id` *(Required)* | Updates a project metadata record definition. |
|
||||
| `/api/project` | `DELETE` | **Yes** | `id` *(Required)* | Drops an empty project wrapper. |
|
||||
| `/api/stock` | `GET` | **Yes** | `id` *(Optional)* | Obtains exact relationship matrices between location nodes and items. |
|
||||
| `/api/stock` | `POST` | **Yes** | None | Links allocations across specific site nodes. |
|
||||
| `/api/stock` | `PUT` | **Yes** | `id` *(Required)* | Modifies stock metrics directly on specified maps. |
|
||||
| `/api/stock` | `DELETE` | **Yes** | `id` *(Required)* | Completely severs relationship entry allocations between nodes. |
|
||||
| `/api/association` | `GET` | **Yes** | `id`, `project_id` | Dumps general configuration links, isolated optionally by operational `project_id`. |
|
||||
| `/api/association` | `POST` | **Yes** | None | Allocates an inventory batch to a dedicated project infrastructure requirement. |
|
||||
| `/api/association` | `PUT` | **Yes** | `id` *(Required)* | Alters active quantity indicators inside a specific deployment matrix. |
|
||||
| `/api/association` | `DELETE` | **Yes** | `id` *(Required)* | Frees up allocations, returning tracking variables back to unassigned states. |
|
||||
| `/api/item` | `GET` | Yes | `id` optional | Returns all items with aggregate quantities, or one item by ID. |
|
||||
| `/api/item` | `POST` | Yes | None | Creates an item. |
|
||||
| `/api/item` | `PUT` | Yes | `id` required | Updates item fields. |
|
||||
| `/api/item` | `DELETE` | Yes | `id` required | Deletes an item if no dependent rows block it. |
|
||||
| `/api/location` | `GET` | Yes | `id`, `content` optional | Returns all locations, one location, or location contents with `content=true`. |
|
||||
| `/api/location` | `POST` | Yes | None | Creates a location. |
|
||||
| `/api/location` | `PUT` | Yes | `id` required | Renames a location. |
|
||||
| `/api/location` | `DELETE` | Yes | `id` required | Deletes a location if no dependent rows block it. |
|
||||
| `/api/project` | `GET` | Yes | `id`, `details` optional | Returns all projects, one project, or project allocations with `details=true`. |
|
||||
| `/api/project` | `POST` | Yes | None | Creates a project. |
|
||||
| `/api/project` | `PUT` | Yes | `id` required | Updates a project. |
|
||||
| `/api/project` | `DELETE` | Yes | `id` required | Deletes a project if no dependent rows block it. |
|
||||
| `/api/stock` | `GET` | Yes | `id` optional | Returns stock entries. |
|
||||
| `/api/stock` | `POST` | Yes | None | Creates a stock entry. |
|
||||
| `/api/stock` | `PUT` | Yes | `id` required | Updates a stock entry. |
|
||||
| `/api/stock` | `DELETE` | Yes | `id` required | Deletes a stock entry. |
|
||||
| `/api/association` | `GET` | Yes | `id`, `project_id` optional | Returns project-item associations. |
|
||||
| `/api/association` | `POST` | Yes | None | Allocates item quantity to a project. |
|
||||
| `/api/association` | `PUT` | Yes | `id` required | Updates a project allocation. |
|
||||
| `/api/association` | `DELETE` | Yes | `id` required | Removes a project allocation. |
|
||||
|
||||
---
|
||||
|
||||
## Setup and Deployment Tutorial
|
||||
## Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before deployment, you must generate SSL/TLS certificates since MiauInv enforces native transport encryption layer communication (or use a bought one).
|
||||
- Go 1.26.
|
||||
- SQLite-compatible environment.
|
||||
- OpenSSL or another way to generate TLS certificates for local development.
|
||||
- A `JWT_SECRET` with at least 32 characters.
|
||||
|
||||
### Generate development TLS files
|
||||
|
||||
The server uses `http.ListenAndServeTLS`, so TLS files must exist before startup.
|
||||
|
||||
```bash
|
||||
# Create directory for certs
|
||||
mkdir -p appdata
|
||||
|
||||
# Generate self-signed certificate and private key
|
||||
openssl req -x509 -newkey rsa:4096 -keyout appdata/key.pem -out appdata/cert.pem -sha256 -days 365 -nodes
|
||||
openssl req -x509 -newkey rsa:4096 \
|
||||
-keyout appdata/key.pem \
|
||||
-out appdata/cert.pem \
|
||||
-days 365 \
|
||||
-nodes \
|
||||
-subj "/CN=localhost"
|
||||
```
|
||||
|
||||
### Option 1: Native Local Deployment
|
||||
|
||||
1. Make sure your Go environment path variable properties are populated (Go 1.22+).
|
||||
2. Create your environmental token and execute the initialization routine task:
|
||||
### Native local run
|
||||
|
||||
```bash
|
||||
export JWT_SECRET="your_minimum_thirty_two_char_secret_key_here"
|
||||
go build -o miauinv main.go
|
||||
export JWT_SECRET="replace-this-with-a-random-secret-of-at-least-32-chars"
|
||||
go mod tidy
|
||||
go build -o miauinv .
|
||||
./miauinv
|
||||
```
|
||||
|
||||
---
|
||||
Then open:
|
||||
|
||||
### Option 2: Docker Deployment (Recommended)
|
||||
```text
|
||||
https://localhost:8080
|
||||
```
|
||||
|
||||
MiauInv includes container definition orchestrations to package configurations cleanly, binding storage databases outside running containers into persistent volumes.
|
||||
## Docker Deployment
|
||||
|
||||
#### 1. Create the Docker Compose Descriptor
|
||||
The repository contains a multi-stage Dockerfile. The final image is based on `scratch` and contains the compiled binary plus frontend assets.
|
||||
|
||||
Write the configuration definition mapping layer blocks directly inside a standard file named `docker-compose.yaml`:
|
||||
Example `docker-compose.yaml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -174,59 +251,31 @@ services:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- JWT_SECRET=SECURE_RANDOM_STRING # Must be at least 32 characters long
|
||||
volumes:
|
||||
- ./appdata:/appdata # To edit your configuration files
|
||||
```
|
||||
|
||||
#### 2. Execution Commands
|
||||
|
||||
To bring up your background container image instance pipelines, execute the compose environment controls:
|
||||
|
||||
```bash
|
||||
# Build and execute the container in background detached mode
|
||||
docker-compose up --build -d
|
||||
|
||||
# Verify container operation statuses
|
||||
docker-compose ps
|
||||
|
||||
# Monitor execution system logs
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
Once running successfully via Docker orchestration loops, navigate your web browser context safely to `https://localhost:8080` to interact with your MiauInv control panel workspace.
|
||||
|
||||
## Reverse Proxy Integration with Caddy
|
||||
|
||||
If you deploy MiauInv behind a global Caddy server, Caddy must act as an HTTPS reverse proxy. Since the MiauInv binary enforces native TLS transport, Caddy needs to be configured to establish a secure backend connection and bypass verification for self-signed backend certificates.
|
||||
|
||||
### 1. Docker Compose Network Configuration
|
||||
Ensure your MiauInv container shares an external network with your Caddy container (e.g., a network named `proxy`). The container does not need to expose public ports since Caddy communicates with it internally over port `8080`.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
miauinv:
|
||||
image: git.miaurizius.de/miaurizius/miauinv:latest
|
||||
container_name: MiauInv
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
environment:
|
||||
- JWT_SECRET=SECURE_RANDOM_STRING
|
||||
- JWT_SECRET=replace-this-with-a-random-secret-of-at-least-32-chars
|
||||
volumes:
|
||||
- ./appdata:/appdata
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
```
|
||||
|
||||
### 2. Caddyfile Configuration
|
||||
Start the container:
|
||||
|
||||
Add the following block to your server's `Caddyfile`. The `https://` prefix forces Caddy to use TLS for the backend connection, and `tls_insecure_skip_verify` allows the proxy to accept the internal self-signed certificate generated during the prerequisites step.
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
## Reverse Proxy Deployment
|
||||
|
||||
MiauInv currently listens with native TLS. If it is deployed behind Caddy or another reverse proxy, the proxy must connect to the backend using HTTPS unless the server code is changed to listen without TLS.
|
||||
|
||||
Example Caddy configuration with a self-signed backend certificate:
|
||||
|
||||
```caddy
|
||||
inv.yourdomain.com {
|
||||
inv.example.com {
|
||||
encode zstd gzip
|
||||
|
||||
reverse_proxy https://miauinv:8080 {
|
||||
@@ -238,20 +287,27 @@ inv.yourdomain.com {
|
||||
header {
|
||||
X-Content-Type-Options nosniff
|
||||
Referrer-Policy strict-origin-when-cross-origin
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Apply Configuration
|
||||
For Docker deployments, place Caddy and MiauInv on the same Docker network and reverse proxy to the service name.
|
||||
|
||||
Reload your Caddy instance to apply the reverse proxy routing rules:
|
||||
## Security Notes
|
||||
|
||||
```bash
|
||||
docker compose exec -w /etc/caddy caddy caddy reload
|
||||
```
|
||||
- JWTs are signed, not encrypted. Do not put secrets into JWT claims.
|
||||
- `JWT_SECRET` must be random and private.
|
||||
- Access tokens expire after 15 minutes.
|
||||
- Refresh tokens expire after 7 days and are rotated on refresh.
|
||||
- Refresh tokens and recovery codes are stored in the database as hashes.
|
||||
- TOTP secrets are currently stored in the database because the server must validate codes. Protect the database file accordingly.
|
||||
- Recovery codes are only shown when generated. Users should download or copy them immediately.
|
||||
- 2FA disable and recovery-code regeneration require both the current password and a valid TOTP code.
|
||||
- The project should add rate limiting before being exposed to untrusted public traffic.
|
||||
- The project should add more automated tests around login, 2FA, recovery codes, and account settings before being considered production-ready.
|
||||
|
||||
## Screenshots
|
||||
|
||||
## Images
|
||||
#### Dashboard
|
||||
<img src="docs/img/dashboard.png">
|
||||
|
||||
|
||||
Reference in New Issue
Block a user