Local Deployment

You can try Secure Chain tool in your local machine for development purposes following the next steps.

Enviroment File

The first you need is to create an enviroment (.env and .env.local) file from this template:

# For dockerized backend and database
GRAPH_DB_URI='bolt://neo4j:7687'
VULN_DB_URI='mongodb://mongoSecureChain:mongoSecureChain@mongo:27017/admin'
DOCS_URL='/docs' # Comment this on production
SERVICES_ALLOWED_ORIGINS='["http://securechain-gateway:8000"]'
GATEWAY_ALLOWED_ORIGINS='["http://securechain-frontend"]'
BACKEND_URL='http://securechain-gateway:8000'
NODE_ENV='development' # Change to 'production' for production builds

# Databases settings
GRAPH_DB_USER='neo4j' # Change in production
GRAPH_DB_PASSWORD='neoSecureChain' # Change in production
VULN_DB_USER='mongoSecureChain' # Change in production
VULN_DB_PASSWORD='mongoSecureChain' # Change in production

# Secrets for JWT
SECURE=False # Set to True in production
ALGORITHM='your_preferred_algorithm'  # e.g., 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES='access_token_expire_minutes'
REFRESH_TOKEN_EXPIRE_DAYS='refresh_token_expire_days'
JWT_ACCESS_SECRET_KEY='your_access_secret_key'
JWT_REFRESH_SECRET_KEY='your_refresh_secret_key'

# Api key for github services
GITHUB_GRAPHQL_API_KEY='add_your_api_key'

# Git python environments
# Git python refresh required env variable. Use one of the following values:
# - quiet|q|silence|s|silent|none|n|0: for no message or exception
# - warn|w|warning|log|l|1: for a warning message (logging level CRITICAL, displayed by default)
# - error|e|exception|raise|r|2: for a raised exception
GIT_PYTHON_REFRESH='select_your option'
GIT_CONFIG_SYSTEM='/dev/null'
GIT_CONFIG_GLOBAL='/dev/null'
GIT_LFS_SKIP_SMUDGE='1'
GIT_TEMPLATE_DIR=''

Nginx configuration

The second step is to create an Nginx configuration in the folder nginx/templates/default.conf.template following this template:

# IP limit: 10 requests/second with a 10 MB shared memory zone
limit_req_zone $binary_remote_addr zone=api_ratelimit:10m rate=10r/s;

# Limit simultaneous connections per IP (not essential)
limit_conn_zone $binary_remote_addr zone=perip:10m;

server {
    listen 80;
    listen [::]:80;

    root /usr/share/nginx/html;
    index index.html;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Gzip compression
    gzip on;
    gzip_types
        text/plain
        text/css
        text/js
        text/xml
        text/javascript
        application/javascript
        application/json
        application/xml+rss;
    gzip_min_length 1000;

    # Cache static assets
    location /_next/static/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location /images/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Return 429 instead of 503 when the limit is exceeded
    limit_req_status 429;

    # Favicon for API routes
    location /api/favicon.ico {
        alias /usr/share/nginx/html/images/securechain-logo.ico;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # API routes - proxy to backend
    location /api/ {
        proxy_pass $BACKEND_URL/;
        proxy_http_version 1.1;

        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_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_cookie_domain off;
        proxy_cookie_path   off;

        proxy_pass_header Set-Cookie;

        # Allows small bursts (burst 20) without rejection (no nodelay = delayed)
        limit_req zone=api_ratelimit burst=20;
    }

    # SPA fallback
    location / {
        try_files $uri $uri/ $uri.html /index.html;
    }

    # Health check
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # Deny access to hidden files
    location ~ /\. {
        deny all;
    }

    # Error pages
    error_page 404 /404.html;
    error_page 500 502 503 504 /500.html;
}

Docker Deployment

The third step only needs as requirements Docker with docker compose.

Docker Network

Create a docker network with command:

docker network create securechain

Databases containers

For graphs and vulnerabilities information you need to download the zipped data dumps from Zenodo. Once you have unzipped the dumps, inside the root folder copy the .env file and run the command:

docker compose up --build

The containerized databases will also be seeded automatically.

Tools containers

To deploy all Secure Chain tools in your local machine as demo, all you need is run this the command docker compose up --build with the .env file and this docker compose file in the same folder:

services:
  securechain-frontend:
    container_name: securechain-frontend
    image: ghcr.io/securechaindev/securechain-frontend:latest
    env_file:
      - .env.local
    ports:
      - "80:80"
    networks:
      - securechain
    depends_on:
      securechain-gateway:
        condition: service_healthy
    volumes:
      - ./nginx/templates:/etc/nginx/templates:ro

  securechain-gateway:
    container_name: securechain-gateway
    image: ghcr.io/securechaindev/securechain-gateway:latest
    env_file:
      - .env
    ports:
      - '8000:8000'
    networks:
      - securechain
    depends_on:
      securechain-auth:
        condition: service_healthy
      securechain-depex:
        condition: service_healthy
      securechain-vexgen:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 5s
      timeout: 3s
      retries: 5

  securechain-auth:
    container_name: securechain-auth
    image: ghcr.io/securechaindev/securechain-auth:latest
    env_file:
      - .env
    ports:
      - '8000'
    networks:
      - securechain
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 5s
      timeout: 3s
      retries: 5

  securechain-depex:
    container_name: securechain-depex
    image: ghcr.io/securechaindev/securechain-depex:latest
    env_file:
      - .env
    ports:
      - '8000'
    networks:
      - securechain
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 5s
      timeout: 3s
      retries: 5

  securechain-vexgen:
    container_name: securechain-vexgen
    image: ghcr.io/securechaindev/securechain-vexgen:latest
    env_file:
      - .env
    ports:
      - '8000'
    networks:
      - securechain
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 5s
      timeout: 3s
      retries: 5

networks:
  securechain:
    name: securechain
    external: true
    driver: bridge