A portfolio is the perfect first thing to ship: it's just HTML and CSS, there's no backend to break, and at the end you have a real link to put on your résumé or in your Discord bio. This build uses the static-site setup — a real nginx web server that serves your files fast — so there's nothing to run and nothing to keep online but the server itself.
| At a glance | |
|---|---|
| You're building | A one-page portfolio: about, projects, contact links |
| You need | A server running the PHP Web Server application (we use only its nginx part — no PHP) |
| Plan | Any plan |
| Time | About twenty minutes |
This guide builds on Host a static website, which sets up the nginx serving. Deploy that first, then bring your portfolio files here.
What you're building
| Piece | File |
|---|---|
| The page | public/index.html — one page, a few sections |
| The look | public/style.css — colors, spacing, layout |
| Served by | nginx from the static-site setup, on your SERVER_PORT |
No package.json, no index.js, no database. A static site is files on disk and a web server handing them out — that's the whole model, and it's why it's fast and cheap to run.
The files
Everything lives in the public/ folder (the static-site setup's web root).
public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Alex Rivera — Developer</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<header>
<h1>Alex Rivera</h1>
<p class="tagline">Backend developer & server tinkerer</p>
</header>
<main>
<section>
<h2>About</h2>
<p>I build small, reliable services and host them myself. I like databases,
clean APIs, and things that stay up.</p>
</section>
<section>
<h2>Projects</h2>
<ul class="projects">
<li><strong>URL Shortener</strong> — a tiny link service in Node and SQLite.</li>
<li><strong>Status Page</strong> — watches my other servers and shows if they're up.</li>
<li><strong>Chat Room</strong> — a real-time chat with Socket.io.</li>
</ul>
</section>
<section>
<h2>Contact</h2>
<ul class="links">
<li><a href="mailto:[email protected]">Email</a></li>
<li><a href="https://github.com/yourname">GitHub</a></li>
<li><a href="https://discord.gg/yourinvite">Discord</a></li>
</ul>
</section>
</main>
<footer><p>Hosted on Falix.</p></footer>
</body>
</html>
public/style.css:
:root { --accent: #4f46e5; --ink: #1f2937; --muted: #6b7280; }
* { box-sizing: border-box; }
body {
font-family: system-ui, -apple-system, sans-serif;
color: var(--ink);
max-width: 44rem;
margin: 0 auto;
padding: 3rem 1.25rem;
line-height: 1.6;
}
header { border-bottom: 2px solid var(--accent); padding-bottom: 1rem; margin-bottom: 2rem; }
h1 { margin: 0; font-size: 2.2rem; }
.tagline { color: var(--muted); margin: 0.3rem 0 0; }
section { margin-bottom: 2rem; }
h2 { font-size: 1.2rem; }
.projects, .links { list-style: none; padding: 0; }
.projects li { padding: 0.5rem 0; border-bottom: 1px solid #eee; }
.links { display: flex; gap: 1rem; }
.links a { color: var(--accent); text-decoration: none; font-weight: 600; }
.links a:hover { text-decoration: underline; }
footer { color: var(--muted); font-size: 0.85rem; border-top: 1px solid #eee; padding-top: 1rem; }
How it works
- The file layout is the URL layout.
public/index.htmlis your home page at/. Addpublic/projects/index.htmland it's at/projects/. nginx serves whatever matches the path. <link rel="stylesheet" href="/style.css">loads the CSS. nginx sends it with the correcttext/csscontent type automatically — you never configure MIME types.- CSS variables keep it tidy. The
:root { --accent: … }block sets your theme in one place; change--accentand every link and border follows. - Nothing runs. There's no process of yours to crash. nginx reads the files off disk and returns them — which is why static sites are the cheapest, most reliable thing you can host.
💡 Tip: Edits to files in
public/are served live — save the file, then hard-refresh the browser (Ctrl/Cmd+Shift+R) to bypass the cache. You do not restart the server for content changes; that's only for the nginx config itself.
Ship it on Falix
- Deploy the Static Website setup from Host a static website — it wires your
SERVER_PORTinto nginx for you. - Open the File Manager, go into
public/, and replace the sampleindex.html(and addstyle.css) with the files above. Or drag your whole folder across over SFTP. - Open your server's address from the Network page. Your portfolio loads.
That's it — a static site needs no SERVER_PORT code from you, because nginx (set up by the static template) already binds it.
🎯 Good to know: Your files survive restarts. A reinstall or switching the application wipes them like any server files, so keep the source in a Git repo — then a redeploy puts it right back, and you get version history for free. See Deploy your code with Git.
Make it yours
- A custom 404. Add
public/404.htmland one line to the nginx config — the static site guide shows exactly where. - More pages.
public/blog/index.html,public/projects/index.html— folders become clean URLs. - A photo or favicon. Drop images in
public/and reference them; nginx serves them with the right type. - Outgrow hand-written HTML? A static-site generator turns Markdown into pages — see Build a blog with Eleventy.
HTML and CSS themselves are vast; MDN Web Docs is the reference the whole web uses.
Give it a real address
address:port is fine for testing but not for sharing. The Network page's Reverse Proxy puts a real domain in front with automatic HTTPS on any plan — follow Domains and HTTPS. A free yourname.falix.org works, or bring your own domain.
Troubleshooting
- 404 on the home page — it must be named exactly
public/index.html, lowercase. Check spelling and that it's insidepublic/. - CSS doesn't apply — the
hrefpath is wrong. With the file atpublic/style.css, the link is/style.css(leading slash). Hard-refresh to clear the cache. - Changed a file but see the old version — browser cache, not the server. Static files are served live; hard-refresh (Ctrl/Cmd+Shift+R).
- Whole site won't load — a reachability problem, not a file one: I can't reach my app.