JustToThePoint English Website Version
JustToThePoint en español

Installing Nginx with Docker Compose in Portainer & Troubleshooting

Mistakes are a great educator when one is honest enough to admit them and willing to learn from them, Aleksandr Solzhenitsynv

VPN

Portainer is a container management platform that provides a user-friendly interface for deploying, managing, and monitoring containerized applications —especially those running on Docker or Kubernetes.

This is the third post in our Portainer series, building on Deploying Portainer on Proxmox LXC. It is highly recommended that you read our first Deploying Portainer on Proxmox LXC: Script-Driven & GUI Walkthrough and second posts, Deploying WordPress as a Portainer Stack: A Hands-On Guide to Docker Compose.

How to install Nginx

  1. Log into your Portainer Server instance by opening a web browser and going to: https://192.168.1.40:9443 (or your container’s IP).

  2. In the Portainer interface, click on the Stacks menu item located on the left sidebar. Then, press the Add stack button at the top-right corner of the Stacks page.

  3. Configure the Stack: Name: Provide a name for your stack, e.g., mynginx
    Compose File: You can either write your Docker Compose file in the provided editor or upload an existing file.
    Environment Variables: Optionally, define any environment variables needed for your services.

  4. Under Build method, choose Web editor. This lets you type out a Docker Compose file manually.

  5. In the big text box, paste your entire docker-compose.yml

    version: '3'
    
    services:
    nginx:
        image: nginx:latest
        ports:
        - "8080:80"
        volumes:
        - /var/www/html:/usr/share/nginx/html
        restart: always
    

    version: ‘3’ It specifies the version of the Docker Compose file format.
    services: It defines the different services (containers) that make up your application. In this case, there is one service named nginx.
    nginx: This is the name of the service, which will be used to create a container for running Nginx.
    image: nginx:latest This specifies the Docker image to use for the container. Here, it pulls the latest version of the official Nginx image from Docker Hub.
    ports: This section maps ports from the host to the container:
    - “8080:80” This maps port 8080 on the host machine to port 80 in the Nginx container. This means you can access the Nginx web server by visiting http://192.168.1.40:8080/ in a web browser.
    volumes: It defines data volumes to persist data and share files between the host and the container:
    - /var/www/html:/usr/share/nginx/html This mounts the host directory /var/www/html to the container directory /usr/share/nginx/html. Any files placed in /var/www/html on the host will be served by Nginx, allowing you to easily manage web content.
    restart: always: This option ensures that the Nginx container automatically restarts if it stops or if the Docker daemon restarts. \

  6. Creating the index.html file on the host server (where Docker and Portainer are installed):

    mkdir -p /var/www/html
    cd /var/www/html
    
    nvim index.html
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Hello, Nginx!</title>
    </head>
    <body>
        <h1>Hello, Nginx!</h1>
        <p>This is a test page served by Nginx in a Docker container.</p>
    </body>
    </html>
    
  7. Click Deploy the stack.

  8. Access the Nginx web server by visiting http://192.168.1.40:8080/ in a web browser.

Managing Containers in Portainer GUI

In Portainer, under the Stacks section, you can manage your containers efficiently. Here are the quick actions available for each container:

Quick Actions

Troubleshoting & best practices

  1. Test Connectivity from Another Machine and try HTTP. https://192.168.1.40:9443, http://192.168.1.40:9000.
    # If Portainer UI hangs or times out:
    docker restart portainer
    
    docker stop portainer && docker rm portainer
    docker volume rm portainer_data
    docker volume create portainer_data
    # Use the HTTP Port as a Fallback
    # Portainer CE by default listens on 9443 for HTTPS.
    # If you want an unencrypted HTTP interface on 9000, you must add --http-enabled when running
    docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest --http-enabled
    
    # Then, you can test
    curl -I http://192.168.1.40:9000
    
    docker logs portainer  # inspect errors
    
  2. Some checks: pct enter ContainerID, docker ps -a (check container status), docker logs portainer (check container logs).
    # Inside your LXC container (myportainer)
    pct enter 110
    
    # Ensure the container’s IPv4 address really is 192.168.1.40/24
    root@portainer:~# ip a show eth0
    2: eth0@if17:  mtu 1500 qdisc noqueue state UP group default qlen 1000
        link/ether bc:24:11:39:28:4c brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 192.168.1.40/24 brd 192.168.1.255 scope global eth0
        valid_lft forever preferred_lft forever
        inet6 fe80::be24:11ff:fe39:284c/64 scope link proto kernel_ll
        valid_lft forever preferred_lft forever
    
    root@portainer:~# docker ps -a
    CONTAINER ID   IMAGE                           COMMAND                  CREATED       STATUS                   PORTS                                                                                                NAMES
    2b92263d8e90   wordpress:latest                "docker-entrypoint.s…"   8 hours ago   Up 8 hours               0.0.0.0:8880->80/tcp, [::]:8880->80/tcp                                                              mysql-wordpress-1
    e5704349f155   mysql:8.0                       "docker-entrypoint.s…"   8 hours ago   Up 8 hours               3306/tcp, 33060/tcp                                                                                  mysql-db-1
    bd7a95ca494c   portainer/portainer-ce:latest   "/portainer"             9 hours ago   Up 9 hours               0.0.0.0:8000->8000/tcp, [::]:8000->8000/tcp, 0.0.0.0:9443->9443/tcp, [::]:9443->9443/tcp, 9000/tcp   myportainer
    3ec276d311bf   hello-world                     "/hello"                 9 hours ago   Exited (0) 9 hours ago                                                                                                        vibrant_wozniak
    # Disable or Adjust UFW in the Container
    root@portainer:~# sudo ufw status verbose
    Status: inactive
    # Otherwise, you can adjust UFW in the Container
    sudo ufw allow 9443/tcp
    sudo ufw reload
    # or simply disable UFW
    sudo ufw disable
    
    # Test HTTPS interface locally
    curl -k https://127.0.0.1:9443 -I
    
    HTTP/1.1 200 OK
    # Portainer is running correctly inside the container.
    [...]
    # Or test the HTTP fallback on 9000 if you have already enabled it
    curl -I http://127.0.0.1:9000
    
  3. Check if the service is actually listening. sudo netstat -tuln | grep -E '9000|9443'. It requires apt install net-tools.
    sudo apt install net-tools
    # Confirm Portainer is listening on all interfaces (0.0.0.0:9443):
    root@ubuntu-vpn:~# sudo netstat -tuln | grep -E '9000|9443'
    tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN
    tcp        0      0 0.0.0.0:9443            0.0.0.0:*               LISTEN
    tcp6       0      0 :::9000                 :::*                    LISTEN
    tcp6       0      0 :::9443
    
  4. View and if necessary, edit the container’s config file:
    cat /etc/pve/lxc/110.conf
    
    arch: amd64
    cores: 2
    # The features line allows the container to run nested containers nested containers, meaning you can run LXC containers or Docker containers inside this container,
    # and manage keys (it could be necessary for certain applications that rely on secure access),
    # while also enabling the creation of device files (this can be necessary for applications that require direct access to hardware or specific device files.).
    features: nesting=1,keyctl=1,mknod=1
    hostname: portainer
    memory: 4096
    nameserver: 1.1.1.1 8.8.8.8
    # Verify the LXC’s Network Mode
    # If the Container Firewall is enabled (indicated by firewall=1), it may restrict network access for the container.
    # If you encounter connectivity issues, consider disabling it by removing the firewall=1 setting in the container configuration.
    # type=veth specifies that the network interface is a virtual Ethernet (veth) interface.
    # Veth pairs are used in container networking to connect the container’s network namespace to the host’s network namespace.
    net0: name=eth0,bridge=vmbr0,gw=192.168.1.1,hwaddr=BC:24:11:39:28:4C,ip=192.168.1.40/24,type=veth
    onboot: 1
    ostype: ubuntu
    rootfs: mypool:subvol-110-disk-0,size=80G
    startup: 1
    swap: 512
    # This line sets the AppArmor profile for the container to "unconfined."
    # AppArmor is a Linux security module that restricts the capabilities of programs.
    # By using the "unconfined" profile, the container is given broader permissions and is not restricted by AppArmor's security policies.
    lxc.apparmor.profile: unconfined
    
    # Restart the container
    pct restart 110
    
    # Verify from the host
    pct exec 110 -- curl -k -I https://192.168.1.40:9443
    
  5. Check the Proxmox Host’s Firewall (if enabled). In the Proxmox Web UI, select your Node/Host (e.g., myserver), Firewall tab, Options, and ensure the firewall is disabled. Otherwise, under Datacenter, Firewall, Rules, Add a new rule to Accept ingress on TCP ports 9000, 9443 to the container’s IP (192.168.1.40):
    Direction: in (inbound)
    Action: ACCEPT
    Protocol: TCP
    Destination: Enter the IP address of your container: 192.168.1.40
    Destination port: 9000,9443
    Enable: Yes (checked)
    Comment (optional): Add a note like “Allow Portainer ports” if desired. Interface: (Optional) Select the correct network interface if your container is on a specific bridge (e.g., vmbr0). If unsure, you can leave this blank.
    Source: (Optional) You can restrict the source IP or network if you want to limit access. If you want to allow access from any IP on your LAN, leave this blank.

    This will allow traffic to reach your container’s Portainer service.

  6. Once the container is fully provisioned, run this from your local machine: ssh-copy-id root@192.168.1.40. Now try logging into the machine, with: ssh root@192.168.1.40
  7. Log into Pi-hole’s web interface (e.g., http://192.168.1.43/admin), go to Settings, Local DNS Records, and add myportainer (domain) mapped to 192.168.1.40. Then, ssh root@myportainer, create an alias myportainer = "ssh root@myportainer";.
Bitcoin donation

JustToThePoint Copyright © 2011 - 2025 Anawim. ALL RIGHTS RESERVED. Bilingual e-books, articles, and videos to help your child and your entire family succeed, develop a healthy lifestyle, and have a lot of fun. Social Issues, Join us.

This website uses cookies to improve your navigation experience.
By continuing, you are consenting to our use of cookies, in accordance with our Cookies Policy and Website Terms and Conditions of use.