Docker
This document describes how to deploy (IPv4 and IPv6) StackV using Docker and how to verify connectivity. It also includes notes for troubleshooting Docker's IPv6 limitations.
Installing Docker
-
sudo yum install -y docker(or use your distro's package manager) -
sudo systemctl enable docker && sudo systemctl start docker
IPv4 Deployment
TODO
IPv6 Deployment
Docker Host Configuration for IPv6
For Docker containers to communicate over IPv6, the Docker daemon must be configured to manage an IPv6 subnet.
-
Edit the Docker Daemon Configuration File:
Open or create the file /etc/docker/daemon.json. Add the following configuration to enable IPv6 and assign a default address pool for Docker networks.
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:21::/64"
}Note: 2001:db8::/32 is a prefix reserved for documentation. For production, it is recommended to use a Unique Local Address (ULA) prefix from your organization's assigned block.
-
Apply the Configuration
Restart the Docker service for the changes to take effect.
sudo systemctl restart docker
StackV Deployment with docker-compose.yml
The following docker-compose.yml defines the app and db services for StackV, configured within an IPv6-enabled network.
docker-compose.yml
version: '3.7'
services:
app:
image: virnao/stackv-orchestrator:release-r2025.1.1
command: ['/bin/wait-for-it.sh', 'db:3306', '-t', '600', '-s', '--', 'sh', '-c', '/bin/startup.sh']
depends_on:
- db
environment:
KC_DOMAIN: <YOUR_HOSTNAME_OR_DOMAIN>:<APP_PORT>
KC_CLIENT: StackV
KC_SECRET: <SECRET_VALUE>
TLS_PASS: password
MAIL_PORT: 587
MAIL_HOST: smtp.office365.com
MAIL_USER: no.reply.stackv@outlook.com
MAIL_PASS: password
JAVA_MEMORY: 24G
healthcheck:
start_period: 60s
test: ['CMD', 'curl', '-f', '-k', 'https://0.0.0.0:<APP_PORT>/StackV-web/portal/']
retries: 5
ports:
- "8443:8443/tcp"
- "[::]:8443:8443/tcp"
restart: always
volumes:
- db_data:/var/lib/mysql
- /opt/stackv/tls:/opt/jboss/wildfly/standalone/configuration/tls
networks:
- stackv-net
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: stackdbpass
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-uroot', '-pstackdbpass']
restart: always
volumes:
- db_data:/var/lib/mysql
- /opt/stackv/db/bin/localhost.sql:/docker-entrypoint-initdb.d/localhost.sql:ro
- /opt/stackv/db/bin/postprocess.sql:/docker-entrypoint-initdb.d/postprocess.sql:ro
- /opt/stackv/db/config:/etc/mysql/conf.d
networks:
- stackv-net
volumes:
db_data:
networks:
stackv-net:
driver: bridge
enable_ipv6: true
ipam:
config:
- subnet: 10.0.21.0/24
- subnet: "<DOCKER_IPV6_PREFIX>/64"
Note on IPv6 Addressing:
- Replace
DOCKER_IPV6_PREFIXwith your chosen Docker IPv6 network prefix. - The host machine should have a public/global IPv6 address (e.g.,
HOST_IPV6) that is used for publishing ports.
To deploy StackV:
-
Save the content above as
docker-compose.yml, replace placeholder values (likeYOUR_HOSTNAME_OR_DOMAIN), and run:docker-compose up -d
Verifying Bidirectional IPv6 Connectivity
Verification is a two-part process to confirm traffic can flow in both directions.
Part A: Outbound Verification (Client \u2192 StackV Server)
This tests if you can reach the containerized service from an external machine (e.g., your laptop).
-
Check Local Machine's IPv6 Connectivity:
Get your public IPv6 address
curl -6 -s https://v6.ident.me
-
Resolve the Server's IPv6 Address:
Confirm the AAAA DNS record points to the host's IPv6
dig AAAA <YOUR_HOSTNAME_OR_DOMAIN> +short
-
Test Network and Port Reachability:
Ping the host machine
ping -6 <HOST_IPV6>
Check if the application port (8443) is open
nc -6vz <HOST_IPV6> <APP_PORT>
-
Test the Application Service:
Connect to the application using its hostname
curl -6 -v -k https://<YOUR_HOSTNAME_OR_DOMAIN>:<APP_PORT>/StackV-web/portal/
Or, connect directly using the host's IPv6 address (note the brackets)
curl -6 -v -k "https://[<HOST_IPV6>]:<APP_PORT>/yourapp/portal/"
Part B: Inbound Verification (StackV Server \u2192 Client)
This crucial test confirms the return path is clear by having the remote server connect back to a service running on your local machine.
-
Prepare Your Local Machine:
- Find your current global IPv6 address: curl -6 https://v6.ident.me/
- Ensure your local firewall is not blocking incoming traffic on test ports (e.g., 44444, 8080).
-
Set Up Test Listeners on Your Local Machine:
-
Option 1: Simple TCP Listener with ncat
On your local machine, listen on port 44444 for any IPv6 connection
sudo ncat -6 -l -p 44444 --keep-open
Verify with:
ss -lntp | grep 44444
-
Option 2: HTTP Server with Docker (nginx)
Run a temporary nginx container publishing port 8080 on IPv6
docker run -d --name test-nginx -p "[::]:8080:80" nginx:alpine
Verify it is listening on [::]:8080
ss -lntp | grep 8080
-
-
Execute the Test from the Remote Server:
- SSH into the remote server where StackV is running.
- Use your local machine's IPv6 address (
LOCAL_IPV6) found in step 1.
Test the ncat listener
nc -6vz [<LOCAL_IPV6>] 44444
Test the nginx HTTP server
curl -6 -v http://[<LOCAL_IPV6>]:8080
Expected results: nc should report "Connection succeeded", and curl should return the "Welcome to nginx!" HTML page. If these tests time out, proceed to troubleshooting.
Troubleshooting Common Issues
-
Issue: Inbound Tests Fail (Timeout)
-
Cause: This is often due to asymmetric routing, especially if your local machine is on a VPN. The server's connection request (SYN) arrives via your Wi-Fi/Ethernet, but your machine's reply (SYN-ACK) is incorrectly routed out through the VPN, breaking the handshake.
-
Diagnosis: On your local machine, use tcpdump to watch for incoming packets: sudo tcpdump -i any -n 'host
REMOTE_HOST_IPV6and portTEST_PORT'. If you see a SYN packet arrive but no reply is sent from your physical interface, asymmetric routing is the likely cause. -
Solution: Add a specific route on your local machine to force replies to the server to bypass the VPN. Find your default gateway (ip -6 route | grep default) and add the route:
sudo ip -6 route add <REMOTE_HOST_IPV6> via <your_gateway_link_local_address> dev <your_physical_interface
-
-
Issue: Service is Not Listening on IPv6
-
Cause: Docker did not bind the port to the host's IPv6 address.
-
Diagnosis: On the remote host, run ss -lntp | grep
APP_PORT. The output must show a listener on [::]:APP_PORTor :::APP_PORT. If it only shows 0.0.0.0:APP_PORT, it is only listening on IPv4. -
Solution: Ensure your docker-compose.yml uses the
[::]:<HOST_PORT>:<CONTAINER_PORT>syntax in the ports section. This explicitly tells Docker to create an IPv6 binding.
-