Rustelo/docs/root-path-config.md
Jesús Pérez 98e2d4e783
Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
chore: update docs
2026-02-08 20:12:31 +00:00

8.3 KiB

ROOT_PATH Configuration Guide

This document explains how to use the ROOT_PATH configuration feature to manage absolute and relative paths in your Rust application.

Overview

The ROOT_PATH configuration allows you to:

  • Convert all relative paths in configuration files to absolute paths
  • Set a base directory for your application
  • Deploy your application anywhere without hardcoding paths
  • Maintain consistent path resolution across different environments

Configuration

Setting ROOT_PATH

There are several ways to set the ROOT_PATH:

export ROOT_PATH=/path/to/your/application

2. Configuration File

# config.toml
root_path = "/path/to/your/application"

3. Default Behavior

If not set, ROOT_PATH defaults to the current working directory.

Environment Variable Priority

The ROOT_PATH can be overridden using the ROOT_PATH environment variable:

# Override config file setting
ROOT_PATH=/custom/path ./target/release/server

Path Resolution

How It Works

  1. Absolute Paths: Left unchanged

    • Input: /absolute/path/to/file
    • Output: /absolute/path/to/file
  2. Relative Paths: Resolved against ROOT_PATH

    • ROOT_PATH: /app
    • Input: public/assets
    • Output: /app/public/assets
  3. Current Directory References: Resolved properly

    • ROOT_PATH: /app
    • Input: ./config
    • Output: /app/config
  4. Parent Directory References: Resolved properly

    • ROOT_PATH: /app/server
    • Input: ../shared
    • Output: /app/shared

Affected Configuration Sections

The following configuration sections have their paths resolved:

Static Files

[static]
assets_dir = "public"          # -> /app/public
site_root = "target/site"      # -> /app/target/site
site_pkg_dir = "pkg"           # -> /app/pkg

Server Directories

[server_dirs]
public_dir = "public"          # -> /app/public
uploads_dir = "uploads"        # -> /app/uploads
logs_dir = "logs"              # -> /app/logs
temp_dir = "tmp"               # -> /app/tmp
cache_dir = "cache"            # -> /app/cache
config_dir = "config"          # -> /app/config
data_dir = "data"              # -> /app/data
backup_dir = "backups"         # -> /app/backups

TLS Configuration

[server.tls]
cert_path = "certs/server.crt" # -> /app/certs/server.crt
key_path = "certs/server.key"  # -> /app/certs/server.key

Logging

[logging]
file_path = "logs/app.log"     # -> /app/logs/app.log

Content Directory (if enabled)

[content]
content_dir = "content"        # -> /app/content

Usage Examples

Development Environment

# Set ROOT_PATH to your project directory
export ROOT_PATH=/home/user/my-rust-app
cd /home/user/my-rust-app
cargo run

Production Deployment

# Docker example
FROM rust:latest
WORKDIR /app
COPY . .
ENV ROOT_PATH=/app
ENV ENVIRONMENT=production
RUN cargo build --release
EXPOSE 3030
CMD ["./target/release/server"]

Systemd Service

[Unit]
Description=My Rust Application
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
Environment=ROOT_PATH=/opt/myapp
Environment=ENVIRONMENT=production
ExecStart=/opt/myapp/target/release/server
Restart=always

[Install]
WantedBy=multi-user.target

Directory Structure

ROOT_PATH/
├── config.toml
├── config.dev.toml
├── config.prod.toml
├── target/
│   └── release/
│       └── server
├── public/              # Static assets
├── content/             # Content files
├── uploads/             # User uploads
├── logs/                # Application logs
├── cache/               # Temporary cache
├── data/                # Application data
├── backups/             # Backup files
└── certs/               # TLS certificates
    ├── server.crt
    └── server.key

API Reference

Config Methods

get_absolute_path(relative_path: &str) -> Result<String, ConfigError>

Converts a relative path to an absolute path using the configured ROOT_PATH.

use server::config::Config;

let config = Config::load()?;
let absolute_path = config.get_absolute_path("uploads/images")?;
println!("Absolute path: {}", absolute_path);
// Output: /app/uploads/images

Environment Variables

Variable Description Default
ROOT_PATH Base directory for path resolution Current directory
CONFIG_FILE Explicit path to config file Auto-discovered
ENVIRONMENT Runtime environment development

Migration Guide

Converting Hardcoded Paths

Before (Hardcoded)

// Don't do this
let config_path = "../../../config.toml";
let content_path = "../../content/menu.toml";

After (ROOT_PATH)

// Do this instead
let config = Config::load()?;
let uploads_path = config.get_absolute_path("uploads")?;
let content_path = config.get_absolute_path("content/menu.toml")?;

Content Loading

Before

// Hardcoded relative path
let content = include_str!("../../content/menu.toml");

After

// Dynamic path resolution
use shared::get_content_path;

let menu_path = get_content_path("menu.toml")?;
let content = std::fs::read_to_string(menu_path)?;

Best Practices

1. Use Environment Variables in Production

# Production
export ROOT_PATH=/opt/myapp
export ENVIRONMENT=production
export DATABASE_URL=postgresql://...

2. Keep Config Files Portable

# Use relative paths in config files
[server_dirs]
public_dir = "public"        # Good
# public_dir = "/var/www"    # Avoid hardcoded absolute paths

3. Document Your Directory Structure

# config.toml
# Directory structure:
# ROOT_PATH/
# ├── public/     -> static assets
# ├── uploads/    -> user uploads
# ├── logs/       -> application logs
# └── data/       -> application data

[server_dirs]
public_dir = "public"
uploads_dir = "uploads"
logs_dir = "logs"
data_dir = "data"

4. Use Consistent Naming

# Consistent directory naming
[server_dirs]
public_dir = "public"      # Not "static" or "assets"
uploads_dir = "uploads"    # Not "files" or "media"
logs_dir = "logs"          # Not "log" or "logging"

Troubleshooting

Common Issues

1. Path Not Found

Error: Root path '/invalid/path' does not exist

Solution: Ensure the ROOT_PATH directory exists and is accessible.

2. Permission Denied

Error: Directory creation error: Permission denied

Solution: Check file permissions and ensure the application has write access.

3. Config File Not Found

Error: Configuration file 'config.toml' not found

Solution: Ensure the config file exists in the ROOT_PATH directory.

Debug Commands

# Check current configuration
cargo run --bin config_tool -- show

# Validate configuration
cargo run --bin config_tool -- validate

# Generate new config
cargo run --bin config_tool -- generate dev

Testing

Unit Tests

#[test]
fn test_path_resolution() {
    use std::env;
    
    // Set test ROOT_PATH
    env::set_var("ROOT_PATH", "/tmp/test");
    
    let config = Config::load().unwrap();
    let absolute_path = config.get_absolute_path("uploads").unwrap();
    
    assert!(absolute_path.starts_with("/tmp/test"));
    assert!(absolute_path.ends_with("uploads"));
}

Integration Tests

# Test with different ROOT_PATH values
ROOT_PATH=/tmp/test1 cargo test
ROOT_PATH=/var/tmp/test2 cargo test

Security Considerations

  1. Path Traversal: The system prevents ../ attacks by resolving paths properly
  2. Permissions: Ensure the ROOT_PATH directory has appropriate permissions
  3. Validation: All paths are validated before use
  4. Sandboxing: Consider using chroot or containers for additional security

Performance

  • Path resolution is performed once at startup
  • Resolved paths are cached in the configuration
  • No runtime overhead for path lookups
  • Canonical path resolution may involve filesystem access