3 months ago
Hi!
I'm deploying a Vite SPA to Railway and need to serve the Apple App Site Association file at /.well-known/apple-app-site-association. This file:
- Has no file extension (Apple's requirement)
- Must be served with Content-Type: application/json
Using npx serve with the -s flag for SPA routing, the file returns index.html instead of the actual file contents. This is a https://github.com/vercel/serve-handler/issues/142 - it doesn't properly handle extensionless files in .well-known.
What I've tried:
1. serve.json with rewrites (renaming to .json and rewriting) - rewrites don't seem to apply
2. serve.json with cleanUrls: false - no effect
3. Running serve from inside the dist directory with -c flag - .well-known returns 404
Is there a recommended way to serve extensionless files with custom headers on Railway without a custom server? Perhaps a built-in nginx config option or another static file server that handles this well?
Pinned Solution
3 months ago
okay , you can create a lightweight Express server that properly handles the file
server.js :
import express from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
const __filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
const app = express();
const PORT = process.env.PORT || 3000;
const distPath = path.join(__dirname, 'dist');
app.get('/.well-known/apple-app-site-association', (req, res) => {
const filePath = path.join(distPath, '.well-known', 'apple-app-site-association');
if (fs.existsSync(filePath)) {
res.setHeader('Content-Type', 'application/json');
res.sendFile(filePath);
} else {
res.status(404).send('Not found');
}
});
app.use(express.static(distPath));
app.get('*', (req, res) => {
res.sendFile(path.join(distPath, 'index.html'));
});
app.listen(PORT, () => {
console.logServer running on port ${PORT});
});
and package.json for Express setup :
{
"name": "your-vite-app",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"vite": "^5.0.0"
}
}
the railway setup for Express is a build command: npm install && npm run build and a Start Command: npm start no nixpacks.toml needed
5 Replies
3 months ago
Hey there! We've found the following might help you get unblocked faster:
If you find the answer from one of these, please let us know by solving the thread!
3 months ago
add this Dockerfile at the root of your project :
# Multi-stage build
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy source files
COPY . .
# Build the app
RUN npm run build
# Production stage
FROM nginx:alpine
# Copy built app from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy custom nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port 80
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
3 months ago
Hi! Thanks, @domehane.
Is there a solution no involving setting up a Dockerfile? This app is inside a monorepo, and I'd rather avoid the additional complexity of directly maintaining a Dockerfile.
3 months ago
okay , you can create a lightweight Express server that properly handles the file
server.js :
import express from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
const __filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
const app = express();
const PORT = process.env.PORT || 3000;
const distPath = path.join(__dirname, 'dist');
app.get('/.well-known/apple-app-site-association', (req, res) => {
const filePath = path.join(distPath, '.well-known', 'apple-app-site-association');
if (fs.existsSync(filePath)) {
res.setHeader('Content-Type', 'application/json');
res.sendFile(filePath);
} else {
res.status(404).send('Not found');
}
});
app.use(express.static(distPath));
app.get('*', (req, res) => {
res.sendFile(path.join(distPath, 'index.html'));
});
app.listen(PORT, () => {
console.logServer running on port ${PORT});
});
and package.json for Express setup :
{
"name": "your-vite-app",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"vite": "^5.0.0"
}
}
the railway setup for Express is a build command: npm install && npm run build and a Start Command: npm start no nixpacks.toml needed
3 months ago
Okay great, I ended up doing that! Thanks!
Status changed to Solved ray-chen • 3 months ago
