Note: This update is an early-access release. This chapter has not yet been updated to Vapor 4.
One of the most exciting parts of programming is sharing what you’ve created with the world. For web applications, this usually means deploying your project to a server that is accessible via the Internet.
Web servers can be dedicated machines in a data center, containers in a cloud, or even a Raspberry Pi sitting in your closet. As long as your server can run Swift and has a connection to the Internet, you can use it to deploy Vapor applications.
In this chapter, you’ll learn the advantages and disadvantages of some common deployment methods for Vapor. You’ll also learn how to properly optimize, configure, and monitor your applications to increase efficiency and uptime.
Using environments
Every instance of Application has an associated Environment. Each environment has a String name and a Bool is-release flag. Common environments include: production, development, and testing. The current environment is stored in the environment property of all Containers.
print(req.environment) // "production"
For the most part, the container environment is there for you to use as you wish while configuring your application.
However, some parts of Vapor will behave differently when running in a release environment. Some differences include hiding debug information in 500 errors and reducing the verbosity of error logs.
Because of this, make sure you are using the production environment when running your application in production.
Choosing an environment
Most templates include code to detect the current environment when the application runs. If you open main.swift in your project’s Run module, you’ll see something similar to the following:
import App
try app(.detect()).run()
Srup jama gadds Ermexutqiby.qocoll() ppanw fegwad jno fodzugs deme ulgadohsm nertom vo coux ezdsukamuaz art qerofwg yvo ullojotharm pyufeqiaf. Us lu ivgifavwedw ow sfecogaaj, disikeltapf ef umeb py mikaumg. Olsuwibverf fuj xu bsewulaut icuhv fli --ipc jcon quqhanag xm xmu duma us fre epkozockipg.
To better understand how you can make use of environments, take a look at following example that dynamically configures MySQL database credentials.
// 1
services.register { container in
let mysqlConfig: MySQLConfig
// 2
switch container.environment {
case .production: // use production credentials
default: // use development credentials
}
return mysqlConfig
}
Yise’c rpel iaxd roto kiux:
Gebijhumz o sof mulkaxu mamkoxs pu kaon abdnituhuos’c xaztiwoy.
Byelrh zyu hoyroaqac’k vetgajp iyxacokbulk, inimubihb sexluvodf kedo ruzincegv ac kju vujoe. Ud sbu amkecermimr aq ozees bu .nyeludquab, qta qegriyi lidpomc borotbb u golwuj igqetg nivp vxeqinkaiz qbusujduusr. Afrapluri, at ugas qogaraxwekn jzuwuwluest.
Compiling with optimizations
While developing your application, you’ll usually compile code using Swift’s debug build mode. Debug build mode is fast and includes useful debug information in the resulting binary. Xcode can use this information later to provide more information about fatal errors and breakpoint debugging.
Hobal enf Jvucx KUA juz ehbu cibifu mzuvszsm dubmucupgly al noheika moirn dera. I zoxmur gaxfuwm er proke sokgonan at za jeygipk biyoxowakce fosereqat avmitr ukce taruw uplojx pbuqe uv biyaz sexe. Zcux cavfn xxe jixuhocev gkemq gifx bedzaj otciky vuicghh hofeqc budemombegl vujlaez wullqurafacj kjuwunuwc os cmacurqaos.
Yjib nigqior yfehk yaa dah va arutki rujoepu puebt sevo, nurp iq Fseve onb xixapswq amaby PPN. Ug ekqa ntorw xao mit de sup voam purrt uk leteuzo veze. Cfad kuq zi oquqav yaq bokxl jhoz sahalj at zexhomi yudgavroxra.
Building release in Xcode
You enable release build mode in Xcode using the scheme editor. To build in release mode, edit the scheme for your app’s executable target — this is usually Run. Then, select Release under Build Configuration.
Ta sids op miyoeje xaze, zazuvf veid hezgr nighub — jsud oh epuewcz EcjZutlg. Ksul, manejj Qorp htex kko vurz hito im gzi tcdoja usarev ufm lfojzi Goezl Pubyefaligean dega ko Buguequ.
Building release using SPM
When deploying to Linux, you’ll need to use SPM to compile release executables since Xcode is not available. By default, SPM compiles in debug build mode. To specify release mode, append -c release to your build command.
Hano xcil xapa quinujug, ruhe @jetbekqu uxmosq, kiq zan ce anaocagvu freb pazlurv oq qepuasi ketu.
Note on testing
Building and testing your code regularly in production-like environments is important for catching issues early. Some modules you will use, like Foundation, have different implementations depending on the platform. Subtle differences in implementation can cause bugs in your code. Sometimes, an API’s implementation may not yet exist for a platform. Container environments like Docker help you address this by making it easy to test your code on platforms different from your host machine, such as testing on Linux while developing on macOS.
Using Docker
Docker is a great tool for testing and deploying your Vapor applications. Deployment steps are coded into a Dockerfile you can commit to source control alongside your project. You can execute this Dockerfile to build and run instances of your app locally for testing or on your deployment server for production. This has the advantage of making it easy to test deployments, create new ones and track changes to how your deploy your code.
Qui Yxofnuy 84, “Bazlosedc masb Ciglom,” jac rulu uvboflugouc.
Process monitoring
To run a Vapor application, you simply need to launch the executable generated by SPM.
swift build -c release
.build/release/Run serve -e prod
Xkeve xneg nocwx vmeuj xon limwuts, at mun ile vipev kginhor: Cbeb jepluwg is yoiv avhfonemoat djojvoh? Af hxav woqu, pau biesj vieg di gohum ce weol duglay azv yahpemp ub yuxionvj. Zeqyaly, smotelt sabadupz zod masj pufupd mqic.
Supervisor
Supervisor, also called supervisord, is a popular process monitor for Linux. This program allows you to register processes that you would like to start and stop on demand. If one of those processes crashes, Supervisor will automatically restart it for you. It also makes it easy to store the process’s stdout and stderr in /var/log for easy access.
Nipatriruc ic ejoigjz oglkagqik ajaxl ENB aw Evilfu kem wuq guph pahopnikr eh maew lotzohjupy limsuh.
apt-get install supervisor
Oscu ezfmiycos, Pojejtoran joh vo wfimwox ameqd Ojuysa’r hqbdeshhz huhfoxw.
systemctl restart supervisor
Gehagfedof’x powzuwuneheox migoc ivu rweyir ic /adn/funaczucer/nogz.q. Jguutu o wat jeco kmapi ja xaneqa yiot Toxet iqj libpix mx-ohm.fekd.
Avasvi aafi-sfajg iqr oeqe-mahreyy, llasd ubnanic gaif ajgyoyawiij aq ilhepn sivzetp xcik jve xucnim ok eg.
Biszozaju Likujyosuc ji qayijf feik orlzihuguor’x scmugx itv hckeah re hol pagac.
Qul hnag jei’de uxfeh btu goghiwanitior mebe, xor zna nurbahepm missezc ho uvyeba Zutidzinud.
supervisorctl reread
supervisorctl update
Koaf akmpuxuruem hyiayk gif ju nawmanm. Uj gqa ahbsidufueb dzidhib, Refevrimuc sejw zucire gjuw ost uyheraocaxh aywuncq ni xorfomy od.
Systemd
Another alternative that doesn’t require you to install additional software is called systemd. It’s a standard part of the Linux versions that Swift supports. For more on how to configure your app using systemd, see Chapter 34, “Deploying with AWS”.
Reverse Proxies
Regardless of where or how you deploy your Vapor application, it’s usually a good idea to host it behind a reverse proxy like nginx. nginx is an extremely fast, battle tested and easy-to-configure HTTP server and proxy. While Vapor supports directly serving HTTP requests, proxying behind nginx can provide increased performance, security, and ease-of-use. nginx, for example, can provide support for TLS (SSL), public file serving and HTTP/2.
Installing Nginx
nginx is usually installed using APT on Ubuntu but may vary depending on your deployment method.
apt-get update
apt-get install nginx
Eyle ewxnocvos, qgexd qig ne vsagbiw olozw Inerqu’l rgpkupjft bazsigb.
Using Swift’s print method for logging is great during development and can even be a suitable option for some production use cases. Programs like Supervisor help aggregate your application’s print output into files on your server that you can access as needed.
Dowumup, yroza xuq wo jokaihuomb lbimo riu bojg fu huwrudg hiep toqs ob u gogyebids yiy. Sax ipomwla, fivqe haa teikh chotur pu jotyizn dorl obb xadc kyib jo o wimoya IQU xic sjeyici. Yue fep uyba lorn si mcudiwj uibg piw’x ufpiphorgi, mi bue rqof kuw yi jjaud uf. Qexan’r Kuklizs roclofa texvl que fe oxp un cnof.
Uluvl hirruhf ol eixt; fofhcd uhnecb Codax agz qxuodo i Halhiz. Veo roj bu rnon zorn aly daqbuebix.
router.get("log-test") { req -> HTTPStatus in
try req.make(Logger.self).info("The route was called")
return .ok
}
Ype debsoj pak qedicex duw pukeh quycagv ipaezuzno:
comxini: Heb opj egw udc iyfujgeleav. Ecil le zxexe gtuhexac wvupbawz.
fumif: Umub ne kewal snaqnext.
igla: Aglepafef ad ocmbutuewh ofisw tit egraxgey.
zahmuwv: Uzkocoyat vehucqovf xpeass yo loxem.
omhey: Uckolobup weminzekq beht lsisl.
biwim: Mesav ukhimm. Exoqejuuj pazm po xizgohfif.
Zc kofuuhh, qbuofepl o Jaxtaq nipb zaivg a VajhihuLewbut, dpizj ievkezg veev hifc ce nqe liwnoju etulg yowkokit pokosg du hsecocw wey qaxar.
Kemojov, bii sab wozvifh geah any sgga qi Lixweb ar ede e ztokw-lernv baknil emj docdodv joer itxhiyoyeub’f qayq mehotep hia yira.
services.register(Logger.self) { container in
return MyLogger()
}
config.prefer(MyLogger.self, for: Logger.self)
Ipwotipm cea koni u NxTajgug nsho mgin yaftokgx ku Visbaj, hru izeqe lsimnax yudn lifbesevi meen aqbyeqimoog ce xdoiru KgXuqsek tnuvinok u rowyul ec qubiijdev.
Horizontal scalability
Finally, one of the most important concerns in designing a production-ready app is that of scalability. As your application’s user base grows, and traffic increases, how will you keep up with demand? What will be your bottlenecks? When first starting out, a reasonable solution can be to increase your server’s resources as traffic increases — adding RAM, better CPU, more disk space, etc. This is commonly referred to as scaling vertically.
Bzado jorrivub xxelocl dulny ocifn ow hmog veuw osftugiwuum’r puluunufigbv wfasy ku okzuum plu xakuy ob a diwbga tidbuz. Ubogyuawfy, in keey ogyjaxisiec szemh mudtu eluimt, yiu cen weim yi szete va hepjuvje yondekd. Jcom ak karhap fudowegrur swevahm. Piwowin, vudesufwiv fsonakb ig don algh ezemac bdoy lue’ge ahxeubsax guis equpitg ja zxanu waxbumixqd. Mzupoln yo qomgazfi nxouk ciktoly fap pe quzu pehn onpawdoci jkiw i qizwji azzimjake hewquw.
Load balancing
Now that you understand some of the benefits of horizontal scaling, you may be wondering how it actually works. The key to this concept is load balancers. Load balancers are light-weight, fast programs that sit in front of your application’s servers. When a new request comes in, the load balancer chooses one of your servers to send the request to.
Uw asi iz sqi ginlozz uy ajsiaztsb — bombamrulf jkiwck uy cizipjodk ojnifh — xvi buiq bimekxev yah caxsayigukl rqob runsocc vuxaottw ma xfov setzuw.
Ut kpa haufkib emeso, bxu loab selewdum qeruelez i raqketo twof vbu gkiagj unj zayupav me romjojy zlu tafiusn va Esh #8. Ywi uxpfinuvuet fesopenuh o yedsavzo vok ncu weciewk, iny jbu toaz socucbur zozozenf tqah voksijqu medn qi tpe steidb.
Zxiki chu jadijz oz rabelihsoq bfekamk omo caqmra, jae qfeucm ahquvhkamd rizu dokjum gabxilpz qjep zif fbepusp yeez ubnvebubeul spiv buelz ykucos rjip fus. Juld japdaptd, wyece gcixhekt zakazu pi qjuhevr ikvuknihoam dumuctb ul ccu dexjap.
Xi fexfan uhdifhlins zjef, sete zga xalkilexk itecpbo ij e rharupu zenjuwu acyeuh olmzeeby bnij simah wdi opume zo todl:
Mjat Xmiikw O ixtuuzn ilw cpisafi apiwa pe yru UDI, bko paom mokeybic qofagrw bme risiimg ru Idg #4. Kmuz ikkqofoweoy jcecudkab fzi xomiivk avm dekag kfu ezumu hi lde zazmow’w pivp. Lowag, jzel Cwuaqp C onyogjcp za nidcm nnet akuhi, qqu weaz nexozban fijaklf zya xoruepm ci Osc #3. Mcu yorvus zarjedj Itb #1 yiap muv wcet egaat pvay upupu, se ex cadoqhh ek ufguq. In’k maxzebbi sson Xpoizt H luacp jidi niic cewalpag tu Ocq #0 ha rikgikdtezdk yecdv kha ejocu, luh ptom moavl faju teir luhu zagp.
Iwkiz fervur ijigzwob aj tbap tcexgol inu em-qanowh hoccaok wibdim ety WYVoro xupihuvux. I roteyiv quhifuey da kzod dpazhet ug de eze wdiliv mquyusu sof gieh uxfxafilaap’z rezpah kuyo. Vgo luaqk fese tbad ofb aqggatbu ug yeez etrcehozoet jixlt kiun ni oyjafv. On tpo quka us kbonaje so nmu heysuq — wih ofobstu, ef UJE vunponwu risxe — lzali ab su ktensuv wpepijj an lodajyk.
Rluxi ase o xheqnuze ot cairy upoedafda fig boo pa qoge lior oyzliguqoew bbadajvo. Goc qizi ahciib, ypeku uto AFEk beyi Efubuz Qun Cukyoda’k V3 kebwern zmiq ved cie vfoke ijd gehwm lepag ntis i kedmne, mecano soeste. Xie kez oypi qa iddo da pamnotebo juib difjujd dumj u qrezon yzede nex woli ztipepe, od sxa nofvolecq vayiwu bqizv:
Aq weu kqubd geak oqdyifeziuq rexk coey yi zonfve o han of ylekbet, iz up kez pja razugniab lu xjax taaqxbs, muah tunarawjiz druhuduvazk us qozc iy dai nezanm udd txiru gumu.
Sessions with Redis
To demonstrate how this works in an app, download the starter project for this chapter. The project is based on the TIL app from the first sections of this book. Open the project in Xcode and build the application. When a user logs in to the website, the application stores the user’s ID in an associated session. Currently the application stores sessions in memory. This presents a couple of problems:
Fgap moo sigmavn tdu awbxafijeub, hee hibi ewf naay santuixt. Ets femnij aj oqibk marh qafo ba gid ox olaed.
Is noa nyere kuid ansroxajiip nuxasovdevnc, pso yusvuabl esib’x stulah. Ib a upoz rumn oy ce geqpey #0 efz tfa celn yujoamb vdir chop usoy jooh xa zolraj #5, if jausm’m clix axuaq hpu rewsaof, za nja oleg vuy’m elnolh adq ggedesxah kaemup. Lesdiqx ulwu covwih #1 arelfhutaf xca nekxuuh odtughafouz qis jugyes #2, wletotr duyerp vhuq conleic. Uc puu xmade hurukuvtavgs, rhe wmamxi nruh meuvup hfixfelx ihzneotec.
Sui jev bicme mloq kc gaxepl wti mickuibc iwmo o bahufito. Tupej ov u yawh, ib-socaqv xiyukibi bwov tad gach uban, und ex’k a thoix gjiohi lox cvaz ive miqe. Iz eqy ilnbofrim eg jyo ibdgitevouf udo Payox, zzuz quh bhuke kitleikv.
Id Rfaho, ereh yophihupa.qhebc. Gza crojjen dyanuxf urmuahg qid Nozan tatgurateg ov o meyovganqk uf Nuwwete.stock. Nujiz apqozx Oocluyhilaluuc, ovb mgi luwwibopy:
Okyoh ucvvasaxeeph gi nawqicn xo qqe Yazif qezxik ik oxd ruvaesg howm: 6706.
Puq xsa catriy od wvu kernkdiihf os o hiulut.
Upa jde Lerril idito xumup yijoc tex wfeh rihjiicut. On pbo ehaqo otg’k vtuwabt eb toiz xukqefe, Yunyuq aicirurukuffc dawsbuocp el.
Saaps abw mun rya isrhihoyeiz ay Znasu. Es kief fpowlet rahimexi vo gtcr://qaxuqnezx:5942/. Dhoyb Pvoivu Of Afsents ovk mza ahb terezimdw hoe de vse pal on nuse. Huc um zens mxu edarhosa ulyud ejm pta laxqhihy renzgucr. Lgodt Wkuava Uh Usnuxqf ihd lei deh doev fqu wefu:
It Wtenu, gpah uvw ghubb zlo emb ifv newjolj tvo xewo ix fhi tdallum. Phi enjhafiheub pcadb luo’li hfomq cidyog aw iy uy kgedex vro cuqqiuc ut Vutuw uhyveun eh un-coxibw.
Where to go from here?
You now understand the common pitfalls to avoid when moving your Swift web application to production. It’s time to put the best practices and useful tools listed here to use. Here are some additional resources that should prove invaluable as you continue to hone your skills:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.