title: Accessing containerised API hosted on digital ocean droplet from a remote machine
body: <p>I am trying to connect to a docker-compose deployed service stack on a DigitalOcean Docker droplet. It contains a MySQL container with a database and a go/alpine container with the API. I am using a custom bridge network which the 2 containers connect to. The issue also occurred when trying to deploy the stack locally on my mac and accessing the API container via localhost:port. I am not using docker-machine as I assume it only is needed for multi-host deployments. The stack is deployed successfully. The server container seems to be able to connect to the DB container. I am wondering if the issue might be within the host's firewall rules?</p>
  
  <p>I did try to run the app locally with mysql server running on my machine and it does work, so I don't think the reason is malfunctioning code. I couldn't get it to work either with basic HTTP server nor with https with self-signed certificates (both work on my local machine).</p>
  
  <p>docker-compose.yml</p>
  
  <pre><code>version: "3.7"
  
  networks:
    net:
      attachable: true
  
  services:
    db:
      build: ./db
      ports:
        - "3306:3306"
      environment:
        - MYSQL_ENV=local
      networks:
        - net
    server:
      build: ./server
      ports:
        - "80:5000"
        - "443:5001"
      networks:
        - net
      tty: true
      links:
        - db:db
  </code></pre>
  
  <p>iptables -L with the stack deployed:</p>
  
  <pre><code>Chain INPUT (policy DROP)
  target     prot opt source               destination         
  ufw-before-logging-input  all  --  anywhere             anywhere            
  ufw-before-input  all  --  anywhere             anywhere            
  ufw-after-input  all  --  anywhere             anywhere            
  ufw-after-logging-input  all  --  anywhere             anywhere            
  ufw-reject-input  all  --  anywhere             anywhere            
  ufw-track-input  all  --  anywhere             anywhere            
  
  Chain FORWARD (policy ACCEPT)
  target     prot opt source               destination         
  DOCKER-USER  all  --  anywhere             anywhere            
  DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
  DOCKER     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
  DOCKER     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere            
  ufw-before-logging-forward  all  --  anywhere             anywhere            
  ufw-before-forward  all  --  anywhere             anywhere            
  ufw-after-forward  all  --  anywhere             anywhere            
  ufw-after-logging-forward  all  --  anywhere             anywhere            
  ufw-reject-forward  all  --  anywhere             anywhere            
  ufw-track-forward  all  --  anywhere             anywhere            
  
  Chain OUTPUT (policy ACCEPT)
  target     prot opt source               destination         
  ufw-before-logging-output  all  --  anywhere             anywhere            
  ufw-before-output  all  --  anywhere             anywhere            
  ufw-after-output  all  --  anywhere             anywhere            
  ufw-after-logging-output  all  --  anywhere             anywhere            
  ufw-reject-output  all  --  anywhere             anywhere            
  ufw-track-output  all  --  anywhere             anywhere            
  
  Chain DOCKER (2 references)
  target     prot opt source               destination         
  ACCEPT     tcp  --  anywhere             172.24.0.2           tcp dpt:mysql
  ACCEPT     tcp  --  anywhere             172.24.0.3           tcp dpt:5001
  ACCEPT     tcp  --  anywhere             172.24.0.3           tcp dpt:5000
  
  Chain DOCKER-ISOLATION-STAGE-1 (1 references)
  target     prot opt source               destination         
  DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
  DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
  RETURN     all  --  anywhere             anywhere            
  
  Chain DOCKER-ISOLATION-STAGE-2 (2 references)
  target     prot opt source               destination         
  DROP       all  --  anywhere             anywhere            
  DROP       all  --  anywhere             anywhere            
  RETURN     all  --  anywhere             anywhere            
  
  Chain DOCKER-USER (1 references)
  target     prot opt source               destination         
  RETURN     all  --  anywhere             anywhere            
  
  Chain ufw-after-forward (1 references)
  target     prot opt source               destination         
  
  Chain ufw-after-input (1 references)
  target     prot opt source               destination         
  ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:netbios-ns
  ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:netbios-dgm
  ufw-skip-to-policy-input  tcp  --  anywhere             anywhere             tcp dpt:netbios-ssn
  ufw-skip-to-policy-input  tcp  --  anywhere             anywhere             tcp dpt:microsoft-ds
  ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:bootps
  ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:bootpc
  ufw-skip-to-policy-input  all  --  anywhere             anywhere             ADDRTYPE match dst-type BROADCAST
  
  Chain ufw-after-logging-forward (1 references)
  target     prot opt source               destination         
  
  Chain ufw-after-logging-input (1 references)
  target     prot opt source               destination         
  LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW BLOCK] "
  
  Chain ufw-after-logging-output (1 references)
  target     prot opt source               destination         
  
  Chain ufw-after-output (1 references)
  target     prot opt source               destination         
  
  Chain ufw-before-forward (1 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
  ACCEPT     icmp --  anywhere             anywhere             icmp destination-unreachable
  ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
  ACCEPT     icmp --  anywhere             anywhere             icmp parameter-problem
  ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
  ufw-user-forward  all  --  anywhere             anywhere            
  
  Chain ufw-before-input (1 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
  ufw-logging-deny  all  --  anywhere             anywhere             ctstate INVALID
  DROP       all  --  anywhere             anywhere             ctstate INVALID
  ACCEPT     icmp --  anywhere             anywhere             icmp destination-unreachable
  ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
  ACCEPT     icmp --  anywhere             anywhere             icmp parameter-problem
  ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
  ACCEPT     udp  --  anywhere             anywhere             udp spt:bootps dpt:bootpc
  ufw-not-local  all  --  anywhere             anywhere            
  ACCEPT     udp  --  anywhere             224.0.0.251          udp dpt:mdns
  ACCEPT     udp  --  anywhere             239.255.255.250      udp dpt:1900
  ufw-user-input  all  --  anywhere             anywhere            
  
  Chain ufw-before-logging-forward (1 references)
  target     prot opt source               destination         
  
  Chain ufw-before-logging-input (1 references)
  target     prot opt source               destination         
  
  Chain ufw-before-logging-output (1 references)
  target     prot opt source               destination         
  
  Chain ufw-before-output (1 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere            
  ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
  ufw-user-output  all  --  anywhere             anywhere            
  
  Chain ufw-logging-allow (0 references)
  target     prot opt source               destination         
  LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW ALLOW] "
  
  Chain ufw-logging-deny (2 references)
  target     prot opt source               destination         
  RETURN     all  --  anywhere             anywhere             ctstate INVALID limit: avg 3/min burst 10
  LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW BLOCK] "
  
  Chain ufw-not-local (1 references)
  target     prot opt source               destination         
  RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL
  RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type MULTICAST
  RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type BROADCAST
  ufw-logging-deny  all  --  anywhere             anywhere             limit: avg 3/min burst 10
  DROP       all  --  anywhere             anywhere            
  
  Chain ufw-reject-forward (1 references)
  target     prot opt source               destination         
  
  Chain ufw-reject-input (1 references)
  target     prot opt source               destination         
  
  Chain ufw-reject-output (1 references)
  target     prot opt source               destination         
  
  Chain ufw-skip-to-policy-forward (0 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere            
  
  Chain ufw-skip-to-policy-input (7 references)
  target     prot opt source               destination         
  DROP       all  --  anywhere             anywhere            
  
  Chain ufw-skip-to-policy-output (0 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere            
  
  Chain ufw-track-forward (1 references)
  target     prot opt source               destination         
  ACCEPT     tcp  --  anywhere             anywhere             ctstate NEW
  ACCEPT     udp  --  anywhere             anywhere             ctstate NEW
  
  Chain ufw-track-input (1 references)
  target     prot opt source               destination         
  
  Chain ufw-track-output (1 references)
  target     prot opt source               destination         
  ACCEPT     tcp  --  anywhere             anywhere             ctstate NEW
  ACCEPT     udp  --  anywhere             anywhere             ctstate NEW
  
  Chain ufw-user-forward (1 references)
  target     prot opt source               destination         
  
  Chain ufw-user-input (1 references)
  target     prot opt source               destination         
             tcp  --  anywhere             anywhere             tcp dpt:ssh ctstate NEW recent: SET name: DEFAULT side: source mask: 255.255.255.255
  ufw-user-limit  tcp  --  anywhere             anywhere             tcp dpt:ssh ctstate NEW recent: UPDATE seconds: 30 hit_count: 6 name: DEFAULT side: source mask: 255.255.255.255
  ufw-user-limit-accept  tcp  --  anywhere             anywhere             tcp dpt:ssh
  ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:2375
  ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:2376
  
  Chain ufw-user-limit (1 references)
  target     prot opt source               destination         
  LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 5 LOG level warning prefix "[UFW LIMIT BLOCK] "
  REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable
  
  Chain ufw-user-limit-accept (1 references)
  target     prot opt source               destination         
  ACCEPT     all  --  anywhere             anywhere            
  
  Chain ufw-user-logging-forward (0 references)
  target     prot opt source               destination         
  
  Chain ufw-user-logging-input (0 references)
  target     prot opt source               destination         
  
  Chain ufw-user-logging-output (0 references)
  target     prot opt source               destination         
  
  Chain ufw-user-output (1 references)
  target     prot opt source               destination 
  </code></pre>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>I have 3 json files with configs &amp; credentials for different environments that are parsed into a config object with the following format (credentials substituted for obvious reasons):</p>
  
  <pre><code>{
    "server": {
      "certificate": "&lt;HTTPS_CERT&gt;.pem",
      "key": "&lt;HTTPS_KEY.pem",
      "ip": "127.0.0.1",
      "port": "5000",
      "protocol": "http://",
      "file_protocol": "bfile://"
    },
    "database": {
      "address": "db",
      "port": "3306",
      "name": "brieefly",
      "user": "&lt;USERNAME&gt;",
      "password": "&lt;PASSWORD&gt;"
    },
    "auth": {
      "public": "&lt;JWT_AUTH_KEY&gt;.rsa.pub",
      "private": "&lt;JWT_AUTH_PRIV_KEY&gt;.rsa"
    }
  }
  </code></pre>
  
  <p>The config is then passed to a db object and a router object:</p>
  
  <p>db:</p>
  
  <pre><code>// connect to db - this succeeds
  
  func Connect(config *config.Config) (*DB, *err.Error) {
      connectionString := fmt.Sprintf("%s:%s@(%s:%s)/%s?parseTime=true",
          config.Database.User,
          config.Database.Password,
          config.Database.Address,
          config.Database.Port,
          config.Database.Name)
      log.Debug(connectionString)
      db, sqlErr := sql.Open("mysql", connectionString)
      if sqlErr != nil {
          return nil, err.New(sqlErr, err.ErrConnectionFailure, nil)
      }
      sqlErr = db.Ping()
      if sqlErr != nil {
          return nil, err.New(sqlErr, err.ErrConnectionFailure, nil)
      }
      return &amp;DB{db}, nil
  }
  
  .
  .
  .
  
  </code></pre>
  
  <p>router:</p>
  
  <pre><code>.
  .
  .
  
  // Run - starts the server
  func (r *Router) Run() *err.Error {
      path := config.MyPath(r.config)
      var httpErr error
  
      if r.config.Environment == config.Local {
          httpErr = http.ListenAndServe(path, r.mux)
      } else {
          httpErr = http.ListenAndServeTLS(path, r.config.TLSCert(), r.config.TLSKey(), r.mux)
      }
  
      return err.New(httpErr, err.ErrInternal, nil)
  }
  
  .
  .
  .
  
  </code></pre>
  
  <p>main function:</p>
  
  <pre><code>// since the db container needs time to start mysql server daemon, the app is retrying the connection infinitely until it succeds, *router.Run()* is a blocking operation.
  
  func main() {
      retry.PerformInfinite(retry.DefaultOptions(), func() *err.Error {
          log.Info("Configuring...")
          c, cErr := config.NewConfig(config.Local)
          if cErr != nil {
              log.Error(cErr)
              return cErr
          }
          log.Info("Configuration successful.")
  
          log.Info("Connecting to database...")
          db, dbErr := db.Connect(c)
          if dbErr != nil {
              log.Error(dbErr)
              return dbErr
          }
          log.Info("Connected.")
  
          router := net.NewRouter(db, c)
  
  
          log.Info("Server is running.")
          log.Info("Accepting standard input -&gt; ")
          rtErr := router.Run()
          if rtErr != nil {
              log.Error(dbErr)
              return rtErr
          }
  
          return nil
      })
  }
  
  </code></pre>