Imagine launching a new server, and within minutes it’s fully configured and ready to work — without a single manual action. Sounds unbelievable? But it’s a reality thanks to the cloud-init tool. This technology allows you to automatically configure a server right after launch by passing all the required parameters through a special configuration file. As a result, the system itself installs the necessary packages, sets up the web server, updates the OS, and even starts your app — all without administrator involvement.
In the RX-NAME service, cloud-init capabilities are available right from the control panel. You can use them in just a few clicks, making server deployment as fast, reliable, and convenient as possible for developers and businesses.
User-data usage examples
Many IT resources provide examples of how to pass configuration data (user-data) during virtual machine launch for automatic server setup. Such cases often use scripts that install and configure the NGINX web server, install Node.js, and launch web applications. This approach allows you to define all security settings, reverse proxy configuration, and auto-start parameters for the application from the start. As a result, time-to-market is significantly reduced.
What is cloud-init and why is it important?
Cloud-init is a universal tool for automatic initialization of cloud servers. It enables a wide range of tasks:
- Package installation and updates. With cloud-init, the server immediately gets all necessary tools (e.g., curl, git, apt-transport-https) to prepare the system for further operation.
- NGINX web server setup. Configuration files are automatically created to ensure secure operation of NGINX and proper proxying of requests to the application.
- Installing Node.js and dependencies. The script checks for the required versions of Node.js and npm, updates them if needed, and installs project dependencies.
- Automatic application launch. Using systemd, you can add a unit file to launch your app as a service. This ensures it runs continuously and restarts automatically if it crashes.
Thanks to these features, cloud-init eliminates human error, reduces misconfiguration risks, and significantly speeds up server deployment. For more details on the functions and advantages of cloud-init, visit our blog — we’ve prepared a separate article on this topic.
Cloud-init script example for deploying a Svelte app
Let’s take a real example: the configuration file below performs automatic deployment and setup of the web server, Node.js, and the Svelte application itself. Here’s what happens, step by step:
- Installing base packages. The packages section lists utilities (curl, git, apt-transport-https) that need to be installed at launch. This ensures the server has all tools to fetch keys, add repositories, and clone projects.
- Creating configuration files. With the write_files directive, the script creates several config files:
- Security headers snippet for NGINX: adds a set of rules to protect the server from XSS, clickjacking, etc.
- Default site config: sets a basic page for testing NGINX without proxying.
- Reverse proxy config for the Svelte app: redirects requests to the app running on port 8080.
- Test HTML page: confirms proper operation of the web server.
- systemd unit file: defines a service for running and restarting the app automatically.
- Security headers snippet for NGINX: adds a set of rules to protect the server from XSS, clickjacking, etc.
- Executing commands (runcmd). This block lists the commands executed to configure the server step by step:
- Verifying presence of NGINX and Node.js: checks for existing installations and logs version info.
- Adding repository and installing NGINX: connects the official repo, installs the latest version, and verifies its operation.
- Installing Node.js v20: if missing or outdated, installs the latest version with npm.
- Cloning and building the Svelte app: downloads the example project from GitHub, installs dependencies, and assigns directory permissions.
- Starting via systemd: launches the service, checks availability on port 8080.
- Enabling Svelte app proxy config in NGINX: enables svelte_app_proxy, disables the default config, and restarts the server after checking syntax.
- Verifying presence of NGINX and Node.js: checks for existing installations and logs version info.
#cloud-config
packages:
- curl
- git
- apt-transport-https
write_files:
# Security headers snippet for nginx
- path: /etc/nginx/snippets/security-headers.conf
permissions: '0644'
content: |
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer" always;
add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate" always;
add_header Pragma "no-cache" always;
# Default nginx site configuration (without proxying)
- path: /etc/nginx/sites-available/default
permissions: '0644'
content: |
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
include /etc/nginx/snippets/security-headers.conf;
}
}
# Nginx configuration for proxying requests to the Svelte app
- path: /etc/nginx/sites-available/svelte_app_proxy
permissions: '0644'
content: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
include /etc/nginx/snippets/security-headers.conf;
}
}
# Simple default HTML page for nginx test
- path: /var/www/html/index.html
permissions: '0644'
content: |
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>NGINX Test</title>
</head>
<body>
<h1>Welcome to NGINX!</h1>
<p>NGINX is running correctly!</p>
</body>
</html>
# systemd unit file to run the Svelte app
- path: /etc/systemd/system/svelte-app.service
permissions: '0644'
content: |
[Unit]
Description=Svelte Application Service
After=network.target
[Service]
WorkingDirectory=/var/www/svelte-app
ExecStart=/usr/bin/npx sirv public --no-clear --dev --host 127.0.0.1 --port 8080
Restart=always
User=www-data
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
runcmd:
- |
LOG_FILE="/var/log/cloud-init-custom.log"
echo "[$(date)] *** Starting cloud-init script ***" >> ${LOG_FILE}
# Check for nginx and Node.js/npm
if command -v nginx >/dev/null 2>&1; then
INSTALLED_NGINX=$(nginx -v 2>&1)
echo "[$(date)] NGINX is already installed: ${INSTALLED_NGINX}" >> ${LOG_FILE}
else
echo "[$(date)] NGINX not found" >> ${LOG_FILE}
fi
if command -v node >/dev/null 2>&1; then
NODE_VER=$(node -v)
echo "[$(date)] Node.js is already installed: ${NODE_VER}" >> ${LOG_FILE}
else
echo "[$(date)] Node.js not found" >> ${LOG_FILE}
fi
if command -v npm >/dev/null 2>&1; then
NPM_VER=$(npm -v)
echo "[$(date)] npm is already installed: ${NPM_VER}" >> ${LOG_FILE}
else
echo "[$(date)] npm not found" >> ${LOG_FILE}
fi
# Add official nginx repository and install the latest version
echo "deb http://nginx.org/packages/ubuntu/ ${UBUNTU_CODENAME:-jammy} nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
echo "deb-src http://nginx.org/packages/ubuntu/ ${UBUNTU_CODENAME:-jammy} nginx" | sudo tee -a /etc/apt/sources.list.d/nginx.list
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo apt-get update >> ${LOG_FILE} 2>&1
sudo apt-get install -y nginx >> ${LOG_FILE} 2>&1
echo "[$(date)] NGINX installed: $(nginx -v 2>&1)" >> ${LOG_FILE}
# Install Node.js v20
if command -v node >/dev/null 2>&1; then
CURRENT_NODE=$(node -v | sed 's/v//')
if [ "$(printf '%s\n' "20.0.0" "$CURRENT_NODE" | sort -V | head -n1)" = "20.0.0" ]; then
echo "[$(date)] Node.js is up to date ($CURRENT_NODE)" >> ${LOG_FILE}
else
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - >> ${LOG_FILE} 2>&1
sudo apt-get install -y nodejs >> ${LOG_FILE} 2>&1
fi
else
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - >> ${LOG_FILE} 2>&1
sudo apt-get install -y nodejs >> ${LOG_FILE} 2>&1
fi
# Check npm installation
if ! command -v npm >/dev/null 2>&1; then
echo "[$(date)] Error: npm is not installed" >> ${LOG_FILE}
exit 1
fi
# Test nginx default config
sudo systemctl restart nginx
if ! sudo systemctl is-active --quiet nginx; then
echo "[$(date)] Failed to start nginx" >> ${LOG_FILE}
exit 1
fi
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1)
if [ "$HTTP_CODE" -ne 200 ]; then
echo "[$(date)] Default page did not return HTTP 200" >> ${LOG_FILE}
exit 1
fi
# Clone and set up the Svelte app
SVELTE_DIR="/var/www/svelte-app"
if [ ! -d "${SVELTE_DIR}" ]; then
sudo git clone https://github.com/sveltejs/template ${SVELTE_DIR} >> ${LOG_FILE} 2>&1
sudo chown -R www-data:www-data ${SVELTE_DIR}
fi
cd ${SVELTE_DIR}
if [ -f package.json ]; then
npm install >> ${LOG_FILE} 2>&1
else
echo "[$(date)] package.json not found" >> ${LOG_FILE}
exit 1
fi
# Start Svelte with systemd
sudo systemctl daemon-reload
sudo systemctl enable svelte-app.service >> ${LOG_FILE} 2>&1
sudo systemctl start svelte-app.service
sleep 5
if ! sudo systemctl is-active --quiet svelte-app.service; then
echo "[$(date)] Failed to start Svelte app" >> ${LOG_FILE}
exit 1
fi
SVELTE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080)
if [ "$SVELTE_CODE" -ne 200 ]; then
echo "[$(date)] Svelte app did not return HTTP 200" >> ${LOG_FILE}
exit 1
fi
# Enable nginx proxy config for Svelte
sudo mkdir -p /etc/nginx/sites-enabled
sudo ln -sf /etc/nginx/sites-available/svelte_app_proxy /etc/nginx/sites-enabled/svelte_app_proxy
sudo rm -f /etc/nginx/sites-enabled/default
if ! grep -q "include /etc/nginx/sites-enabled/*;" /etc/nginx/nginx.conf; then
sudo sed -i '/include \/etc\/nginx\/conf.d\/\*.conf;/a include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf
fi
sudo systemctl restart nginx
PROXY_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1)
if [ "$PROXY_CODE" -ne 200 ]; then
echo "[$(date)] Proxy via nginx failed" >> ${LOG_FILE}
exit 1
fi
echo "[$(date)] *** Svelte app setup and configuration completed successfully ***" >> ${LOG_FILE}
final_message: "Cloud-init completed. Check the log at /var/log/cloud-init-custom.log for details."
Svelte vs Nuxt vs Next: Framework comparison
When choosing a frontend framework, developers often consider Svelte, Nuxt, or Next. Each has its strengths and limitations.
Svelte
Pros:
- Compiles into pure JavaScript without a virtual DOM, making apps extremely lightweight and fast.
- Minimal code and high readability simplify development and maintenance.
- Intuitive syntax and low learning curve.
Cons:
- Smaller ecosystem and fewer ready-made solutions compared to major frameworks.
- Fewer learning resources and examples for complex tasks compared to Nuxt and Next.
Nuxt
Pros:
- Built on Vue.js, making it appealing to those familiar with the Vue ecosystem.
- Has built-in server-side rendering (SSR) and static site generation features.
- Large, active community and well-developed plugin/module ecosystem.
Cons:
- More complex configuration and optimization than Svelte.
- Can require more resources for development and maintenance.
Next
Pros:
- Built on React, ensuring broad support and many ready-to-use components.
- Excellent support for SSR and static page generation.
- Mature ecosystem and proven usage in large projects.
Cons:
- Might be too “heavy” for small projects where simplicity and development speed are more critical than scalability.
- More complex setup compared to Svelte.
Conclusions
Automated server configuration with cloud-init significantly reduces infrastructure deployment and setup time. It enables not only package installation and NGINX setup, but also the deployment of a modern Svelte-based application.
Compared to Nuxt and Next, Svelte stands out for its simplicity, minimal code output, and high performance. However, for larger projects, Nuxt or Next is often preferred due to their richer ecosystems and additional capabilities.
Thanks to the integration of cloud-init in the RX-NAME user panel, you get a powerful automation tool to help you quickly and securely launch your projects. Try this approach and see for yourself how it simplifies the development and deployment process. For more details about cloud-init and other automation solutions, check out our blog.
Leave a Reply