Putting your app from Lovable, Bolt or another AI builder on your WebOké hosting
Built an app with Lovable, Bolt or another AI builder and want to put it on your own domain at WebOké? You can. This article explains how to get the code out of the AI builder, how to build and upload the app, and how GitHub can do that for you automatically.
1. What kind of app do you have?
Open the package.json file in your project. It tells you what kind of app it is.
- A static app (React with Vite).
package.jsoncontainsviteand no server framework. Runningnpm run buildcreates adistfolder with plain HTML, JavaScript and CSS files. You upload those topublic_html. This works on any hosting plan. Many apps from Bolt and older apps from Lovable are built this way. - An app with its own server. Since 13 May 2026, Lovable builds apps with TanStack Start: in that case
package.jsoncontains@tanstack/react-start. Such an app runs server code, so it won't work as loose files inpublic_html. You set it up as a Node.js app (see step 6). The same applies to other apps with their own server, such as an Express backend. - An app with Supabase or Lovable Cloud as its backend. The database, login and functions stay with Supabase or Lovable. On WebOké you only host the front end. When building, you do need to pass in the Supabase URL and public key (see step 5).
2. Getting the code out of the AI builder via GitHub
Lovable and Bolt can put your project in your own GitHub repository. Changes then sync both ways: what you change in the AI builder ends up in GitHub, and what you change in GitHub comes back into the AI builder.
In Lovable:
- Open your project and go to Project settings > Git > GitHub.
- Click Add connection and give the Lovable app access to your GitHub account.
- Under Accounts, click Connect. Lovable creates a private repository and keeps it up to date.
You can also do it without GitHub: use Download codebase under Project settings > Git to download the code (on a paid Lovable plan).
In Bolt:
- Open your project and click the GitHub icon in the top right.
- Log in to GitHub, click Authorize and install Bolt's GitHub app.
- Enter a name for the repository and click Create repository. Bolt then works in the
mainbranch.
3. Building and uploading a static app
You build the app on your own computer. For that you need Node.js, version 22 (the current Vite requires at least 20.19 or 22.12).
- Get the code:
git cloneyour repository, or unzip the download. - Open a terminal in the project folder and install the packages with
npm ci(ornpm installif there's nopackage-lock.json). - Build the app with
npm run build. You now have adistfolder containing anindex.htmland anassetsfolder. - Upload the contents of
disttodomains/yourdomain.nl/public_html, using an FTP client or the File Manager in DirectAdmin. So don't upload thedistfolder itself, and don't upload the source code ornode_modules. - Place the
.htaccessfile below inpublic_html.
An app with multiple pages (a router) shows addresses in the browser like yourdomain.nl/about-us. Those pages don't exist as files on the server. If you refresh such a page or open the link directly, you get a 404. With this .htaccess file, the server sends those addresses to index.html, and the app then shows the right page:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^assets/ - [R=404,L]
RewriteRule ^ index.html [L]
Existing files and folders are simply served by the server. A missing file in assets returns a real 404, so errors are easier to spot. Everything else goes to the app.
.htaccess file in your project's public folder. Vite copies everything from public to dist on every build, so it always gets uploaded along with the rest. Can't see the file in your FTP client or File Manager? Files starting with a dot are sometimes hidden, see Showing and editing hidden files such as .htaccess.4. Putting the app in a subfolder
Want the app at yourdomain.nl/app instead of yourdomain.nl? Then the app needs to know that at build time. Otherwise the browser looks for the files in /assets instead of /app/assets and the screen stays white.
- In
vite.config.js(orvite.config.ts), set the optionbase: '/app/'. - Give the router the same path. With React Router, you do this with
<BrowserRouter basename={import.meta.env.BASE_URL}>. - Build again and upload the contents of
disttopublic_html/app. - In
public_html/app/.htaccess, place the same file as above, withRewriteBase /app/.
5. Supabase, Lovable Cloud and other settings (env variables)
Settings that start with VITE_, such as VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY (VITE_SUPABASE_ANON_KEY in older projects), are written into the JavaScript files by Vite during the build. You can't set them on the server afterwards.
- You'll find the values in your project's
.envfile. Copy the names exactly as they are. - If your project has no
.envfile, create one yourself in the project folder before you runnpm run build. With GitHub Actions, you set them as secrets (see step 7). - If you've changed a value, rebuild and re-upload the app.
VITE_ can be read by every visitor. Supabase's public key (publishable or anon key) is fine there, as that's what it's meant for; Supabase protects your data with security rules (row level security). Never put the service_role key or any other secret key in a VITE_ variable.6. An app with its own server: as a Node.js app
You set up an app with server code, such as a TanStack Start app from Lovable, using Setup Node.js App in DirectAdmin. You can read how that works in Activating Node.js in DirectAdmin. For a TanStack Start app, it goes like this:
- Build the app on your computer with
NITRO_PRESET=node-server npm run build. You'll now have a.outputfolder. - Create an app under Setup Node.js App, with Node.js 22 and a folder outside
public_html, for exampleapps/myapp. - Upload the
.outputfolder to that folder. - In the same folder, create a file
start.cjscontaining this single line, and enterstart.cjsunder Application startup file:import('./.output/server/index.mjs'); - Add the settings the server needs, such as
SUPABASE_URLandSUPABASE_PUBLISHABLE_KEY, under Environment variables. - Click Restart. Do this after every new upload as well.
The small start.cjs file is needed because the server in .output is a modern JavaScript module (.mjs), while the Node.js environment loads the startup file the old way. If the app returns a 503 error, check stderr.log in your app's folder.
7. Automatic deployment with GitHub Actions
With GitHub Actions, GitHub builds your app on every change to the main branch and puts the result on your package. Because Lovable and Bolt write to GitHub, a change from the AI builder is then online within a few minutes. The Git feature in DirectAdmin doesn't build anything; it only places files. That's why GitHub Actions is more convenient for a Vite app.
Never put passwords and keys in your repository; store them as a secret in GitHub instead:
- Open your repository on GitHub and go to Settings > Secrets and variables > Actions.
- Click New repository secret, enter the name and the value and click Add secret. Do this for each secret from the variant you choose.
- Create the file
.github/workflows/deploy.ymlin your repository with one of the two examples below. - After the next change, check the Actions tab to see whether it worked. You can also start it manually with Run workflow.
Variant A: via FTPS (all hosting packages). In DirectAdmin, create a separate FTP account for GitHub, with the Domain option selected under Root folder (see How does FTP work at WebOké?). Secrets: FTP_SERVER (the server name of your package, such as linux2023.webawere.nl, not your domain name), FTP_USERNAME (the full name, such as github@yourdomain.nl), FTP_PASSWORD, and your app's VITE_ values.
name: Build and deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
env:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.VITE_SUPABASE_PUBLISHABLE_KEY }}
- uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
protocol: ftps
port: 21
local-dir: ./dist/
server-dir: public_html/
Variant B: via SSH with rsync (packages with SSH). SSH is included in Power Webhost Three and Four, AI Wordpress Three and Power Reseller, on port 1967 and with a key only (see SSH access and the Terminal in DirectAdmin).
- On your computer, create a separate key for GitHub, without a passphrase:
ssh-keygen -t ed25519 -f github-deploy -N "". - Paste the contents of
github-deploy.pubin DirectAdmin under SSH Keys > PASTE KEY. - Put the contents of
github-deploy(the private key) in the secretSSH_PRIVATE_KEY. Then delete the file from your computer. - Run
ssh-keyscan -p 1967 linux2023.webawere.nland put the output in the secretSSH_KNOWN_HOSTS. This way GitHub checks that it's really connecting to your server. - Also add
SSH_HOST(the server name),SSH_USER(your DA username),DOMEIN(such asyourdomain.nl) and theVITE_values as secrets.
name: Build and deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
env:
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
VITE_SUPABASE_PUBLISHABLE_KEY: ${{ secrets.VITE_SUPABASE_PUBLISHABLE_KEY }}
- name: Deploy
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
DOMEIN: ${{ secrets.DOMEIN }}
run: |
mkdir -p ~/.ssh
printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
printf '%s\n' "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
rsync -rlptz --delete --exclude=.well-known --exclude=cgi-bin \
-e "ssh -p 1967 -i ~/.ssh/deploy_key" \
dist/ "$SSH_USER@$SSH_HOST:domains/$DOMEIN/public_html/"
--delete, rsync removes everything from public_html that isn't part of your app, except .well-known (needed for your SSL certificate) and cgi-bin. If there's anything else in public_html, such as a second site in a subfolder, remove --delete or put the app in its own subfolder.If you don't use Supabase, leave out the lines with VITE_SUPABASE or replace them with your own app's VITE_ variables. If logging in fails a few times, the server temporarily blocks GitHub's IP address. In that case, check your secrets and start the workflow again.
8. Common errors
- The homepage works, but refreshing or a direct link gives a 404. The
.htaccessfile from step 3 is missing or is in the wrong folder. - A white screen. Open your browser's developer tools (F12) and check Console or Network. Do you see 404 errors on files in
/assets? Then the path is wrong: you uploaded thedistfolder itself instead of its contents, or the app is in a subfolder without the correctbase(step 4). - The app loads, but logging in or data doesn't work, or you see a message such as
supabaseUrl is required. TheVITE_variables weren't available during the build. Put them in.envor add them as a secret and build again. - The build fails with a message about the Node.js version. Use Node.js 22, both on your computer and in the workflow (
node-version: 22). npm cifails. There is nopackage-lock.json, for example because the project only has abun.lock. Runnpm installonce and add the newpackage-lock.jsonto your repository.- There is no
index.htmlin the build. Then it's an app with its own server, such as TanStack Start. Set it up as a Node.js app (step 6).
See also: Connecting with FileZilla (FTP, FTPS and SFTP) and SSH keys and logging in with SSH.
Detailed explanation with screenshots: Setting up a Node.js app in the DirectAdmin manual.
