Edunexus Docker Deployment Troubleshooting Guide: Fix Network Conflicts, Nginx 502 Errors, and SQL Initialization Issues

Edunexus is a Docker Compose-based deployment stack. Its most common pain points are services that appear to be running but remain inaccessible externally, configurations that do not take effect, and container network conflicts. This guide provides a reusable troubleshooting sequence across Docker, Nginx, and SQL. Keywords: Docker deployment, Nginx 502, container networking.

The technical specification snapshot establishes the deployment baseline

Parameter Description
Deployment target Edunexus
Runtime environment Ubuntu / Linux
Orchestration method Docker Compose
Core protocols HTTP, TCP
Key ports 80, 9000, 8808, 3306, 6379, 1883, 18083
Core dependencies Docker, docker-compose, Nginx, MySQL, Redis, EMQX
Network characteristics Custom bridge subnet, such as 172.25.0.0/16
GitHub stars Not provided in the source data

This guide provides a more reliable deployment troubleshooting path

The value of this manual is not the number of commands. It is the order in which you run them. Many Docker failures are not single-point issues. They are chain reactions caused by overlapping problems in networking, configuration, volume mounts, and image versions.

Work through the system in this order: host listening state → container self-check → inter-container connectivity → effective Nginx configuration → external access. This sequence narrows the scope quickly and prevents repeated trial and error at the wrong layer.

# 1) Check whether containers are running normally
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# 2) Check whether host ports are in the listening state
sudo netstat -tlnp | grep -E ':(80|3306|6379|1883|8808|9000|18083) '

# 3) Check whether the service inside the container responds
docker exec platform_edunexus sh -c 'wget -qO- --timeout=3 http://127.0.0.1:8808/api/ 2>&1 | head -3' || true

# 4) Check whether the nginx configuration syntax is valid
docker exec platform_nginx nginx -t

These commands establish a minimum health baseline so you can first determine whether the failure is at the process, port, or reverse proxy layer.

Docker network conflicts are usually the first place to investigate when startup fails

When Compose reports Pool overlaps with other one on this address space, the declared subnet overlaps with an existing network on the host. Common sources include leftover networks from older projects, VPN virtual adapters, or internal corporate routing.

First identify what is already using the 172.25.* range. Then decide whether to remove stale networks or switch to a different subnet entirely. Prefer cleaning up unused networks first, because changing the subnet usually requires additional updates in Nginx and application configuration files.

# Find Docker network and routing conflicts
docker network ls
docker network inspect $(docker network ls -q) 2>/dev/null | grep -B5 '172.25' | head -30
ip route | grep 172.25

# Clean up leftover networks first
docker-compose -f /edunexus/edunexus_deploy_v1.1/docker-compose.yaml down --remove-orphans
docker network prune -f

These commands locate and clean up conflicting subnets. This is the first step toward restoring Compose startup.

If a real subnet conflict exists, you must replace the subnet consistently

If 172.25.0.0/16 truly conflicts with the enterprise network, switch consistently to a range such as 10.88.0.0/16. Do not update only docker-compose.yaml. You must also replace every hard-coded IP in related configuration files.

Otherwise, containers may start successfully, but upstream routes, Nginx upstream targets, or application callbacks may still point to the old addresses. The result is often intermittent 502 errors, connection resets, or systems that appear available while the end-to-end path remains broken.

Entrypoint permission errors usually indicate an incomplete image build

exec: "/opt/xxx/entrypoint.sh": permission denied means the entrypoint script does not have executable permissions. This is common in custom images, especially services such as EMQX, DetectSvr, and StreamSrv that rely on custom shell scripts.

The temporary workaround is to avoid rebuilding the image and let the shell interpret the script directly. The permanent fix is to correct host-side file permissions and explicitly run chmod +x in the Dockerfile.

mqtt:
  entrypoint: ["sh", "/opt/emqx/entrypoint.sh"]

This configuration runs the script through sh, which bypasses the missing +x permission on the script itself.

COPY entrypoint.sh /opt/emqx/entrypoint.sh
RUN chmod +x /opt/emqx/entrypoint.sh

# Fix script permissions in batch
RUN find /opt/avtronsys/StreamSrv -maxdepth 2 -name "*.sh" -exec chmod +x {} \;

This Dockerfile moves the permission fix into the image build stage and prevents the same runtime issue from recurring.

When Nginx listens on the port but the connection is reset, the problem is usually inside the container

If curl returns Connection reset by peer, the TCP handshake has already succeeded, but the application immediately sent an RST. This is not a typical firewall symptom. It more often points to Nginx configuration problems, image version mismatches, or missing static assets.

Do not limit the investigation to whether docker-proxy is listening. More importantly, verify which configuration Nginx actually loaded, whether the container is really listening on the target port, and whether the error log shows syntax problems or upstream failures.

# Check routes, configuration, runtime listeners, and error logs
ip route
docker network inspect $(docker network ls -q) 2>/dev/null | grep -E 'Subnet|Gateway' | head
docker exec platform_nginx nginx -t
docker exec platform_nginx nginx -T 2>/dev/null | grep -E "listen 9000|edunexus_backend"
docker exec platform_nginx sh -c "cat /proc/net/tcp | awk 'NR>1 {print \$2}' | cut -d: -f2 | sort -u | while read p; do printf '%d\n' 0x\$p; done | sort -un"
docker logs platform_nginx --tail 80

These commands confirm whether Nginx actually loaded the expected configuration and is listening on the target port inside the container.

Sticky old configuration is the most hidden failure source in deployment scripts

If the deployment script uses a rule like “skip copying when the directory already exists,” the new nginx.conf may never overwrite the old file. In that case, the host appears to have the new configuration, while the container mount still uses the old one.

If nginx -T does not show listen 9000 or edunexus_backend, but those directives clearly exist in the source file, you can treat this as configuration stickiness with high confidence.

sudo cp -f /edunexus/edunexus_deploy_v1.1/avtronsys/Nginx/conf/nginx.conf /opt/avtronsys/Nginx/conf/nginx.conf
docker exec platform_nginx nginx -s reload

These commands force an overwrite of the Nginx configuration and reload it immediately.

Incompatible Nginx directives can cause reload to fail outright

For example, older Nginx versions may not support keepalive_requests or keepalive_timeout inside an upstream block. This issue is often misdiagnosed as a configuration typo when the real cause is an outdated image version.

As a short-term workaround, remove the unsupported directives. As a long-term fix, standardize on a newer Nginx base image so future features are not blocked by version limitations.

# Temporarily remove incompatible directives
sudo sed -i '/keepalive_requests/d; /keepalive_timeout 75s/d' /opt/avtronsys/Nginx/conf/nginx.conf
docker exec platform_nginx nginx -s reload

# Long-term solution: upgrade the image
# FROM nginx:1.27-alpine

These commands represent two strategies: immediate mitigation and permanent remediation.

Missing frontend dist assets and cross-container probing quickly expose path-level failures

If the dist directory was not copied into the mounted container path, Nginx may still have a valid configuration but can only return an error page or an empty site. This issue often appears together with deployment logic that skips copying when files already exist.

Another efficient technique is to test connectivity from a different container. Minimal Nginx images often do not include curl, wget, or ping. In that case, you can reuse an MQTT container that includes nc for port probing.

# Check whether frontend assets exist
docker exec platform_nginx ls /opt/avtronsys/Nginx/frontend/edunexus/dist/ 2>&1

# Validate connectivity from another container
docker exec platform_mqtt sh -c "nc -zv 172.25.0.7 8808 && echo OK"
docker exec platform_mqtt sh -c "nc -zv 172.25.0.2 9000"

# Connect directly to the container IP from the host
curl -sv http://172.25.0.7:8808/api/ 2>&1 | head -10

These commands validate static assets, inter-container connectivity, and the actual response from the application container at the same time.

External access and database recovery must be handled separately

If curl 127.0.0.1:9000 works locally but other machines on the LAN cannot reach the host IP, the problem has shifted to the firewall, virtualization networking, or NAT port forwarding.

In VMware NAT mode, even if both the container and the host are healthy, external traffic may still fail between the host and the virtual machine. Bridged mode is usually more direct.

# Check and allow firewall ports
sudo ufw status
sudo iptables -L INPUT -n | head -20
sudo ufw allow 9000/tcp
sudo ufw allow 80/tcp
sudo ufw reload

These commands are the standard step for ruling out host-level firewall blocking when external access fails.

Reset the database only when you have confirmed re-initialization is required

MySQL initialization depends on /docker-entrypoint-initdb.d/*.sql. If the data volume already exists, the initialization scripts will not run again. In many cases, “SQL was not imported” does not mean the script failed. It means the volume was never cleared.

A full reset deletes historical data. Use it only for failed first-time deployments, polluted schema states, or rollback scenarios in test environments.

# Clear the data volume and re-initialize MySQL
docker-compose down -v
sudo rm -rf /opt/avtronsys/Mysql/data/*
docker-compose up -d mysql
docker logs platform_mysql -f

# Verify that the database and tables were created
docker exec platform_mysql mysql -uroot -p'Avt@2024!' -e "SHOW DATABASES; USE edunexus; SHOW TABLES;" 2>&1 | tail -30

These commands trigger first-time MySQL initialization and verify that the edunexus database has been created successfully.

Correct idempotency design in deployment scripts determines long-term stability

The most important lesson from this troubleshooting exercise is not any single command. It is that deployment scripts must distinguish between configuration files and user data. Configuration should be force-overwritten. Data should be preserved. That boundary defines a maintainable deployment system.

If you invert that boundary, the system behaves like this: “We redeployed, but the issue never changed.” These failures are the hardest to detect and often the most time-consuming to resolve.

FAQ

Q1: Why are all containers Up, but the browser still cannot open port 9000?
A: First confirm that the host port is in the LISTEN state, then check whether nginx -T actually loaded listen 9000. In many cases, the issue is not that the service failed to start. It is that the old configuration was never overwritten or the frontend dist directory was never mounted.

Q2: What is the difference between Connection reset by peer and firewall blocking?
A: The former means the TCP connection was established and then immediately reset by the application layer. It commonly points to Nginx configuration errors, upstream failures, or image version incompatibilities. Firewall problems more often appear as a timeout or connection refused.

Q3: When should I run docker-compose down -v for a full reset and redeploy?
A: Use it only when the network, configuration, and data volumes are all polluted and difficult to repair individually. It deletes named volumes and persistent data, which makes it appropriate for test environments but unsafe for production systems without backups.

Core summary: This guide reconstructs a practical Edunexus troubleshooting manual for Docker-based environments. It covers health checks, subnet conflicts, entrypoint permissions, ineffective Nginx configuration, missing frontend assets, firewall verification, and database resets, with executable commands, root-cause criteria, and repair paths.