Multi-Component Applications

Learn how to deploy applications with multiple interconnected services using Flux's internal DNS system

What You'll Learn

    Deploy multi-component applications
    Configure component-to-component communication
    Use Flux internal DNS patterns
    Manage environment variables across components

Before You Start

  • ✓ Completed the Basic Deployment tutorial
  • ✓ Understand Docker networking basics
  • ✓ Familiar with environment variables
  • ✓ Have FLUX tokens (~calculating... FLUX for this tutorial)

Understanding Flux Internal DNS

When you deploy a multi-component app on Flux, each component can communicate with others using a special internal DNS pattern:

flux{componentname}_{appname}

Example: For an app named "mystack" with components:

  • database → accessible at fluxdatabase_mystack:5432
  • api → accessible at fluxapi_mystack:3000
  • frontend → accessible at fluxfrontend_mystack:8080
1

Plan Your Multi-Component Architecture

Let's build a simple web application stack with three components:

PostgreSQL Database

Stores application data

Port: 5432

Node.js API

Backend REST API

Port: 3000

React Frontend

User interface

Port: 8080

Communication Flow:

Frontend (8080) → API (3000) → Database (5432)
2

Create the API Component

Create a Node.js API that connects to PostgreSQL:

api/server.jsjavascript
const express = require('express');
const { Pool } = require('pg');

const app = express();
const PORT = process.env.PORT || 3000;

// Database connection using Flux internal DNS
const pool = new Pool({
  host: process.env.DB_HOST,
  port: 5432,
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
});

app.use(express.json());

// Health check
app.get('/health', async (req, res) => {
  try {
    await pool.query('SELECT 1');
    res.json({ status: 'healthy', database: 'connected' });
  } catch (error) {
    res.status(500).json({ status: 'unhealthy', error: error.message });
  }
});

// Get all items
app.get('/api/items', async (req, res) => {
  try {
    const result = await pool.query('SELECT * FROM items ORDER BY created_at DESC');
    res.json(result.rows);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Create item
app.post('/api/items', async (req, res) => {
  try {
    const { name, description } = req.body;
    const result = await pool.query(
      'INSERT INTO items (name, description) VALUES ($1, $2) RETURNING *',
      [name, description]
    );
    res.json(result.rows[0]);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(PORT, '0.0.0.0', () => {
  console.log(`API server running on port ${PORT}`);
  console.log(`Database host: ${process.env.DB_HOST}`);
});
Build and push API image
docker build -t yourusername/mystack-api:latest ./api
docker push yourusername/mystack-api:latest
3

Create the Frontend Component

Create a simple React frontend that calls the API:

frontend/src/App.jsxjavascript
import { useState, useEffect } from 'react';

function App() {
  const [items, setItems] = useState([]);
  const [name, setName] = useState('');
  const [description, setDescription] = useState('');

  // API URL from environment variable
  const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:3000';

  useEffect(() => {
    fetchItems();
  }, []);

  const fetchItems = async () => {
    try {
      const response = await fetch(`${API_URL}/api/items`);
      const data = await response.json();
      setItems(data);
    } catch (error) {
      console.error('Error fetching items:', error);
    }
  };

  const addItem = async (e) => {
    e.preventDefault();
    try {
      await fetch(`${API_URL}/api/items`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, description }),
      });
      setName('');
      setDescription('');
      fetchItems();
    } catch (error) {
      console.error('Error adding item:', error);
    }
  };

  return (
    <div className="App">
      <h1>My Flux App</h1>
      <form onSubmit={addItem}>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Name"
          required
        />
        <input
          type="text"
          value={description}
          onChange={(e) => setDescription(e.target.value)}
          placeholder="Description"
        />
        <button type="submit">Add Item</button>
      </form>
      <ul>
        {items.map((item) => (
          <li key={item.id}>
            <strong>{item.name}</strong>: {item.description}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;
Build and push frontend image
docker build -t yourusername/mystack-frontend:latest ./frontend
docker push yourusername/mystack-frontend:latest
4

Create Multi-Component Deployment Spec

Now create a deployment spec that ties all three components together:

flux-spec.jsonjson
{
  "version": 8,
  "name": "mystack",
  "description": "Multi-component web application stack",
  "owner": "YOUR_ZELID_HERE",
  "instances": 3,
  "staticip": false,
  "enterprise": "",
  "compose": [
    {
      "name": "database",
      "description": "PostgreSQL database",
      "repotag": "postgres:16-alpine",
      "ports": [5432],
      "containerPorts": [5432],
      "domains": [""],
      "environmentParameters": [
        "POSTGRES_DB=myapp",
        "POSTGRES_USER=myuser",
        "POSTGRES_PASSWORD=mypassword"
      ],
      "commands": [],
      "containerData": "/var/lib/postgresql/data",
      "cpu": 1.0,
      "ram": 2000,
      "hdd": 20,
      "tiered": false
    },
    {
      "name": "api",
      "description": "Node.js API server",
      "repotag": "yourusername/mystack-api:latest",
      "ports": [3000],
      "containerPorts": [3000],
      "domains": [""],
      "environmentParameters": [
        "PORT=3000",
        "DB_HOST=fluxdatabase_mystack",
        "DB_NAME=myapp",
        "DB_USER=myuser",
        "DB_PASSWORD=mypassword"
      ],
      "commands": [],
      "containerData": "/appdata",
      "cpu": 1.0,
      "ram": 2000,
      "hdd": 10,
      "tiered": false
    },
    {
      "name": "frontend",
      "description": "React frontend",
      "repotag": "yourusername/mystack-frontend:latest",
      "ports": [8080],
      "containerPorts": [8080],
      "domains": [""],
      "environmentParameters": [
        "REACT_APP_API_URL=http://fluxapi_mystack:3000"
      ],
      "commands": [],
      "containerData": "/appdata",
      "cpu": 0.5,
      "ram": 1000,
      "hdd": 5,
      "tiered": false
    }
  ]
}

Key Points

  • • API connects to database using fluxdatabase_mystack
  • • Frontend connects to API using fluxapi_mystack:3000
  • • All components share the same app name: mystack
  • • Database gets persistent storage for data survival
5

Deploy and Verify Communication

Deploy your multi-component stack to Flux:

  1. 1

    Go to home.runonflux.io and paste your spec

  2. 2

    Review the total cost (~calculating... FLUX/month for all 3 components)

  3. 3

    Deploy and wait 5-10 minutes for all components to start

  4. 4

    Test API health to verify database connection:

    curl https://mystack-api-abc123.app.runonflux.io/health
  5. 5

    Access frontend and verify it can communicate with API

Troubleshooting Component Communication:

  • • Make sure component names in spec match the DNS pattern
  • • Check environment variables are set correctly
  • • Verify all components are in "Running" state
  • • Look at container logs for connection errors

Best Practices

🔒 Security

  • • Don't expose database ports publicly (Flux handles this automatically)
  • • Use strong passwords for databases
  • • Consider using Enterprise mode for private images with secrets

💾 Data Persistence

  • • Always set containerData for databases
  • • Allocate sufficient HDD space for data growth
  • • Test backups before going to production

⚡ Performance

  • • Start components in order: database → backend → frontend
  • • Add health check endpoints to all components
  • • Monitor resource usage and scale appropriately