Docker
Learn how to self-host Shelve using Docker
Self-Hosting with Docker
Shelve provides official Docker images and a Docker Compose configuration for easy self-hosting. This guide will walk you through the process of deploying Shelve using Docker.
Docker Images
Official Shelve images are available on GitHub Container Registry. You can pull the latest version or a specific one:
# Pull latest version
docker pull ghcr.io/hugorcd/shelve:latest
# Pull specific version
docker pull ghcr.io/hugorcd/shelve:v2.0.0.beta-11
If you opt for the image setup, you will have to provide the necessary services (PostgreSQL, Redis) and connect them manually by setting the required environment variables:
DATABASE_URLNUXT_PRIVATE_REDIS_URL
Docker Compose
The recommended way to deploy Shelve is using Docker Compose, which will handle all the required services (PostgreSQL, Redis) and their configuration. Check the Docker Compose file for the community version or app-compose.coolify.yml for the Coolify version.
To deploy Shelve using Docker Compose, follow these steps:
Copy the Docker Compose file.
Create the .env file with the required environment variables. You can find the list of required variables in the Docker Compose file.
Run the following command to start the services:
docker-compose -f app-compose.community.yml up -d
Access the application by navigating to http://localhost:3000.
That's it! You have successfully self-hosted the Shelve application using Docker Compose.
services:
  shelve_app:
    image: ghcr.io/hugorcd/shelve:latest
    container_name: shelve_app
    restart: always
    environment:
      - DATABASE_URL=${DATABASE_URL:-postgres://postgres:postgres@shelve_db:5432/postgres}
      - NUXT_PRIVATE_REDIS_URL=${NUXT_PRIVATE_REDIS_URL:-redis://shelve_redis:6379}
      - NUXT_PRIVATE_ENCRYPTION_KEY=${NUXT_PRIVATE_ENCRYPTION_KEY}
      - NUXT_SESSION_PASSWORD=${NUXT_SESSION_PASSWORD}
      # OAuth configuration
      - NUXT_OAUTH_GITHUB_CLIENT_ID=${NUXT_OAUTH_GITHUB_CLIENT_ID}
      - NUXT_OAUTH_GITHUB_CLIENT_SECRET=${NUXT_OAUTH_GITHUB_CLIENT_SECRET}
      - NUXT_OAUTH_GOOGLE_CLIENT_ID=${NUXT_OAUTH_GOOGLE_CLIENT_ID}
      - NUXT_OAUTH_GOOGLE_CLIENT_SECRET=${NUXT_OAUTH_GOOGLE_CLIENT_SECRET}
      # Optional
      - NUXT_PRIVATE_RESEND_API_KEY=${NUXT_PRIVATE_RESEND_API_KEY}
      - NUXT_PRIVATE_ADMIN_EMAILS=${NUXT_PRIVATE_ADMIN_EMAILS}
    depends_on:
      shelve_redis:
        condition: service_healthy
      shelve_db:
        condition: service_healthy
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:3000/api/hello" ]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M
    networks:
      - shelve-network
  shelve_db:
    container_name: shelve_db
    image: postgres:17-alpine
    restart: always
    volumes:
      - postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
      POSTGRES_DB: ${POSTGRES_DB:-postgres}
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "postgres" ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - shelve-network
  shelve_redis:
    container_name: shelve_redis
    image: redis:7.4-alpine
    restart: always
    volumes:
      - redis:/data
    healthcheck:
      test: [ "CMD", "redis-cli", "ping" ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - shelve-network
networks:
  shelve-network:
    driver: bridge
volumes:
  postgres:
  redis:
Health Checks
The Docker Compose configuration includes health checks for all services:
- Shelve application: Checks the API endpoint every 30 seconds
 - PostgreSQL: Verifies database connectivity
 - Redis: Ensures Redis is responding
 
Resource Management
The configuration includes resource limits to ensure stable operation:
- CPU: 1 core limit, 0.5 core reserved
 - Memory: 1GB limit, 512MB reserved
 
Data Persistence
Data is persisted using Docker volumes:
- postgres: PostgreSQL data
 - redis: Redis data These volumes ensure your data survives container restarts.
 
Troubleshooting
If you encounter issues, check the container logs:
# All services
docker compose logs
# Specific service
docker compose logs <service-name>
For more detailed logs, you can find them in the JSON log files (limited to 10MB per file, 3 files maximum).
Upgrading
To upgrade Shelve, pull the latest image and restart the services:
Pull the latest image:
docker compose pull
Restart the services:
docker compose down
docker compose up -d
Security Considerations
- Always use strong, unique values for sensitive environment variables
 - Consider using a reverse proxy with SSL termination
 - Regularly update to the latest version for security patches
 - Restrict network access as needed