How to Fix “map directive is not allowed here” Error in Nginx Configuration for Meteor Deployment


1 views

The error occurs because the map directive in Nginx has specific placement requirements. Unlike regular directives that can appear in various contexts, map can only be placed within the http context in your main configuration file.

# Correct placement example:
http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    # Other http context configurations
}

In your current setup, you've placed the map block directly in your site configuration file (/etc/nginx/sites-enabled/app), outside of any context. Nginx's parser rejects this because:

  1. The map directive is context-sensitive
  2. It must be declared before any server blocks that reference its variables
  3. It cannot be nested inside other blocks except http

For the cleanest implementation, move the map block to either:

# Option 1: Main nginx.conf (recommended)
http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    
    include /etc/nginx/sites-enabled/*;
}

Or alternatively create a separate config file in /etc/nginx/conf.d/:

# Option 2: Separate include file (/etc/nginx/conf.d/websocket.conf)
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Here's how your final configuration should look for a Meteor deployment:

# In /etc/nginx/nginx.conf
http {
    # WebSocket mapping
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    
    include /etc/nginx/sites-enabled/*;
}

# In /etc/nginx/sites-enabled/app
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    
    location = /favicon.ico {
        root /home/USERNAME/portal/programs/web.browser/app;
        access_log off;
    }
    
    location ~* "^/[a-z0-9]{40}\.(css|js)$" {
        gzip_static on;
        root /home/USERNAME/portal/programs/web.browser;
        access_log off;
    }
    
    location ~ "^/packages" {
        root /home/USERNAME/portal/programs/web.browser;
        access_log off;
    }
    
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
    }
}

After making these changes, always verify your configuration:

sudo nginx -t
sudo systemctl reload nginx

Test WebSocket functionality by checking the Connection and Upgrade headers in your browser's developer tools.

For production environments, consider these enhancements:

  • Add SSL/TLS configuration
  • Implement proper caching headers
  • Set up load balancing if scaling horizontally
  • Configure proper timeouts for WebSocket connections

When deploying Meteor applications with Nginx, developers often need to configure WebSocket support through a map directive. The error occurs because the map block is incorrectly placed in the server configuration file rather than the HTTP context.

The map directive must be placed in the http context of your Nginx configuration. Here's the proper structure:

http {
    # WebSocket mapping goes here at http level
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    include /etc/nginx/sites-enabled/*;
}

For your specific case, you should modify the files as follows:

In /etc/nginx/nginx.conf:

http {
    # ... existing http configuration ...

    # Add map directive here
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    include /etc/nginx/sites-enabled/*;
}

And in your site configuration (/etc/nginx/sites-enabled/app):

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    
    location = /favicon.ico {
        root /home/USERNAME/portal/programs/web.browser/app;
        access_log off;
    }
    
    # ... other location blocks ...
}

After making these changes:

sudo nginx -t
sudo systemctl reload nginx

1. Double-check for duplicate include statements in your nginx.conf
2. Ensure no conflicting map directives exist in other included files
3. Watch for syntax errors in the modified files

For production environments, consider adding these optimizations:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

upstream meteor_server {
    server 127.0.0.1:8080;
    keepalive 64;
}

server {
    # ... existing server config ...
    
    location / {
        proxy_pass http://meteor_server;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}