Skip to content

Bootstrap an opinionated, production-ready Bun application environment on Ubuntu.

License

Notifications You must be signed in to change notification settings

acfatah/ubuntu-bun-server-setup

Repository files navigation

Ubuntu Bun Server Setup

GitHub GitHub Release GitHub last commit (by committer)

Bootstrap an opinionated, production-ready Bun application environment for Ubuntu.

  • Installs Bun, Nginx, UFW, Certbot (via snap), and sets up a Bun app under /srv/app.
  • Creates a systemd service bun-app for running the Bun app.
  • Configures Nginx as a reverse proxy to localhost:3000 and serves static files from /var/www/app/dist (or /var/www/html if sample app is skipped).
  • Configures UFW: allows SSH (22), HTTP (80), and HTTPS (443), limits SSH, and prefers the 'Nginx Full' profile.
  • Optionally creates a sample Bun app at /srv/app and enables the bun-app service (set SKIP_BUN_APP=1 to skip).
  • Intended for provisioning Ubuntu servers (22.04+); run as root/sudo with internet access.

Prerequisites

  • Ubuntu 22.04+ or 24.04, run as root or with sudo.
  • Internet access for package and snap installs.

Software Included

Software Version License
Bun 1.3.x MIT
Nginx 1.24.x Artistic License 2.0
Certbot 5.1.x Apache 2 on GitHub

Quick Start

Pipe the installer directly to bash (runs as root with sudo)

Important

Piping remote scripts to a shell executes code from the network — review the script before running.

curl -fsSL https://raw.githubusercontent.com/acfatah/ubuntu-bun-server-setup/main/install.sh | sudo bash

To skip sample app:

curl -fsSL https://raw.githubusercontent.com/acfatah/ubuntu-bun-server-setup/main/install.sh | sudo bash -s -- SKIP_BUN_APP=1

Or after cloning this repository:

sudo bash install.sh

When done:

  • Check Bun: bun --version
  • Bun app service: systemctl status bun-app (logs: journalctl -u bun-app -f)
  • Nginx default site: http://<server-ip> serving /var/www/html.
  • Get HTTPS cert for your Nginx site: certbot --nginx.

Cloudflare IP updates (optional)

The templates/cloudflare-update-ips.sh script downloads Cloudflare's IPv4 and IPv6 ranges, converts each line into an allow directive, and rewrites /etc/nginx/cloudflare-ip-filter.conf before reloading Nginx.

The nginx default config already ships with the include commented out. To enable this feature, uncomment the include cloudflare-ip-filter.conf; line in the server block to apply the allowlist to the default host.

If you need the rules applied globally, place the include in the http { ... } block of /etc/nginx/nginx.conf instead, so every server block inherits it.

Schedule the script with cron (runs as root so it can reload Nginx) by using crontab -e; for example, adding the following line:

1 2 * * * /etc/nginx/cloudflare-update-ips.sh

This runs shortly after 2:00 AM every day to keep Cloudflare's allowlist current. The script logs warnings to /var/log/cloudflare-update-ips.log if it can’t download enough addresses.

Testing

This project includes a Docker-based end-to-end test harness that provisions an Ubuntu systemd environment in a container and runs the installer in realistic scenarios.

Requirements

  • Docker installed and the Docker daemon running.
  • Ability to run privileged containers (the test container runs systemd).
  • Run commands from the repository root.

Run the full test suite

From the project root:

make test

This will:

  • Build a test image from tests/docker/Dockerfile.
  • Start short-lived, privileged containers mounting this repo read-only at /workspace.
  • Execute the test scripts under tests/docker/scripts/*.sh.

Run an individual test

You can target a specific scenario by calling the test runner directly:

tests/docker/run.sh test_root_guard
tests/docker/run.sh test_default
tests/docker/run.sh test_skip_sample

The .sh suffix is optional; both test_default and test_default.sh work.

Test scenarios

  • test_root_guard.sh — ensures the installer fails when run as a non-root user.
  • test_default.sh — runs a default install and verifies systemd units, application files, Nginx configuration, HTTP response ("Hello Bun"), and certbot availability.
  • test_skip_sample.sh — runs the installer with SKIP_BUN_APP=1 and checks that Nginx serves /var/www/html and returns the expected "Hello World" content.

You can override the test image name with the BUN_INSTALLER_TEST_IMAGE environment variable if you want to reuse or inspect the image:

BUN_INSTALLER_TEST_IMAGE=my-registry/ubuntu-bun-installer-tests make test

Environment toggles

Set any to 1 to skip:

  • SKIP_BUN_APP=1 — Do not create sample /srv/app and use /var/www/html for Nginx static root. You are now responsible for building/copying your own Bun-generated HTML assets into /var/www/html.

    Build steps typically look like bun install && bun run build from your project and then cp -R dist/* /var/www/html before managing your own Bun service.

Example:

sudo SKIP_BUN_APP=1 bash install.sh

Notes

  • The default Bun app runs from /srv/app and executes bun run start.

  • Static files are served by Nginx from /var/www/app/dist (or /var/www/html if sample app is skipped). Place your built assets in that directory and set the correct permissions:

    sudo chown -R www-data:www-data /var/www/app/dist
    sudo find /var/www/app/dist -type d -exec chmod 755 {} +
    sudo find /var/www/app/dist -type f -exec chmod 644 {} +
  • Static files are served at / and API is proxied to Bun at /api.

  • To use your own Bun app, replace /srv/app contents and update the systemd service ExecStart as needed.

  • If you skip the default app, set up your own Bun application and systemd unit file. Example:

    [Unit]
    Description=Bun App
    After=network.target
    
    [Service]
    Type=simple
    WorkingDirectory=/srv/app
    ExecStart=/root/.bun/bin/bun run start
    Restart=always
    RestartSec=3
    User=root
    Environment=NODE_ENV=production
    Environment=INSTANCE_ID= # Value from /etc/environment
    StandardOutput=journal
    StandardError=journal
    SyslogIdentifier=bun-app
    
    [Install]
    WantedBy=multi-user.target

About

Bootstrap an opinionated, production-ready Bun application environment on Ubuntu.

Resources

License

Contributing

Stars

Watchers

Forks