How to deploy a svelte kit app after build using nginx as web server
Asked Answered
F

4

8

I have a svelte kit project. I want to deploy the app in an Nginx web server after an npm run build. At the moment I have a node container and I use to start using npm run preview. It's working fine, but I want to deploy in a production environment using build.

How could I do that?

ref: https://kit.svelte.dev/docs#command-line-interface-svelte-kit-build

Feckless answered 17/12, 2021 at 21:10 Comment(0)
I
10

As @Caleb Irwin said, you can run node ./build/index.js

The NGINX configuration will look like this:

upstream sveltekit {
  server 127.0.0.1:3000;
  keepalive 8;
}


server {
  # listen ... 
  # servername ...

  # root ... (folder with an index.html in case of sveltekit being crashed)

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://sveltekit;
    proxy_redirect off;

    error_page 502 = @static;
  }

  location @static {
    try_files $uri /index.html =502;
  }
}

(I'm not a NGINX pro and welcomes feedback to improve on it)

You may also want to make the SvelteKit app listen only to localhost by adding the environment HOST=127.0.0.1 before running node build/index.js. This will prevent the port 3000 from being reached from the outside.

You can also look into using pm2 to manage the sveltekit process, including running it on each of your cores in cluster mode, automatic restart in case of server crash / reboot.

Idioglossia answered 21/12, 2021 at 11:23 Comment(7)
Thank you. I will learn more about pm2. I use a reverse haproxy up front, with ssl and other settings. I tried this settings in the containers, node ./build/index.js. In fact, I think now nginx is not needed to run. Thanks.Eversion
I am facing issues with the nginx configuration. It works for location /. But if I want to point the sveltekit app to a different location (e.g. /survey), it doesn't work. Why could that be?Somber
@Somber try setting config.kit.paths.base your svelte.config.js to /survey.Idioglossia
@coyotte508, let me try it. I see an issue in my dev app itself now. If I go to localhost:3000, it asks me if I meant /survey. Going to localhost:3000/survey renders it fine, but some of my fetch commands fail as I need to hard-code the 'survey/' path everywhere. I wonder if there is a cleaner approach?Somber
You can make a fetch wrapper to add a base path? function bfetch(path, options) { return fetch(base+path, options)} Maybe there is a better way, would need to look into the docs. You can import {base} from "$app/paths".Idioglossia
@coyotte508, changing the base worked somewhat. The app is accessible at the /survey location. But none of the components/assets within _app get loaded. What could be the reason?Somber
The @Duke answer support serving the static files as static files, cache on the images and pass only the real nodejs work to nodejs.Gaze
T
7

If you have a static website (ie no endpoints) you should use @sveltejs/adapter-static. It will put the files you should serve in /build directory. You can then serve the generated pages using NGINX. A sample NGINX config would be:

server {
        listen 80;
        server_name test.jasonrigden.com;
        root /path/to/build/directory;
        index index.html;
}

If your site is not static you should use @sveltejs/adapter-node and run that in your container. You could put NGINX in front of it to use its features (SSL, load balancing, firewall, etc). After building your site (using npm run build) you can run node ./build/index.js.

Alternatively, you could use Netlify, Vercel, or Cloudflare Pages to host you site.

To see how to change your adapter see the docs.

Good luck!

Tandratandy answered 18/12, 2021 at 17:54 Comment(1)
My website isn't static, it's actually an enterprise app. I use a reverse haproxy up front, with ssl and other settings. I tried this settings in the containers, node ./build/index.js. It's working fine! Thank you.Eversion
B
4

This config is for running SvelteKit with node-adapter.

upstream sveltekit-server {
  server 127.0.0.1:3000;
  keepalive 8;
}

server {
  listen 80;
  server_name mydomain.com;

  root /home/deploy/frontend/build/client;

  location / {
    try_files $uri $uri/ @sveltekit;
  }

  location @sveltekit {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Sendfile-Type X-Accel-Redirect;

    proxy_pass http://sveltekit-server;
    proxy_redirect off;

    # error_page 502 = @static;
  }

  location ^~ /_app/immutable/ {
    # gzip_static on;
    expires max;
    add_header Cache-Control public;
    access_log off;
    try_files $uri $uri/;
  }
}

Here's a gist --

https://gist.github.com/dukejones/01fd7ddbfc8cdac4e02c6105d26ca7fe

The best thing about nginx is it can just serve the static files with strong caching for immutable files with content-hashed naming, and pass the rest onto the nodejs server.

Of course use some process manager (systemd etc) to keep the nodejs server running, or run nodejs in docker & expose the port.

EDIT: based on Ivailo's comment

Belinda answered 1/10, 2023 at 5:19 Comment(1)
on /_app/immutable/ location I think there is no need to have the @sveltekit upstreamGaze
K
2

I've managed to deploy a Svelte Kit app to my Google Cloud Engine virtual machine and serve it using Nginx. I've still got some outstanding questions myself, but so far these are my steps:

  1. Run the build locally as per the docs referenced by OP. Local directory: $ npm run build
  2. Local directory:$ gcloud compute scp --recurse build/ user@gcpinstance:~/Desktop
  3. Local directory:$ gcloud compute scp package*.* user@gcpinstance:~/Desktop
  4. On the remote vm, from the directory to which I uploaded my build folder and the package files, (e.g.~/Desktop$), I run npm install. That re-created the node-modules folder (otherwise it takes forever to upload the node-modules folder from the local machine).
  5. ~/Desktop$ mkdir SvelteKitProd/
  6. ~/Desktop$ mv package*.* build/ node-modules/ SvelteKitProd/
  7. ~/Desktop$ sudo chown -R root:root SvelteKitProd/
  8. ~/Desktop$ mv SvelteKitProd/ /var/www/domainname/ 9 ~/Desktop$ cd /var/www/domainname/
  9. /var/www/domainname:$ sudo vi /etc/nginx/sites-available/domainname (this is my nginx configuration for this domain and this app).
upstream hijacked-media {
    server 127.0.0.1:3000;
    keepalive 64;
}

server {
    server_name hijacked.media www.hijacked.media;
    #root /var/www/hijacked.media/sveltekittest/sveltekitprod/PROD-GCP;
    #       index index.html index.htm;
    access_log  /var/log/nginx/hijacked.media.access.log;
    error_log  /var/log/nginx/hijacked.media.error.log;

    location  / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';

        proxy_pass http://hijacked-media;
        proxy_redirect off;
        proxy_read_timeout 240s;
        #proxy_cache_bypass $http_upgrade;
    }


    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/hijacked.media/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/hijacked.media/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = www.hijacked.media) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = hijacked.media) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    server_name hijacked.media www.hijacked.media;
    listen 80;
    return 404; # managed by Certbot


}
  1. /var/www/domainname$ pm2 start SvelteKitProd/build/index.js

I'm still trying to figure out what all I need to do in order to serve multiple apps each from its own top-level domain. I was hoping that I could change the PORT once built and uploaded (see the build/index.js file), but so far that isn't working for me. So I'll try specifying a unique port number while building it locally or messing with it once uploaded to the remote server; or perhaps use PM2 and Nginx to make multiple apps work on the same port, e.g. 3000.

Kalinda answered 3/1, 2022 at 22:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.