Multi-Component Applications
Learn how to deploy applications with multiple interconnected services using Flux's internal DNS system
What You'll Learn
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:
Example: For an app named "mystack" with components:
- •
database→ accessible atfluxdatabase_mystack:5432 - •
api→ accessible atfluxapi_mystack:3000 - •
frontend→ accessible atfluxfrontend_mystack:8080
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:
Create the API Component
Create a Node.js API that connects to PostgreSQL:
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}`);
});docker build -t yourusername/mystack-api:latest ./api
docker push yourusername/mystack-api:latestCreate the Frontend Component
Create a simple React frontend that calls the API:
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;docker build -t yourusername/mystack-frontend:latest ./frontend
docker push yourusername/mystack-frontend:latestCreate Multi-Component Deployment Spec
Now create a deployment spec that ties all three components together:
{
"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
Deploy and Verify Communication
Deploy your multi-component stack to Flux:
- 1
Go to home.runonflux.io and paste your spec
- 2
Review the total cost (~calculating... FLUX/month for all 3 components)
- 3
Deploy and wait 5-10 minutes for all components to start
- 4
Test API health to verify database connection:
curl https://mystack-api-abc123.app.runonflux.io/health - 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
containerDatafor 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