Compare commits

...

8 Commits

Author SHA1 Message Date
Daniel Luiz Alves
9afe8292fa v3.0.0-beta.2 (#62) 2025-06-17 23:43:12 -03:00
Daniel Luiz Alves
e15f50a8a8 fix(docker): Implement bind mount compose (#61) 2025-06-17 23:31:06 -03:00
Daniel Luiz Alves
8affdc8f95 (fix) Share download (#58) 2025-06-17 23:27:38 -03:00
Daniel Luiz Alves
281eff0f14 chore: update Dockerfile and supervisord configuration for improved logging
- Modified the Dockerfile to streamline the creation of the supervisor configuration directory.
- Updated `infra/supervisord.conf` to redirect logs to stdout and stderr, enhancing log management and visibility.
- Removed specific log file paths and sizes to simplify logging setup.
2025-06-17 23:23:36 -03:00
Daniel Luiz Alves
b28f1f97c4 Refactor Dockerfile to use external supervisord configuration file
- Replaced inline supervisor configuration in Dockerfile with a separate `infra/supervisord.conf` file for better organization and maintainability.
- Ensured the new configuration retains all previous settings for the server and web programs.
2025-06-17 23:14:40 -03:00
Daniel Luiz Alves
c5660b3c6b feat: Enhance Docker setup and documentation for Palmr.
- Added a new `docker-compose-bind-mount-example.yaml` for easier bind mount configuration.
- Updated `.gitignore` to include the `data/` directory for persistent storage.
- Modified `docker-compose.yaml` to clarify volume paths and improve comments.
- Enhanced `Dockerfile` to support flexible UID/GID configuration and ensure proper directory permissions.
- Updated environment variable handling in `server-start.sh` and Prisma configuration for better database management.
- Revised documentation in `quick-start.mdx` and `uid-gid-configuration.mdx` to reflect new features and best practices for deployment.
2025-06-17 22:46:28 -03:00
Charly Gley
e64f718998 fix: change error and success messages 2025-06-17 19:59:27 +02:00
Charly Gley
f00a9dadd0 fix: make download on shares work 2025-06-17 19:55:23 +02:00
12 changed files with 456 additions and 353 deletions

3
.gitignore vendored
View File

@@ -29,4 +29,5 @@ apps/server/.env
apps/server/dist/*
#DEFAULT
.env
.env
data/

View File

@@ -1,10 +1,11 @@
FROM node:20-alpine AS base
# Install system dependencies (removed netcat-openbsd since we no longer need to wait for PostgreSQL)
# Install system dependencies
RUN apk add --no-cache \
gcompat \
supervisor \
curl
curl \
su-exec
# Enable pnpm
RUN corepack enable pnpm
@@ -80,15 +81,12 @@ ARG PALMR_GID=1001
RUN addgroup --system --gid ${PALMR_GID} nodejs
RUN adduser --system --uid ${PALMR_UID} --ingroup nodejs palmr
# Create application directories and set permissions
# Include storage directories for filesystem mode and SQLite database directory
RUN mkdir -p /app/server /app/web /home/palmr/.npm /home/palmr/.cache \
/app/server/uploads /app/server/temp-chunks /app/server/uploads/logo \
/app/server/prisma
# Create application directories
RUN mkdir -p /app/palmr-app /app/web /home/palmr/.npm /home/palmr/.cache
RUN chown -R palmr:nodejs /app /home/palmr
# === Copy Server Files ===
WORKDIR /app/server
# === Copy Server Files to /app/palmr-app (separate from /app/server for bind mounts) ===
WORKDIR /app/palmr-app
# Copy server production files
COPY --from=server-builder --chown=palmr:nodejs /app/server/dist ./dist
@@ -101,8 +99,9 @@ COPY --from=server-builder --chown=palmr:nodejs /app/server/reset-password.sh ./
COPY --from=server-builder --chown=palmr:nodejs /app/server/src/scripts/ ./src/scripts/
RUN chmod +x ./reset-password.sh
# Ensure storage directories have correct permissions
RUN chown -R palmr:nodejs /app/server/uploads /app/server/temp-chunks /app/server/prisma
# Copy seed file to the shared location for bind mounts
RUN mkdir -p /app/server/prisma
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma/seed.js /app/server/prisma/seed.js
# === Copy Web Files ===
WORKDIR /app/web
@@ -116,46 +115,17 @@ COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/static ./.next/stati
WORKDIR /app
# Create supervisor configuration
RUN mkdir -p /etc/supervisor/conf.d /var/log/supervisor
RUN mkdir -p /etc/supervisor/conf.d
# Copy server start script
COPY infra/server-start.sh /app/server-start.sh
RUN chmod +x /app/server-start.sh
RUN chown palmr:nodejs /app/server-start.sh
# Copy supervisor configuration (simplified without PostgreSQL dependency)
COPY <<EOF /etc/supervisor/conf.d/supervisord.conf
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
# Copy supervisor configuration
COPY infra/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
[program:server]
command=/app/server-start.sh
directory=/app/server
user=palmr
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/server.err.log
stdout_logfile=/var/log/supervisor/server.out.log
environment=PORT=3333,HOME="/home/palmr"
priority=100
[program:web]
command=/bin/sh -c 'echo "Waiting for API to be ready..."; while ! curl -f http://127.0.0.1:3333/health >/dev/null 2>&1; do echo "API not ready, waiting..."; sleep 2; done; echo "API is ready! Starting frontend..."; exec node server.js'
directory=/app/web
user=palmr
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/web.err.log
stdout_logfile=/var/log/supervisor/web.out.log
environment=PORT=5487,HOSTNAME="0.0.0.0",HOME="/home/palmr",API_BASE_URL="http://127.0.0.1:3333"
priority=200
startsecs=10
EOF
# Create main startup script with UID/GID runtime support
# Create main startup script
COPY <<EOF /app/start.sh
#!/bin/sh
set -e
@@ -164,56 +134,15 @@ echo "Starting Palmr Application..."
echo "Storage Mode: \${ENABLE_S3:-false}"
echo "Database: SQLite"
# Runtime UID/GID configuration - only apply if environment variables are set
if [ -n "\${PALMR_UID}" ] || [ -n "\${PALMR_GID}" ]; then
RUNTIME_UID=\${PALMR_UID:-${PALMR_UID}}
RUNTIME_GID=\${PALMR_GID:-${PALMR_GID}}
echo "Runtime UID/GID configuration detected: UID=\$RUNTIME_UID, GID=\$RUNTIME_GID"
# Get current user/group IDs
CURRENT_UID=\$(id -u palmr 2>/dev/null || echo "${PALMR_UID}")
CURRENT_GID=\$(id -g palmr 2>/dev/null || echo "${PALMR_GID}")
# Only modify if different from current
if [ "\$CURRENT_UID" != "\$RUNTIME_UID" ] || [ "\$CURRENT_GID" != "\$RUNTIME_GID" ]; then
echo "Adjusting user/group IDs from \$CURRENT_UID:\$CURRENT_GID to \$RUNTIME_UID:\$RUNTIME_GID"
# Modify group if needed
if [ "\$CURRENT_GID" != "\$RUNTIME_GID" ]; then
if getent group \$RUNTIME_GID >/dev/null 2>&1; then
EXISTING_GROUP=\$(getent group \$RUNTIME_GID | cut -d: -f1)
echo "Using existing group with GID \$RUNTIME_GID: \$EXISTING_GROUP"
usermod -g \$EXISTING_GROUP palmr 2>/dev/null || echo "Warning: Could not change user group"
else
groupmod -g \$RUNTIME_GID nodejs 2>/dev/null || echo "Warning: Could not modify group GID"
fi
fi
# Modify user if needed
if [ "\$CURRENT_UID" != "\$RUNTIME_UID" ]; then
if getent passwd \$RUNTIME_UID >/dev/null 2>&1; then
EXISTING_USER=\$(getent passwd \$RUNTIME_UID | cut -d: -f1)
echo "Warning: UID \$RUNTIME_UID already exists as user '\$EXISTING_USER'"
echo "Container will continue but may have permission issues"
else
usermod -u \$RUNTIME_UID palmr 2>/dev/null || echo "Warning: Could not modify user UID"
fi
fi
# Update file ownership for application directories
echo "Updating file ownership for application directories..."
chown -R palmr:nodejs /app /home/palmr 2>/dev/null || echo "Warning: Could not update all file ownership"
else
echo "Runtime UID/GID matches current values, no changes needed"
fi
else
echo "No runtime UID/GID configuration provided, using defaults"
fi
# Set global environment variables
export DATABASE_URL="file:/app/server/prisma/palmr.db"
export UPLOAD_PATH="/app/server/uploads"
export TEMP_CHUNKS_PATH="/app/server/temp-chunks"
# Ensure storage directories exist with correct permissions
# Ensure /app/server directory exists for bind mounts
mkdir -p /app/server/uploads /app/server/temp-chunks /app/server/uploads/logo /app/server/prisma
chown -R palmr:nodejs /app/server/uploads /app/server/temp-chunks /app/server/prisma 2>/dev/null || echo "Warning: Could not set permissions on storage directories"
echo "Data directories ready for first run..."
# Start supervisor
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
@@ -221,8 +150,8 @@ EOF
RUN chmod +x /app/start.sh
# Create volume mount points for persistent storage (filesystem mode and SQLite database)
VOLUME ["/app/server/uploads", "/app/server/temp-chunks", "/app/server/prisma"]
# Create volume mount points for bind mounts
VOLUME ["/app/server"]
# Expose ports
EXPOSE 3333 5487
@@ -232,4 +161,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:5487 || exit 1
# Start application
CMD ["/app/start.sh"]
CMD ["/app/start.sh"]

View File

@@ -3,32 +3,50 @@ title: Quick Start (Docker)
icon: "Rocket"
---
Hey there! Welcome to the fastest way to launch <span className="font-bold">Palmr.</span>, your very own secure <span className="font-bold italic">file sharing solution</span>. Whether you're a first-timer to <span className="font-bold italic">self-hosting</span> or a tech wizard, we've made this process incredibly straightforward. In just a few minutes, you'll have a sleek, user-friendly <span className="font-bold italic">file sharing platform</span> running on your <span className="font-bold italic">server</span> or <span className="font-bold italic">VPS</span>.
Welcome to the fastest way to deploy <span className="font-bold">Palmr.</span> - your secure, self-hosted file sharing solution. This guide will have you up and running in minutes, whether you're new to self-hosting or an experienced developer.
This guide is all about speed and simplicity, using our built-in <span className="font-bold italic">file storage system</span> ideal for most users. While Palmr. supports advanced setups like <span className="font-bold italic">manual installation</span> or <span className="font-bold italic">Amazon S3-compatible external storage</span>, we're focusing on the easiest path with <span className="font-bold italic">Docker Compose</span>. Curious about other options? Check out the dedicated sections in our docs for those advanced configurations.
Palmr. offers flexible deployment options to match your infrastructure needs. This guide focuses on Docker deployment with our recommended filesystem storage, perfect for most use cases.
Let's dive in and get Palmr. up and running!
## Prerequisites
## What you'll need
Ensure you have the following installed on your system:
To get started, you only need two tools installed on your system. Don't worry, they're easy to set up:
- **Docker** - Container runtime ([installation guide](https://docs.docker.com/get-docker/))
- **Docker Compose** - Multi-container orchestration ([installation guide](https://docs.docker.com/compose/install/))
- **Docker** ([https://docs.docker.com](https://docs.docker.com/)) - This will run Palmr. in a container.
- **Docker Compose** ([https://docs.docker.com/compose](https://docs.docker.com/compose/)) - This helps manage the setup with a simple configuration file.
> **Platform Support**: Palmr. is developed on macOS and extensively tested on Linux servers. While we haven't formally tested other platforms, Docker's cross-platform nature should ensure compatibility. Report any issues on our [GitHub repository](https://github.com/kyantech/Palmr/issues).
> **Note**: Palmr. was developed on **MacOS** and thoroughly tested on **Linux servers**, ensuring top-notch performance on these platforms. We haven't tested on **Windows** or other environments yet, so there might be some hiccups. Since we're still in **beta**, bugs can pop up anywhere. If you spot an issue, we'd love your help please report it on our GitHub [issues page](https://github.com/kyantech/Palmr/issues).
## Storage Options
## Setting up with Docker Compose
Palmr. supports two storage approaches for persistent data:
Docker Compose is the simplest way to deploy Palmr. across different environments. Once you've got Docker and Docker Compose installed, you're ready to roll with our streamlined setup.
### Named Volumes (Recommended)
In the root folder of the Palmr. project, you'll find a few compose files. For this guide, we're using `docker-compose.yaml` the only file you need to run Palmr. with file system storage. No need to build anything yourself; our pre-built images are hosted on [DockerHub](https://hub.docker.com/repositories/kyantech) and referenced in this file.
**Best for**: Production environments, automated deployments
You can tweak settings directly in `docker-compose.yaml` or use environment variables (more on that later). Let's take a closer look at what's inside this file.
- ✅ **Managed by Docker**: No permission issues or manual path management
- ✅ **Optimized Performance**: Docker-native storage optimization
- ✅ **Cross-platform**: Consistent behavior across operating systems
- ✅ **Simplified Backups**: Docker volume commands for backup/restore
## Exploring the docker-compose.yaml file
### Bind Mounts
Here's the full content of our `docker-compose.yaml`. Feel free to copy it from here or grab it from our official repository ([Docker Compose](https://github.com/kyantech/Palmr/blob/main/docker-compose.yaml)).
**Best for**: Development, direct file access requirements
- ✅ **Direct Access**: Files stored in local directory you specify
- ✅ **Transparent Storage**: Direct filesystem access from host
- ✅ **Custom Backup**: Use existing file system backup solutions
- ⚠️ **Permission Considerations**: May require user/group configuration
---
## Option 1: Named Volumes (Recommended)
Named volumes provide the best performance and are managed entirely by Docker.
### Configuration
Use the provided `docker-compose.yaml` for named volumes:
```yaml
services:
@@ -39,103 +57,112 @@ services:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars # CHANGE THIS KEY FOR SECURITY
ports:
- "5487:5487" # Web port
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY, IF YOU DONT WANT TO EXPOSE THE API, JUST REMOVE THIS LINE )
- "5487:5487" # Web interface
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
volumes:
- palmr_data:/app/server # Volume for the application data
- palmr_data:/app/server # Named volume for the application data
restart: unless-stopped # Restart the container unless it is stopped
volumes:
palmr_data:
```
We've added helpful comments in the file to guide you through customization. Let's break down what you can adjust to fit your setup.
---
### Understanding the services
Palmr. runs as a single service in this filesystem storage setup. Here's a quick overview:
| **Service** | **Image** | **Exposed Ports** | **Main Features** |
| ----------- | ---------------------------------------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| palmr | [kyantech/palmr:latest](https://hub.docker.com/repository/docker/kyantech/palmr/general) | **3333** (API)<br/>**5487** (Web) | • Combined backend API and frontend service<br/>• Uses local filesystem storage<br/>• Has healthcheck to ensure availability |
---
### Customizing with environment variables
You can fine-tune Palmr. using environment variables. Here's what's available for the filesystem storage setup:
| **Variable** | **Default Value** | **Description** |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------ |
| `ENABLE_S3` | false | Set to 'false' for filesystem storage or 'true' for S3/MinIO |
| `ENCRYPTION_KEY` | change-this-key-in-production-min-32-chars | Required for filesystem encryption (minimum 32 characters) |
> **Important**: These variables can be set in a `.env` file at the project root or directly in your environment when running Docker Compose. The `ENCRYPTION_KEY` is crucial for securing your filesystem storage **always change it** to a unique, secure value in production. you can generate a secure key using the [KeyGenerator](/docs/3.0-beta/quick-start#generating-a-secure-encryption-key) tool.
---
### Managing persistent data
To ensure your data sticks around even if the container restarts, we use a persistent volume:
| **Volume** | **Description** |
| ------------ | ------------------------------------- |
| `palmr_data` | Stores all the data of Palmr. service |
---
## Launching Palmr.
With your `docker-compose.yaml` ready, it's time to start Palmr.! Run this command to launch everything in the background:
### Deployment
```bash
docker-compose up -d
```
This runs Palmr. in **detached mode**, meaning it operates silently in the background without flooding your terminal with logs.
Now, open your browser and visit:
```bash
http://localhost:5487
```
If you're on a server, replace `localhost` with your server's IP:
```bash
http://[YOUR_SERVER_IP]:5487
```
For example, if your server IP is `192.168.1.10`, the URL would be `http://192.168.1.10:5487`. Remember, this is just an example use your actual server IP.
> **Pro Tip**: For full functionality and security, configure your server with **HTTPS** by setting up a valid SSL certificate.
---
## Keeping Palmr. up to date
## Option 2: Bind Mounts
Want the latest features and fixes? Updating Palmr. is a breeze. Run these commands to pull the newest version from DockerHub and restart the service:
Bind mounts store data in a local directory, providing direct file system access.
### Configuration
To use bind mounts, **replace the content** of your `docker-compose.yaml` with the following configuration (you can also reference `docker-compose-bind-mount-example.yaml` as a template):
```yaml
services:
palmr:
image: kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars # CHANGE THIS KEY FOR SECURITY
# Optional: Set custom UID/GID for file permissions
# - PALMR_UID=1000
# - PALMR_GID=1000
ports:
- "5487:5487" # Web port
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
volumes:
# Bind mount for persistent data (uploads, database, temp files)
- ./data:/app/server # Local directory for the application data
restart: unless-stopped # Restart the container unless it is stopped
```
### Deployment
```bash
docker-compose pull
docker-compose up -d
```
That's it! You're now running the latest version of Palmr.
> **Permission Configuration**: If you encounter permission issues with bind mounts (common on NAS systems), see our [UID/GID Configuration](/docs/3.0-beta/uid-gid-configuration) guide for automatic permission handling.
---
## Running with Docker (without Compose)
## Environment Variables
Prefer to skip Docker Compose and use plain Docker? No problem! Use this command to start Palmr. directly:
Configure Palmr. behavior through environment variables:
| Variable | Default | Description |
| ---------------- | ------- | ------------------------------------------------------- |
| `ENABLE_S3` | `false` | Enable S3-compatible storage |
| `ENCRYPTION_KEY` | - | **Required**: Minimum 32 characters for file encryption |
> **⚠️ Security Warning**: Always change the `ENCRYPTION_KEY` in production. This key encrypts your files - losing it makes files permanently inaccessible.
### Generate Secure Encryption Keys
Need a strong key for `ENCRYPTION_KEY`? Use our built-in generator to create cryptographically secure keys:
<KeyGenerator />
---
## Accessing Palmr.
Once deployed, access Palmr. through your web browser:
- **Local**: `http://localhost:5487`
- **Server**: `http://YOUR_SERVER_IP:5487`
### API Access (Optional)
If you exposed port 3333 in your configuration, you can also access:
- **API Documentation**: `http://localhost:3333/docs` (local) or `http://YOUR_SERVER_IP:3333/docs` (server)
- **API Endpoints**: Available at `http://localhost:3333` (local) or `http://YOUR_SERVER_IP:3333` (server)
> **📚 Learn More**: For complete API documentation, authentication, and integration examples, see our [API Reference](/docs/3.0-beta/api) guide.
> **💡 Production Tip**: For production deployments, configure HTTPS with a valid SSL certificate for enhanced security.
---
## Docker CLI Alternative
Prefer using Docker directly? Both storage options are supported:
**Named Volume:**
```bash
docker run -d \
--name palmr \
-e ENABLE_S3=false \
-e ENCRYPTION_KEY=change-this-key-in-production-min-32-chars \
-e ENCRYPTION_KEY=your-secure-key-min-32-chars \
-p 5487:5487 \
-p 3333:3333 \
-v palmr_data:/app/server \
@@ -143,22 +170,84 @@ docker run -d \
kyantech/palmr:latest
```
This also runs in detached mode, so it's hands-off. Access Palmr. at the same URLs mentioned earlier.
**Bind Mount:**
> **Critical Reminder**: Whichever method you choose, **change the `ENCRYPTION_KEY`** to a secure, unique value. This key encrypts your files on the filesystem if you lose it, your files become inaccessible.
```bash
docker run -d \
--name palmr \
-e ENABLE_S3=false \
-e ENCRYPTION_KEY=your-secure-key-min-32-chars \
-p 5487:5487 \
-p 3333:3333 \
-v $(pwd)/data:/app/server \
--restart unless-stopped \
kyantech/palmr:latest
```
---
## Generating a Secure Encryption Key
## Maintenance
Need a strong key for `ENCRYPTION_KEY`? Use our handy Password Generator Tool below to create one:
### Updates
<KeyGenerator />
Keep Palmr. current with the latest features and security fixes:
```bash
docker-compose pull
docker-compose up -d
```
### Backup & Restore
The backup method depends on which storage option you're using:
**Named Volume Backup:**
```bash
docker run --rm \
-v palmr_data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/palmr-backup.tar.gz -C /data .
```
**Named Volume Restore:**
```bash
docker run --rm \
-v palmr_data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/palmr-backup.tar.gz -C /data
```
**Bind Mount Backup:**
```bash
tar czf palmr-backup.tar.gz ./data
```
**Bind Mount Restore:**
```bash
tar xzf palmr-backup.tar.gz
```
---
## You're all set!
## Next Steps
Congratulations! You've just deployed your own secure file sharing solution with Palmr. in record time. We're thrilled to have you on board and hope you love using this powerful tool as much as we loved building it.
Your Palmr. instance is now ready! Explore additional configuration options:
Got questions or ideas? Dive into the rest of our documentation or reach out via our GitHub [issues page](https://github.com/kyantech/Palmr/issues). Happy sharing!
### Advanced Configuration
- **[UID/GID Configuration](/docs/3.0-beta/uid-gid-configuration)** - Configure user permissions for NAS systems and custom environments
- **[S3 Storage](/docs/3.0-beta/s3-configuration)** - Scale with Amazon S3 or compatible storage providers
- **[Manual Installation](/docs/3.0-beta/manual-installation)** - Manual installation and custom configurations
### Integration & Development
- **[API Reference](/docs/3.0-beta/api)** - Integrate Palmr. with your applications
- **[Architecture Guide](/docs/3.0-beta/architecture)** - Understanding Palmr. components and design
---
Need help? Visit our [GitHub Issues](https://github.com/kyantech/Palmr/issues) or community discussions.

View File

@@ -3,78 +3,62 @@ title: UID/GID Configuration
icon: "Users"
---
Having trouble with **permission denied** errors when using bind-mounted directories? This guide will help you configure <span className="font-bold">Palmr.</span> to work seamlessly with your host system's <span className="font-bold italic">user and group permissions</span>.
Configure user and group permissions for seamless bind mount compatibility across different host systems, particularly NAS environments.
This is particularly common on **NAS systems** like Synology or QNAP, where the container's default UID/GID doesn't match your host system. Instead of manually changing directory ownership on your host, Palmr. now supports <span className="font-bold italic">flexible UID/GID configuration</span> to automatically handle these permission conflicts.
## Overview
## The Problem
Palmr. supports runtime UID/GID configuration to resolve permission conflicts when using bind mounts. This eliminates the need for manual permission management on your host system.
By default, Palmr. runs with UID 1001 and GID 1001 inside the container. When you bind-mount a directory from your host system (like `./data:/app/server`), permission conflicts can occur if:
**Default Configuration**: UID 1001, GID 1001
- Your host user has a different UID/GID
- You're running on a NAS system with specific user configurations
- The mounted directory ownership doesn't match the container user
## When to Configure
This results in errors like:
UID/GID configuration is recommended when:
- **Access denied** even with 777 permissions
- **Database connection failures** (SQLite can't create/access files)
- **File upload failures** in the application
## The Solution
Palmr. now supports **runtime UID/GID configuration** through environment variables. The container will automatically adjust its internal user permissions to match your host system, eliminating the need to manually change directory ownership.
- Using bind mounts with different host user permissions
- Deploying on NAS systems (Synology, QNAP, etc.)
- Encountering "permission denied" errors
- Host system uses different default UID/GID values
## Environment Variables
Configure these **optional** environment variables in your `docker-compose.yml`:
Configure permissions using these optional environment variables:
| Variable | Description | Default | When to Use |
| ----------- | ---------------------------------- | ------- | ------------------------------------------- |
| `PALMR_UID` | User ID for the container process | 1001 | When host directory owner has different UID |
| `PALMR_GID` | Group ID for the container process | 1001 | When host directory group has different GID |
| Variable | Description | Default | Example |
| ----------- | -------------------------------- | ------- | ------- |
| `PALMR_UID` | User ID for container processes | `1001` | `1000` |
| `PALMR_GID` | Group ID for container processes | `1001` | `1000` |
> **Important**: These variables are **completely optional**. If you don't set them, Palmr. works exactly as before with UID/GID 1001.
---
## Finding Your Host UID/GID
## Finding Host UID/GID
Before configuring, you need to find your host system's user and group IDs:
Determine your host system's user and group IDs:
```bash
# Find your user ID
id -u
# Find your group ID
id -g
# See both together
# Check current user
id
# Output example
uid=1000(user) gid=1000(group) groups=1000(group),27(sudo)
```
Example output:
Use the `uid` and `gid` values for your configuration.
```bash
$ id
uid=1000(myuser) gid=1000(mygroup) groups=1000(mygroup),27(sudo)
```
In this example, you would use `PALMR_UID=1000` and `PALMR_GID=1000`.
---
## Configuration Examples
### Basic Linux System
Most Linux desktop systems use UID/GID 1000 for the first user:
### Standard Linux System
```yaml
services:
palmr:
image: docker.io/kyantech/palmr:latest
image: kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
# Add these lines to match your host user
- ENCRYPTION_KEY=your-secure-key-min-32-chars
- PALMR_UID=1000
- PALMR_GID=1000
ports:
@@ -86,158 +70,135 @@ services:
### Synology NAS
Synology systems commonly use these UID/GID combinations:
```yaml
services:
palmr:
image: docker.io/kyantech/palmr:latest
image: kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
# Common Synology configuration
- ENCRYPTION_KEY=your-secure-key-min-32-chars
- PALMR_UID=1026
- PALMR_GID=100
ports:
- "5487:5487"
volumes:
- /volume1/docker/palmr/data:/app/server
- /volume1/docker/palmr:/app/server
restart: unless-stopped
```
### QNAP NAS
QNAP systems typically use:
```yaml
services:
palmr:
image: docker.io/kyantech/palmr:latest
image: kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
# Common QNAP configuration
- ENCRYPTION_KEY=your-secure-key-min-32-chars
- PALMR_UID=1000
- PALMR_GID=100
ports:
- "5487:5487"
volumes:
- /share/Container/palmr/data:/app/server
- /share/Container/palmr:/app/server
restart: unless-stopped
```
### No Configuration Needed
---
If you're not experiencing permission issues, you don't need to set these variables:
## Migration Guide
```yaml
services:
palmr:
image: docker.io/kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
# No PALMR_UID/PALMR_GID needed - uses defaults
ports:
- "5487:5487"
volumes:
- ./data:/app/server
restart: unless-stopped
```
### Existing Installations
## Migration for Existing Installations
To add UID/GID configuration to running installations:
If you already have Palmr. running and want to add UID/GID configuration:
1. **Stop the container**
### Step 1: Backup Your Data
```bash
docker-compose down
```
2. **Backup your data**
```bash
cp -r ./data ./data-backup
```
3. **Update configuration**
Add UID/GID variables to your `docker-compose.yaml`
4. **Restart with new configuration**
```bash
docker-compose up -d
```
---
## Verification
### Check Configuration
Verify UID/GID settings are applied correctly:
```bash
docker-compose down
cp -r ./data ./data-backup
```
# View startup logs
docker-compose logs palmr | head -20
### Step 2: Update docker-compose.yml
Add the UID/GID environment variables to your existing configuration:
```yaml
services:
palmr:
image: docker.io/kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=your-existing-key
# Add these new lines
- PALMR_UID=1000 # Your host user UID
- PALMR_GID=1000 # Your host group GID
# ... rest of your configuration
```
### Step 3: Restart Palmr.
```bash
docker-compose up -d
```
The container will automatically detect the new UID/GID configuration and adjust permissions accordingly.
## Troubleshooting
### Checking Current Configuration
To verify your container is running with the correct UID/GID:
```bash
# Check the user ID inside the container
docker exec palmr id
# Check file ownership in the mounted volume
# Check file ownership
docker exec palmr ls -la /app/server/
# Verify process UID/GID
docker exec palmr ps aux | grep node
```
### Permission Issues Persist
### Troubleshooting
If you're still having permission issues after configuration:
**Permission issues persist:**
```bash
# Check container logs for UID/GID adjustment messages
docker-compose logs palmr | grep -i "uid\|gid"
# Check environment variables
docker exec palmr env | grep PALMR
# Manually fix permissions if needed
docker exec -u root palmr chown -R palmr:nodejs /app/server
# Verify file ownership
docker exec palmr stat /app/server/prisma/palmr.db
# Review configuration logs
docker-compose logs palmr | grep -E "🔧|🔐|🔽"
```
### Finding NAS-Specific UID/GID
For NAS systems, check your system's user management interface or use SSH:
**NAS-specific debugging:**
```bash
# On your NAS, check existing users
# Synology - Check mount point ownership
ls -la /volume1/docker/palmr/
# QNAP - Check mount point ownership
ls -la /share/Container/palmr/
# Check NAS user configuration
cat /etc/passwd | grep -v nobody
# Check groups
cat /etc/group
```
## How It Works
---
When you set `PALMR_UID` and/or `PALMR_GID` environment variables:
## Implementation Details
1. **Container startup**: The container detects the environment variables
2. **User adjustment**: Automatically modifies the internal `palmr` user to use your specified UID/GID
3. **Ownership update**: Updates file ownership of application directories
4. **Conflict handling**: Gracefully handles cases where the UID/GID already exists
5. **Logging**: Provides clear feedback about what changes were made
The UID/GID configuration process:
The process is completely automatic and requires no manual intervention.
1. **Detection** - Environment variables are read during container startup
2. **Ownership Update** - File permissions are adjusted to match target UID/GID
3. **Privilege Drop** - Application runs with specified user permissions via `su-exec`
4. **Logging** - Configuration changes are logged for verification
## Build-Time Customization
This approach provides automatic permission management without user creation or system modification.
For advanced users who want to build custom images with different default UID/GID:
---
## Build-Time Configuration
For custom base images with different default values:
```bash
docker build \
@@ -246,18 +207,16 @@ docker build \
-t palmr:custom .
```
This sets new defaults at build time, which can still be overridden with environment variables at runtime.
Runtime environment variables override build-time defaults.
---
## Summary
## Benefits
The UID/GID configuration feature makes Palmr. **universally compatible** with different host systems without requiring manual permission changes. Key benefits:
- **Zero Configuration** - Works automatically when environment variables are set
- **Universal Compatibility** - Supports any valid UID/GID combination
- **NAS Optimized** - Tested with major NAS platforms
- **Backward Compatible** - Existing deployments continue without modification
- **Performance Optimized** - Lightweight implementation using `su-exec`
- ✅ **Automatic permission handling** - No manual `chown` commands needed
- ✅ **NAS system compatibility** - Tested with Synology and QNAP
- ✅ **Backward compatible** - Existing installations continue to work unchanged
- ✅ **Optional configuration** - Only use when needed
- ✅ **Runtime flexibility** - Change UID/GID without rebuilding images
If you're experiencing permission issues with bind-mounted directories, try adding the appropriate `PALMR_UID` and `PALMR_GID` environment variables to your configuration. The container will handle the rest automatically!
For permission issues with bind mounts, add the appropriate `PALMR_UID` and `PALMR_GID` environment variables to resolve conflicts automatically.

View File

@@ -1,6 +1,7 @@
# FOR FILESYSTEM STORAGE ENV VARS
ENABLE_S3=false
ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
DATABASE_URL="file:./palmr.db"
# FOR USE WITH S3 COMPATIBLE STORAGE
# ENABLE_S3=true

View File

@@ -4,7 +4,7 @@ generator client {
datasource db {
provider = "sqlite"
url = "file:./palmr.db"
url = env("DATABASE_URL")
}
model User {

View File

@@ -11,6 +11,7 @@ const envSchema = z.object({
S3_REGION: z.string().optional(),
S3_BUCKET_NAME: z.string().optional(),
S3_FORCE_PATH_STYLE: z.union([z.literal("true"), z.literal("false")]).default("false"),
DATABASE_URL: z.string().optional().default("file:/app/server/prisma/palmr.db"),
});
export const env = envSchema.parse(process.env);

View File

@@ -51,11 +51,11 @@ export function usePublicShare() {
await loadShare(password);
};
const handleDownload = async (file: { id: string; name: string }) => {
const handleDownload = async (objectName: string, fileName: string) => {
try {
const response = await getDownloadUrl(file.id);
const encodedObjectName = encodeURIComponent(objectName);
const response = await getDownloadUrl(encodedObjectName);
const downloadUrl = response.data.url;
const fileName = downloadUrl.split("/").pop() || file.name;
const link = document.createElement("a");
link.href = downloadUrl;
@@ -63,6 +63,7 @@ export function usePublicShare() {
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
toast.success(t("share.messages.downloadStarted"));
} catch (error) {
toast.error(t("share.errors.downloadFailed"));
}

View File

@@ -0,0 +1,17 @@
services:
palmr:
image: kyantech/palmr:latest
container_name: palmr
environment:
- ENABLE_S3=false
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars # CHANGE THIS KEY FOR SECURITY
# Optional: Set custom UID/GID for file permissions
# - PALMR_UID=1000
# - PALMR_GID=1000
ports:
- "5487:5487" # Web port
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
volumes:
# Bind mount for persistent data (uploads, database, temp files)
- ./data:/app/server # Volume for the application data
restart: unless-stopped # Restart the container unless it is stopped

View File

@@ -9,7 +9,7 @@ services:
- "5487:5487" # Web port
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
volumes:
- palmr_data:/app/server # Volume for the application data
- palmr_data:/app/server # Volume for the application data (changed from /data to /app/server)
restart: unless-stopped # Restart the container unless it is stopped
volumes:

View File

@@ -1,22 +1,93 @@
#!/bin/sh
set -e
echo "Starting Palmr Server with SQLite..."
echo "🌴 Starting Palmr Server..."
# Set proper environment
export HOME=/home/palmr
export NPM_CONFIG_CACHE=/home/palmr/.npm
export PNPM_HOME=/home/palmr/.pnpm
# === UID/GID Runtime Configuration ===
TARGET_UID=${PALMR_UID:-1001}
TARGET_GID=${PALMR_GID:-1001}
cd /app/server
if [ -n "$PALMR_UID" ] || [ -n "$PALMR_GID" ]; then
echo "🔧 Runtime UID/GID: $TARGET_UID:$TARGET_GID"
# Update ownership of critical directories to match target UID/GID
echo "🔐 Updating file ownership..."
chown -R $TARGET_UID:$TARGET_GID /app/palmr-app 2>/dev/null || echo "⚠️ Some ownership changes may have failed"
chown -R $TARGET_UID:$TARGET_GID /home/palmr 2>/dev/null || echo "⚠️ Some home directory ownership changes may have failed"
# Update ownership of data directory if it exists
if [ -d "/app/server" ]; then
chown -R $TARGET_UID:$TARGET_GID /app/server 2>/dev/null || echo "⚠️ Some data directory ownership changes may have failed"
fi
echo "✅ UID/GID configuration completed"
fi
echo "Generating Prisma client..."
npx prisma generate --schema=./prisma/schema.prisma
# Ensure we're in the correct directory
cd /app/palmr-app
echo "Pushing database schema..."
npx prisma db push --accept-data-loss
# Set the database URL
export DATABASE_URL="file:/app/server/prisma/palmr.db"
echo "Running database seeds..."
node prisma/seed.js || echo "Seeds failed or already exist, continuing..."
echo "📂 Data directory: /app/server"
echo "💾 Database: $DATABASE_URL"
echo "Starting server application..."
exec node dist/server.js
# Create all necessary directories
echo "📁 Creating data directories..."
mkdir -p /app/server/prisma /app/server/uploads /app/server/temp-chunks /app/server/uploads/logo
# Check if it's a first run (no database file exists)
if [ ! -f "/app/server/prisma/palmr.db" ]; then
echo "🚀 First run detected - setting up database..."
# Create database with proper schema path
echo "🗄️ Creating database schema..."
npx prisma db push --schema=./prisma/schema.prisma --skip-generate
# Run seed script from application directory (where node_modules is)
echo "🌱 Seeding database..."
node ./prisma/seed.js
echo "✅ Database setup completed!"
else
echo "♻️ Existing database found"
# Always run migrations to ensure schema is up to date
echo "🔧 Checking for schema updates..."
npx prisma db push --schema=./prisma/schema.prisma --skip-generate
# Check if configurations exist
echo "🔍 Verifying database configurations..."
CONFIG_COUNT=$(node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
prisma.appConfig.count()
.then(count => {
console.log(count);
process.exit(0);
})
.catch(() => {
console.log(0);
process.exit(0);
});
" 2>/dev/null || echo "0")
if [ "$CONFIG_COUNT" -eq "0" ]; then
echo "🌱 No configurations found, running seed..."
# Always run seed from application directory where node_modules is available
node ./prisma/seed.js
else
echo "✅ Found $CONFIG_COUNT configurations"
fi
fi
echo "🚀 Starting Palmr server..."
# Drop privileges using su-exec with specific UID/GID
if [ "$(id -u)" = "0" ]; then
echo "🔽 Dropping privileges to UID:GID $TARGET_UID:$TARGET_GID"
exec su-exec $TARGET_UID:$TARGET_GID node dist/server.js
else
# We're already running as non-root
exec node dist/server.js
fi

34
infra/supervisord.conf Normal file
View File

@@ -0,0 +1,34 @@
[supervisord]
nodaemon=true
user=root
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/var/run/supervisord.pid
loglevel=info
[program:server]
command=/bin/sh -c "export DATABASE_URL='file:/app/server/prisma/palmr.db' && export UPLOAD_PATH='/app/server/uploads' && export TEMP_CHUNKS_PATH='/app/server/temp-chunks' && /app/server-start.sh"
directory=/app/palmr-app
user=root
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=PORT=3333,HOME="/home/palmr"
priority=100
[program:web]
command=/bin/sh -c 'echo "Waiting for API to be ready..."; while ! curl -f http://127.0.0.1:3333/health >/dev/null 2>&1; do echo "API not ready, waiting..."; sleep 2; done; echo "API is ready! Starting frontend..."; exec node server.js'
directory=/app/web
user=palmr
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=PORT=5487,HOSTNAME="0.0.0.0",HOME="/home/palmr",API_BASE_URL="http://127.0.0.1:3333"
priority=200
startsecs=10