Today We will Develop, Build and Publish a File Sharing Server on the Web anyone can join from Anywhere for Free. We will be using Nodejs and Reactjs for the development and Port Forwarding for Publishing our Site Internationally. If you don’t use this stack but find the project worthwhile doing then I you might want to check this out.
We will start with the server first. Firstly create a folder for the server and go in to it, after that initialize a node project. Use the y option to skip the interrogation. If you are unsure you have Nodejs on your system, check the version of node and if Nodejs is not installed go to https://nodejs.org/en and download the LTS version.
mkdir server
cd server
# Check for node version
node -v
# Initialize project
npm init -y
Install the project dependencies: express, express-fileupload, nodemon. Express will be used to create the web server and express-fileupload will be used for accessing the uploaded files.
npm i express express-fileupload
Add the main javascript file. For this example I will be naming it main.js
Add a script to start the server under the package.json file. You can also delete the test script. At the end this must be your package.json.
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node main.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Now we must write the script. I won’t go to the details but the script can be roughly separated in 3 parts: The Imports, the Boilerplate app statements and the routes. The fs.append code blocks are trackers for our website, they track the browser’s IP and route they are on
// Imports
const fs = require('fs')
const path = require('path')
const express = require('express')
const fileupload = require('express-fileupload')
const cors = require('cors')
// Boilerplate app statements
const app = express()
app.use(fileupload({
useTempFiles: true,
tempFileDir: "/tmp/"
}))
app.use(express.json())
app.use(cors({ origin: "*", }))
// helper functions
function padTo2Digits(num) {
return num.toString().padStart(2, '0');
}
function formatDate(date) {
return (
[
date.getFullYear(),
padTo2Digits(date.getMonth() + 1),
padTo2Digits(date.getDate()),
].join('-') +
' ' +
[
padTo2Digits(date.getHours()),
padTo2Digits(date.getMinutes()),
padTo2Digits(date.getSeconds()),
].join(':')
);
}
// Routes
// Sends the filenames under the uploads sibling directory
app.get('/sync', (req, res) => {
try {
fs.appendFile('connections.txt', `${formatDate(new Date())} ${req.ip} / \n`, function (err) {
if (err) return res.sendStatus(500)
});
res.json({ files: fs.readdirSync('./uploads') })
} catch (error) {
console.error(error);
res.sendStatus(500)
}
})
app.post('/upload-file', async (req, res) => {
try {
const files = req.files.upload
fs.appendFile('connections.txt', `${formatDate(new Date())} ${req.ip} /upload \n`, function (err) {
if (err) return res.sendStatus(500)
});
if(typeof files[Symbol.iterator] === 'function'){
for(const file of files){
console.log('saving: '+file.name)
await file.mv(`./uploads/${file.name}`)
}
}else{
console.log('saving: '+files.name)
await files.mv(`./uploads/${files.name}`)
}
res.status(200).json({ files: fs.readdirSync('./uploads') })
} catch (error) {
console.error(error);
res.sendStatus(500)
}
})
app.delete('/delete', async (req, res) => {
try {
const filename = req.query.filename
fs.appendFile('connections.txt', `${formatDate(new Date())} ${req.ip} /delete?filename=${filename} \n`, function (err) {
if (err) return res.sendStatus(500)
});
await fs.promises.rm(`./uploads/${filename}`)
res.status(200).json({ files: fs.readdirSync('./uploads') })
} catch (error) {
console.error(error);
res.sendStatus(500)
}
})
// Sends a file contents to Browser
app.get('/retrieve', (req, res) => {
try {
const filename = req.query.filename
fs.appendFile('connections.txt', `${formatDate(new Date())} ${req.ip} /retrieve?filename=${filename} \n`, function (err) {
if (err) return res.sendStatus(500)
});
console.log(filename)
res.sendFile(path.join(__dirname, 'uploads', filename))
} catch (error) {
console.error(error);
res.sendStatus(404)
}
})
app.listen(9001)
Add the Frontend
For the Front-end, I have created a repo. I have added the steps in the repo but I will write them again. If you are struggling with these steps the steps in the repo are more detailed
Numero uno thing you want to do is replace every instance with your public ip ( (You can find your public ip here)[https://ifconfig.me/] )
A notable thing that I did was that in vite.config.js I added
server: {
host: true
}
This allows the router ( and therefore any other device in LAN ) to enter the app.
Then you want to build the app for production:
npm run build
This will generate the dist which you want to put in the server directory and add the following code to the index js file.
app.use(‘/’, express.static(‘dist’)).
Here is how it looks:
// ...
app.use(fileupload({
useTempFiles: true,
tempFileDir: "/tmp/"
}))
app.use(express.json())
app.use(cors({ origin: "*", }))
// The line below serves the dist folder ( app ) when users make a request to /
app.use('/', express.static('dist'))
// ...
Hosting your Server with port Forwarding.
These steps will differ from person to person because each of us has a different Internet Service Provider (ISP). Meaning the gateway website layout is different, I will give you the objectives and you will try to accomplish them.
1. Find your Default Gateway. On windows type ipconfig and search for Default Gateway. On UNIX systems type ip route show and you will see default via … .
2. Paste the number on the URL search bar.
3. Log in with your credentials. You will find the credentials on your router and typically the User Name is admin
4. Search for either Port Forwarding. In my case it was under NAT.
5. Add a rule, the layout will probably differ.
You are ready to fire up the server
With that, fire up the server and if you have any problems you can’t fix please contact me. Thank you very much for following along with this tutorial, now you have a file Sharing App on the web everyone you want can join, moreover you have installed trackers so if there are any uninvited people you can see them and if you want you can add an if statement checking for blacklisted people.
Top comments (0)