Angular + Caddyfile + Api reverse proxy

I'm having problems deploying my angular application, i already use the template of caddyfile but, nothing works, when i'm trying to access the page, have this 404 error, and getting logs into the deploy's logs, but anything else…

This is my caddyfile right now with the commented modifications that i tried.

global options

{
admin off # theres no need for the admin api in railway's environment
persistconfig off # storage isn't persistent anyway autohttps off # railway handles https for us, this would cause issues if left enabled
# runtime logs
log {
format json # set runtime log format to json mode
}
# server options
servers {
trustedproxies static privateranges # trust railway's proxy
}
}

site block, listens on the $PORT environment variable, automatically assigned by railway

:{$PORT} {
# access logs
log {
format json # set access log format to json mode
}

# health check for railway
rewrite /health /*

# serve from the set folder
root * {$ANGULAR_OUTPUT_PATH}/browser

# enable gzipping responses
encode gzip

# serve files
file_server

# if path doesn't exist, redirect it to 'index.html' for client side routing
try_files {path} /index.html

# set redirects on /api calls to the backend
#handle /api/* {

# reverseproxy {$BACKENDURL}
#}

#handle {

# root * /var/www/html
# tryfiles {path} /index.html # fileserver
#}

}

40 Replies

a year ago

The form formatting has broken the Caddyfile, please attach it instead.

Please also share your repo.


This is it, as .txt bcs of upload field supports

Attachments


a year ago

Please share your build logs -

https://bookmarklets.up.railway.app/log-downloader/

Please also share your repo.


Ready

Attachments


https://github.com/appli-io/frontend-main

this it is the repo, i'm trying to do something like that proxy.conf.json file


I'm starting to desperate :(


Think already solve it, in this part

# serve from the set folder
root * {$ANGULAR_OUTPUT_PATH}/browser

just have to remove /browser, that folder doesn't exist, and it is in the template, now, I'm fighting to make work the proxy just like proxy.conf.json file but in production


Cause when i'm calling /api/* routes, i'm getting 405 method not allowed error


In the network i'm getting this headers response

Access-Control-Allow-Methods: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE
Access-Control-Allow-Origin: *
Allow: GET, HEAD
Content-Length: 0
Date: Sun, 05 May 2024 04:00:11 GMT

Server: railway


:{$PORT} {
  @origin header Origin *
  header @origin Access-Control-Allow-Origin "*"
  header @origin Access-Control-Allow-Methods "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
  header @origin Allow "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"

    # access logs
    log {
        format json # set access log format to json mode
    }

  reverse_proxy /api/* wwt-auth-production.up.railway.app


    # health check for railway
    rewrite /health /*

    # serve from the set folder
    root * {$ANGULAR_OUTPUT_PATH}

    # enable gzipping responses
    encode gzip

    # serve files
    file_server

    # if path doesn't exist, redirect it to 'index.html' for client side routing
    try_files {path} /index.html
}

Keep having this problem, can't figure it out

Attachments


a year ago

You should be using the internal URL for the API proxy.

I'm starting to desperate

This is community support, please be patient.


Ok, used the internal url, but keep getting the same error

reverse_proxy /api/* wwt-auth.railway.internal

And the headers response in the browser

Access-Control-Allow-Methods: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE
Access-Control-Allow-Origin: *
Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE
Allow: GET, HEAD
Content-Length: 0
Date: Sun, 05 May 2024 18:35:43 GMT
Server: railway

I don't understand this second "Allow" header, I tried using this first URL in my local for the proxy file, and everything works fine


a year ago

You haven't specified a port in that URL.


Sorry, same error, I'm specifying port 8080 it is configurated in the railway environment variables


Don't know if you could be able to see my repo to see if I did anything wrong, please


a year ago

Yeah share it!



a year ago

Is your backend listening on IPv6?


No, my backend it is a NestJS server, don’t know anything about IPv6


###################
# BUILD FOR LOCAL DEVELOPMENT
###################

FROM node:18-alpine As development

# Create app directory
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
# Copying this first prevents re-running npm install on every code change.
COPY --chown=node:node package*.json ./

# Install app dependencies using the `npm ci` command instead of `npm install`
RUN npm ci

# Bundle app source
COPY --chown=node:node . .

# Use the node user from the image (instead of the root user)
USER node

###################
# BUILD FOR PRODUCTION
###################

FROM node:18-alpine As build

WORKDIR /usr/src/app

COPY --chown=node:node package*.json ./

# In order to run `npm run build` we need access to the Nest CLI which is a dev dependency. In the previous development stage we ran `npm ci` which installed all dependencies, so we can copy over the node_modules directory from the development image
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules

COPY --chown=node:node . .

# Run the build command which creates the production bundle
RUN npm run build

# Set NODE_ENV environment variable
ENV NODE_ENV production

# Running `npm ci` removes the existing node_modules directory and passing in --only=production ensures that only the production dependencies are installed. This ensures that the node_modules directory is as optimized as possible
RUN npm ci --only=production && npm cache clean --force

USER node

###################
# PRODUCTION
###################

FROM node:18-alpine As production

# Copy the bundled code from the build stage to the production image
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist
COPY --chown=node:node keys ./keys

# Start the server using the production build
CMD [ "node", "dist/main.js" ]

a year ago

It's need to be listening on IPv6, since Railways private network is IPv6 only.

And please only send code using code blocks.


That it is my dockerfile of backend


Sorry, my bad, I’m on my phone now… and about that internal communication, I really don’t know how to do that changes, do you know how can I search about it or any code template


Update my backend and set the listen method to hear on ‘::’ host, as said in NestJS documentation, but keep without working sadly



a year ago

How do you know your backend is listening on PORT 8080?


Bcs of environment variables

Attachments


Or I’m I wrong?


a year ago

That doesn't necessarily mean your app listens on the PORT environment variable.


And, how I would be able to understand the actual port that is listening? I’ll try a console log haha


Well, my console log shows me this

PORT: 8080

Just to be sure, Caddyfile have this config

:{$PORT} {
  @origin header Origin *
  header @origin Access-Control-Allow-Origin "*"
  header @origin Access-Control-Allow-Methods "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
  header @origin Allow "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"

    # access logs
    log {
        format json # set access log format to json mode
    }

  reverse_proxy /api/* wwt-auth.railway.internal:8080


    # health check for railway
    rewrite /health /*

    # serve from the set folder
    root * {$ANGULAR_OUTPUT_PATH}

    # enable gzipping responses
    encode gzip

    # serve files
    file_server

    # if path doesn't exist, redirect it to 'index.html' for client side routing
    try_files {path} /index.html

}

my backend have this config

await app.listen(
    configService.get('port'), // PORT: 8080
    '::'
  );

Do I have to change it through a call directly to the endpoint? :(


Has anyone been in this type of situation?


a year ago

Again, your backend needs to listen on IPv6.


Okay, which endpoint should i use, wwt-auth-production.up.railway.app, wwt-auth.railway.internal or viaduct.proxy.rlwy.net:11733?


And, this Caddy config it is fine?, please, just a confirmation

  @origin header Origin *
  header @origin Access-Control-Allow-Origin "*"
  header @origin Access-Control-Allow-Methods "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"
  header @origin Allow "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE"

    # access logs
    log {
        format json # set access log format to json mode
    }

  reverse_proxy /api/* wwt-auth.railway.internal:8080 ← The endpoint that i'm asking in the previous message


    # health check for railway
    rewrite /health /*

    # serve from the set folder
    root * {$ANGULAR_OUTPUT_PATH}

    # enable gzipping responses
    encode gzip

    # serve files
    file_server

    # if path doesn't exist, redirect it to 'index.html' for client side routing
    try_files {path} /index.html

a year ago

If wwt-auth.railway.internal is the service's internal domain, and 8080 is the port it listens on, then yes that is correct.


For those who don't find it working, after many iterations, and dozens of steps to production, this code has worked for me…

# global options
{
    admin off # no se necesita la API de administración en el entorno de Railway
    persist_config off # el almacenamiento no es persistente de todos modos
    auto_https off # Railway maneja https por nosotros, esto causaría problemas si se deja habilitado
    # runtime logs
    log {
        format json # establecer el formato de registro en modo json
    }
    # server options
    servers {
        trusted_proxies static private_ranges # confiar en el proxy de Railway
    }
}

# site block, escucha en la variable de entorno $PORT, asignada automáticamente por Railway
:{$PORT} {
    # access logs
    log {
        format json # establecer el formato de registro de acceso en modo json
        output stdout
    }

    # Manejar solicitudes de API
    handle /api/* {
        reverse_proxy wwt-auth:8080 {
            transport http {
                versions h1c
            }
        }
    }

    # Health check para Railway
    respond /health 200

    # Manejar solicitudes del frontend
    handle {
        root * /dist
        encode gzip
        file_server
        try_files {path} /index.html
    }
}

a year ago

This wouldn't work without the transport block?

That's odd, I've never had to do that myself.


Angular + Caddyfile + Api reverse proxy - Railway Help Station